1: /*
   2:  * Copyright (c) 1982, 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)in_pcb.c	7.1 (Berkeley) 6/5/86
   7:  */
   8: 
   9: #include "param.h"
  10: #include "systm.h"
  11: #include "dir.h"
  12: #include "user.h"
  13: #include "mbuf.h"
  14: #include "socket.h"
  15: #include "socketvar.h"
  16: #include "ioctl.h"
  17: #include "in.h"
  18: #include "in_systm.h"
  19: #include "../net/if.h"
  20: #include "../net/route.h"
  21: #include "in_pcb.h"
  22: #include "in_var.h"
  23: #include "protosw.h"
  24: 
  25: struct  in_addr zeroin_addr;
  26: 
  27: in_pcballoc(so, head)
  28:     struct socket *so;
  29:     struct inpcb *head;
  30: {
  31:     struct mbuf *m;
  32:     register struct inpcb *inp;
  33: 
  34:     m = m_getclr(M_DONTWAIT, MT_PCB);
  35:     if (m == NULL)
  36:         return (ENOBUFS);
  37:     inp = mtod(m, struct inpcb *);
  38:     inp->inp_head = head;
  39:     inp->inp_socket = so;
  40:     insque(inp, head);
  41:     so->so_pcb = (caddr_t)inp;
  42:     return (0);
  43: }
  44: 
  45: in_pcbbind(inp, nam)
  46:     register struct inpcb *inp;
  47:     struct mbuf *nam;
  48: {
  49:     register struct socket *so = inp->inp_socket;
  50:     register struct inpcb *head = inp->inp_head;
  51:     register struct sockaddr_in *sin;
  52:     u_short lport = 0;
  53: 
  54:     if (in_ifaddr == 0)
  55:         return (EADDRNOTAVAIL);
  56:     if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
  57:         return (EINVAL);
  58:     if (nam == 0)
  59:         goto noname;
  60:     sin = mtod(nam, struct sockaddr_in *);
  61:     if (nam->m_len != sizeof (*sin))
  62:         return (EINVAL);
  63:     if (sin->sin_addr.s_addr != INADDR_ANY) {
  64:         int tport = sin->sin_port;
  65: 
  66:         sin->sin_port = 0;      /* yech... */
  67:         if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
  68:             return (EADDRNOTAVAIL);
  69:         sin->sin_port = tport;
  70:     }
  71:     lport = sin->sin_port;
  72:     if (lport) {
  73:         u_short aport = ntohs(lport);
  74:         int wild = 0;
  75: 
  76:         /* GROSS */
  77:         if (aport < IPPORT_RESERVED && u.u_uid != 0)
  78:             return (EACCES);
  79:         /* even GROSSER, but this is the Internet */
  80:         if ((so->so_options & SO_REUSEADDR) == 0 &&
  81:             ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
  82:              (so->so_options & SO_ACCEPTCONN) == 0))
  83:             wild = INPLOOKUP_WILDCARD;
  84:         if (in_pcblookup(head,
  85:             zeroin_addr, 0, sin->sin_addr, lport, wild))
  86:             return (EADDRINUSE);
  87:     }
  88:     inp->inp_laddr = sin->sin_addr;
  89: noname:
  90:     if (lport == 0)
  91:         do {
  92:             if (head->inp_lport++ < IPPORT_RESERVED ||
  93:                 head->inp_lport > IPPORT_USERRESERVED)
  94:                 head->inp_lport = IPPORT_RESERVED;
  95:             lport = htons(head->inp_lport);
  96:         } while (in_pcblookup(head,
  97:                 zeroin_addr, 0, inp->inp_laddr, lport, 0));
  98:     inp->inp_lport = lport;
  99:     return (0);
 100: }
 101: 
 102: /*
 103:  * Connect from a socket to a specified address.
 104:  * Both address and port must be specified in argument sin.
 105:  * If don't have a local address for this socket yet,
 106:  * then pick one.
 107:  */
 108: in_pcbconnect(inp, nam)
 109:     struct inpcb *inp;
 110:     struct mbuf *nam;
 111: {
 112:     struct in_ifaddr *ia;
 113:     struct sockaddr_in *ifaddr;
 114:     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
 115: 
 116:     if (nam->m_len != sizeof (*sin))
 117:         return (EINVAL);
 118:     if (sin->sin_family != AF_INET)
 119:         return (EAFNOSUPPORT);
 120:     if (sin->sin_port == 0)
 121:         return (EADDRNOTAVAIL);
 122:     if (in_ifaddr) {
 123:         /*
 124: 		 * If the destination address is INADDR_ANY,
 125: 		 * use the primary local address.
 126: 		 * If the supplied address is INADDR_BROADCAST,
 127: 		 * and the primary interface supports broadcast,
 128: 		 * choose the broadcast address for that interface.
 129: 		 */
 130: #define satosin(sa) ((struct sockaddr_in *)(sa))
 131:         if (sin->sin_addr.s_addr == INADDR_ANY)
 132:             sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
 133:         else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
 134:           (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
 135:             sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
 136:     }
 137:     if (inp->inp_laddr.s_addr == INADDR_ANY) {
 138:         register struct route *ro;
 139:         struct ifnet *ifp;
 140: 
 141:         ia = (struct in_ifaddr *)0;
 142:         /*
 143: 		 * If route is known or can be allocated now,
 144: 		 * our src addr is taken from the i/f, else punt.
 145: 		 */
 146:         ro = &inp->inp_route;
 147:         if (ro->ro_rt &&
 148:             satosin(&ro->ro_dst)->sin_addr.s_addr !=
 149:             sin->sin_addr.s_addr) {
 150:             RTFREE(ro->ro_rt);
 151:             ro->ro_rt = (struct rtentry *)0;
 152:         }
 153:         if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
 154:             (ro->ro_rt == (struct rtentry *)0 ||
 155:             (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0)) {
 156:             /* No route yet, so try to acquire one */
 157:             ro->ro_dst.sa_family = AF_INET;
 158:             ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
 159:                 sin->sin_addr;
 160:             rtalloc(ro);
 161:             /*
 162: 			 * If we found a route, use the address
 163: 			 * corresponding to the outgoing interface
 164: 			 * unless it is the loopback (in case a route
 165: 			 * to our address on another net goes to loopback).
 166: 			 */
 167:             if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
 168:                 (ifp->if_flags & IFF_LOOPBACK) == 0)
 169:                 for (ia = in_ifaddr; ia; ia = ia->ia_next)
 170:                     if (ia->ia_ifp == ifp)
 171:                         break;
 172:         }
 173:         if (ia == 0) {
 174:             ia = (struct in_ifaddr *)
 175:                 ifa_ifwithdstaddr((struct sockaddr *)sin);
 176:             if (ia == 0)
 177:                 ia = in_iaonnetof(in_netof(sin->sin_addr));
 178:             if (ia == 0)
 179:                 ia = in_ifaddr;
 180:             if (ia == 0)
 181:                 return (EADDRNOTAVAIL);
 182:         }
 183:         ifaddr = (struct sockaddr_in *)&ia->ia_addr;
 184:     }
 185:     if (in_pcblookup(inp->inp_head,
 186:         sin->sin_addr,
 187:         sin->sin_port,
 188:         inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
 189:         inp->inp_lport,
 190:         0))
 191:         return (EADDRINUSE);
 192:     if (inp->inp_laddr.s_addr == INADDR_ANY) {
 193:         if (inp->inp_lport == 0)
 194:             (void)in_pcbbind(inp, (struct mbuf *)0);
 195:         inp->inp_laddr = ifaddr->sin_addr;
 196:     }
 197:     inp->inp_faddr = sin->sin_addr;
 198:     inp->inp_fport = sin->sin_port;
 199:     return (0);
 200: }
 201: 
 202: in_pcbdisconnect(inp)
 203:     struct inpcb *inp;
 204: {
 205: 
 206:     inp->inp_faddr.s_addr = INADDR_ANY;
 207:     inp->inp_fport = 0;
 208:     if (inp->inp_socket->so_state & SS_NOFDREF)
 209:         in_pcbdetach(inp);
 210: }
 211: 
 212: in_pcbdetach(inp)
 213:     struct inpcb *inp;
 214: {
 215:     struct socket *so = inp->inp_socket;
 216: 
 217:     so->so_pcb = 0;
 218:     sofree(so);
 219:     if (inp->inp_options)
 220:         (void)m_free(inp->inp_options);
 221:     if (inp->inp_route.ro_rt)
 222:         rtfree(inp->inp_route.ro_rt);
 223:     remque(inp);
 224:     (void) m_free(dtom(inp));
 225: }
 226: 
 227: in_setsockaddr(inp, nam)
 228:     register struct inpcb *inp;
 229:     struct mbuf *nam;
 230: {
 231:     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
 232: 
 233:     nam->m_len = sizeof (*sin);
 234:     sin = mtod(nam, struct sockaddr_in *);
 235:     bzero((caddr_t)sin, sizeof (*sin));
 236:     sin->sin_family = AF_INET;
 237:     sin->sin_port = inp->inp_lport;
 238:     sin->sin_addr = inp->inp_laddr;
 239: }
 240: 
 241: in_setpeeraddr(inp, nam)
 242:     register struct inpcb *inp;
 243:     struct mbuf *nam;
 244: {
 245:     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
 246: 
 247:     nam->m_len = sizeof (*sin);
 248:     sin = mtod(nam, struct sockaddr_in *);
 249:     bzero((caddr_t)sin, sizeof (*sin));
 250:     sin->sin_family = AF_INET;
 251:     sin->sin_port = inp->inp_fport;
 252:     sin->sin_addr = inp->inp_faddr;
 253: }
 254: 
 255: /*
 256:  * Pass some notification to all connections of a protocol
 257:  * associated with address dst.  Call the protocol specific
 258:  * routine (if any) to handle each connection.
 259:  */
 260: in_pcbnotify(head, dst, errno, notify)
 261:     struct inpcb *head;
 262:     register struct in_addr *dst;
 263:     int errno, (*notify)();
 264: {
 265:     register struct inpcb *inp, *oinp;
 266:     int s = splimp();
 267: 
 268:     for (inp = head->inp_next; inp != head;) {
 269:         if (inp->inp_faddr.s_addr != dst->s_addr ||
 270:             inp->inp_socket == 0) {
 271:             inp = inp->inp_next;
 272:             continue;
 273:         }
 274:         if (errno)
 275:             inp->inp_socket->so_error = errno;
 276:         oinp = inp;
 277:         inp = inp->inp_next;
 278:         if (notify)
 279:             (*notify)(oinp);
 280:     }
 281:     splx(s);
 282: }
 283: 
 284: /*
 285:  * Check for alternatives when higher level complains
 286:  * about service problems.  For now, invalidate cached
 287:  * routing information.  If the route was created dynamically
 288:  * (by a redirect), time to try a default gateway again.
 289:  */
 290: in_losing(inp)
 291:     struct inpcb *inp;
 292: {
 293:     register struct rtentry *rt;
 294: 
 295:     if ((rt = inp->inp_route.ro_rt)) {
 296:         if (rt->rt_flags & RTF_DYNAMIC)
 297:             (void) rtrequest((int)SIOCDELRT, rt);
 298:         rtfree(rt);
 299:         inp->inp_route.ro_rt = 0;
 300:         /*
 301: 		 * A new route can be allocated
 302: 		 * the next time output is attempted.
 303: 		 */
 304:     }
 305: }
 306: 
 307: /*
 308:  * After a routing change, flush old routing
 309:  * and allocate a (hopefully) better one.
 310:  */
 311: in_rtchange(inp)
 312:     register struct inpcb *inp;
 313: {
 314:     if (inp->inp_route.ro_rt) {
 315:         rtfree(inp->inp_route.ro_rt);
 316:         inp->inp_route.ro_rt = 0;
 317:         /*
 318: 		 * A new route can be allocated the next time
 319: 		 * output is attempted.
 320: 		 */
 321:     }
 322: }
 323: 
 324: struct inpcb *
 325: in_pcblookup(head, faddr, fport, laddr, lport, flags)
 326:     struct inpcb *head;
 327:     struct in_addr faddr, laddr;
 328:     u_short fport, lport;
 329:     int flags;
 330: {
 331:     register struct inpcb *inp, *match = 0;
 332:     int matchwild = 3, wildcard;
 333: 
 334:     for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
 335:         if (inp->inp_lport != lport)
 336:             continue;
 337:         wildcard = 0;
 338:         if (inp->inp_laddr.s_addr != INADDR_ANY) {
 339:             if (laddr.s_addr == INADDR_ANY)
 340:                 wildcard++;
 341:             else if (inp->inp_laddr.s_addr != laddr.s_addr)
 342:                 continue;
 343:         } else {
 344:             if (laddr.s_addr != INADDR_ANY)
 345:                 wildcard++;
 346:         }
 347:         if (inp->inp_faddr.s_addr != INADDR_ANY) {
 348:             if (faddr.s_addr == INADDR_ANY)
 349:                 wildcard++;
 350:             else if (inp->inp_faddr.s_addr != faddr.s_addr ||
 351:                 inp->inp_fport != fport)
 352:                 continue;
 353:         } else {
 354:             if (faddr.s_addr != INADDR_ANY)
 355:                 wildcard++;
 356:         }
 357:         if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
 358:             continue;
 359:         if (wildcard < matchwild) {
 360:             match = inp;
 361:             matchwild = wildcard;
 362:             if (matchwild == 0)
 363:                 break;
 364:         }
 365:     }
 366:     return (match);
 367: }

Defined functions

in_losing defined in line 290; used 1 times
in_pcbbind defined in line 45; used 5 times

Defined variables

zeroin_addr defined in line 25; used 2 times

Defined macros

satosin defined in line 130; used 2 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1549
Valid CSS Valid XHTML 1.0 Strict