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.1 (Berkeley) 6/5/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: (ifp = 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: * If we found a route, use the address 163: * corresponding to the outgoing interface 164: * unless it is the loopback (in case a route 165: * to our address on another net goes to loopback). 166: */ 167: if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) && 168: (ifp->if_flags & IFF_LOOPBACK) == 0) 169: for (ia = in_ifaddr; ia; ia = ia->ia_next) 170: if (ia->ia_ifp == ifp) 171: break; 172: } 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: }