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