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