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