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