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: }