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