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