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

Defined functions

in_losing defined in line 334; never used
in_pcballoc defined in line 34; never used
in_pcbbind defined in line 52; used 1 times
in_pcbconnect defined in line 115; never used
in_pcbdetach defined in line 224; used 1 times
in_pcbdisconnect defined in line 214; never used
in_pcblookup defined in line 368; used 3 times
in_pcbnotify defined in line 278; never used
in_rtchange defined in line 355; used 2 times
in_setpeeraddr defined in line 253; never used
in_setsockaddr defined in line 239; never used

Defined variables

zeroin_addr defined in line 32; used 2 times

Defined macros

satosin defined in line 137; used 2 times
Last modified: 1994-02-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4373
Valid CSS Valid XHTML 1.0 Strict