|
|
1.1 ! root 1: /* in_pcb.c 6.1 83/07/29 */ ! 2: ! 3: #include "../h/param.h" ! 4: #include "../h/systm.h" ! 5: #include "../h/dir.h" ! 6: #include "../h/user.h" ! 7: #include "../h/mbuf.h" ! 8: #include "../h/socket.h" ! 9: #include "../h/socketvar.h" ! 10: #include "../netinet/in.h" ! 11: #include "../netinet/in_systm.h" ! 12: #include "../net/if.h" ! 13: #include "../net/route.h" ! 14: #include "../netinet/in_pcb.h" ! 15: #include "../h/protosw.h" ! 16: ! 17: struct in_addr zeroin_addr; ! 18: ! 19: in_pcballoc(so, head) ! 20: struct socket *so; ! 21: struct inpcb *head; ! 22: { ! 23: struct mbuf *m; ! 24: register struct inpcb *inp; ! 25: ! 26: m = m_getclr(M_DONTWAIT, MT_PCB); ! 27: if (m == NULL) ! 28: return (ENOBUFS); ! 29: inp = mtod(m, struct inpcb *); ! 30: inp->inp_head = head; ! 31: inp->inp_socket = so; ! 32: insque(inp, head); ! 33: so->so_pcb = (caddr_t)inp; ! 34: return (0); ! 35: } ! 36: ! 37: in_pcbbind(inp, nam) ! 38: register struct inpcb *inp; ! 39: struct mbuf *nam; ! 40: { ! 41: register struct socket *so = inp->inp_socket; ! 42: register struct inpcb *head = inp->inp_head; ! 43: register struct sockaddr_in *sin; ! 44: u_short lport = 0; ! 45: ! 46: if (ifnet == 0) ! 47: return (EADDRNOTAVAIL); ! 48: if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) ! 49: return (EINVAL); ! 50: if (nam == 0) ! 51: goto noname; ! 52: sin = mtod(nam, struct sockaddr_in *); ! 53: if (nam->m_len != sizeof (*sin)) ! 54: return (EINVAL); ! 55: if (sin->sin_addr.s_addr != INADDR_ANY) { ! 56: int tport = sin->sin_port; ! 57: ! 58: sin->sin_port = 0; /* yech... */ ! 59: if (if_ifwithaddr((struct sockaddr *)sin) == 0) ! 60: return (EADDRNOTAVAIL); ! 61: sin->sin_port = tport; ! 62: } ! 63: lport = sin->sin_port; ! 64: if (lport) { ! 65: u_short aport = htons(lport); ! 66: int wild = 0; ! 67: ! 68: /* GROSS */ ! 69: if (aport < IPPORT_RESERVED && u.u_uid != 0) ! 70: return (EACCES); ! 71: /* even GROSSER, but this is the Internet */ ! 72: if ((so->so_options & SO_REUSEADDR) == 0 && ! 73: ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || ! 74: (so->so_options & SO_ACCEPTCONN) == 0)) ! 75: wild = INPLOOKUP_WILDCARD; ! 76: if (in_pcblookup(head, ! 77: zeroin_addr, 0, sin->sin_addr, lport, wild)) ! 78: return (EADDRINUSE); ! 79: } ! 80: inp->inp_laddr = sin->sin_addr; ! 81: noname: ! 82: if (lport == 0) ! 83: do { ! 84: if (head->inp_lport++ < IPPORT_RESERVED) ! 85: head->inp_lport = IPPORT_RESERVED; ! 86: lport = htons(head->inp_lport); ! 87: } while (in_pcblookup(head, ! 88: zeroin_addr, 0, inp->inp_laddr, lport, 0)); ! 89: inp->inp_lport = lport; ! 90: return (0); ! 91: } ! 92: ! 93: /* ! 94: * Connect from a socket to a specified address. ! 95: * Both address and port must be specified in argument sin. ! 96: * If don't have a local address for this socket yet, ! 97: * then pick one. ! 98: */ ! 99: in_pcbconnect(inp, nam) ! 100: struct inpcb *inp; ! 101: struct mbuf *nam; ! 102: { ! 103: struct ifnet *ifp; ! 104: struct sockaddr_in *ifaddr; ! 105: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); ! 106: ! 107: if (nam->m_len != sizeof (*sin)) ! 108: return (EINVAL); ! 109: if (sin->sin_family != AF_INET) ! 110: return (EAFNOSUPPORT); ! 111: if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0) ! 112: return (EADDRNOTAVAIL); ! 113: if (inp->inp_laddr.s_addr == INADDR_ANY) { ! 114: ifp = if_ifonnetof(in_netof(sin->sin_addr)); ! 115: if (ifp == 0) { ! 116: /* ! 117: * We should select the interface based on ! 118: * the route to be used, but for udp this would ! 119: * result in two calls to rtalloc for each packet ! 120: * sent; hardly worthwhile... ! 121: */ ! 122: ifp = if_ifwithaf(AF_INET); ! 123: if (ifp == 0) ! 124: return (EADDRNOTAVAIL); ! 125: } ! 126: ifaddr = (struct sockaddr_in *)&ifp->if_addr; ! 127: } ! 128: if (in_pcblookup(inp->inp_head, ! 129: sin->sin_addr, ! 130: sin->sin_port, ! 131: inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, ! 132: inp->inp_lport, ! 133: 0)) ! 134: return (EADDRINUSE); ! 135: if (inp->inp_laddr.s_addr == INADDR_ANY) { ! 136: if (inp->inp_lport == 0) ! 137: in_pcbbind(inp, (struct mbuf *)0); ! 138: inp->inp_laddr = ifaddr->sin_addr; ! 139: } ! 140: inp->inp_faddr = sin->sin_addr; ! 141: inp->inp_fport = sin->sin_port; ! 142: return (0); ! 143: } ! 144: ! 145: in_pcbdisconnect(inp) ! 146: struct inpcb *inp; ! 147: { ! 148: ! 149: inp->inp_faddr.s_addr = INADDR_ANY; ! 150: inp->inp_fport = 0; ! 151: if (inp->inp_socket->so_state & SS_NOFDREF) ! 152: in_pcbdetach(inp); ! 153: } ! 154: ! 155: in_pcbdetach(inp) ! 156: struct inpcb *inp; ! 157: { ! 158: struct socket *so = inp->inp_socket; ! 159: ! 160: so->so_pcb = 0; ! 161: sofree(so); ! 162: if (inp->inp_route.ro_rt) ! 163: rtfree(inp->inp_route.ro_rt); ! 164: remque(inp); ! 165: (void) m_free(dtom(inp)); ! 166: } ! 167: ! 168: in_setsockaddr(inp, nam) ! 169: register struct inpcb *inp; ! 170: struct mbuf *nam; ! 171: { ! 172: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); ! 173: ! 174: nam->m_len = sizeof (*sin); ! 175: sin = mtod(nam, struct sockaddr_in *); ! 176: bzero((caddr_t)sin, sizeof (*sin)); ! 177: sin->sin_family = AF_INET; ! 178: sin->sin_port = inp->inp_lport; ! 179: sin->sin_addr = inp->inp_laddr; ! 180: } ! 181: ! 182: in_setpeeraddr(inp, nam) ! 183: register struct inpcb *inp; ! 184: struct mbuf *nam; ! 185: { ! 186: register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); ! 187: ! 188: nam->m_len = sizeof (*sin); ! 189: sin = mtod(nam, struct sockaddr_in *); ! 190: bzero((caddr_t)sin, sizeof (*sin)); ! 191: sin->sin_family = AF_INET; ! 192: sin->sin_port = inp->inp_fport; ! 193: sin->sin_addr = inp->inp_faddr; ! 194: } ! 195: ! 196: /* ! 197: * Pass an error to all internet connections ! 198: * associated with address sin. Call the ! 199: * protocol specific routine to clean up the ! 200: * mess afterwards. ! 201: */ ! 202: in_pcbnotify(head, dst, errno, abort) ! 203: struct inpcb *head; ! 204: register struct in_addr *dst; ! 205: int errno, (*abort)(); ! 206: { ! 207: register struct inpcb *inp, *oinp; ! 208: int s = splimp(); ! 209: ! 210: for (inp = head->inp_next; inp != head;) { ! 211: if (inp->inp_faddr.s_addr != dst->s_addr) { ! 212: next: ! 213: inp = inp->inp_next; ! 214: continue; ! 215: } ! 216: if (inp->inp_socket == 0) ! 217: goto next; ! 218: inp->inp_socket->so_error = errno; ! 219: oinp = inp; ! 220: inp = inp->inp_next; ! 221: (*abort)(oinp); ! 222: } ! 223: splx(s); ! 224: } ! 225: ! 226: struct inpcb * ! 227: in_pcblookup(head, faddr, fport, laddr, lport, flags) ! 228: struct inpcb *head; ! 229: struct in_addr faddr, laddr; ! 230: u_short fport, lport; ! 231: int flags; ! 232: { ! 233: register struct inpcb *inp, *match = 0; ! 234: int matchwild = 3, wildcard; ! 235: ! 236: for (inp = head->inp_next; inp != head; inp = inp->inp_next) { ! 237: if (inp->inp_lport != lport) ! 238: continue; ! 239: wildcard = 0; ! 240: if (inp->inp_laddr.s_addr != INADDR_ANY) { ! 241: if (laddr.s_addr == INADDR_ANY) ! 242: wildcard++; ! 243: else if (inp->inp_laddr.s_addr != laddr.s_addr) ! 244: continue; ! 245: } else { ! 246: if (laddr.s_addr != INADDR_ANY) ! 247: wildcard++; ! 248: } ! 249: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 250: if (faddr.s_addr == INADDR_ANY) ! 251: wildcard++; ! 252: else if (inp->inp_faddr.s_addr != faddr.s_addr || ! 253: inp->inp_fport != fport) ! 254: continue; ! 255: } else { ! 256: if (faddr.s_addr != INADDR_ANY) ! 257: wildcard++; ! 258: } ! 259: if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) ! 260: continue; ! 261: if (wildcard < matchwild) { ! 262: match = inp; ! 263: matchwild = wildcard; ! 264: if (matchwild == 0) ! 265: break; ! 266: } ! 267: } ! 268: return (match); ! 269: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.