1 /* in_pcb.c 6.7 85/04/18 */ 2 3 #include "param.h" 4 #include "systm.h" 5 #include "dir.h" 6 #include "user.h" 7 #include "mbuf.h" 8 #include "socket.h" 9 #include "socketvar.h" 10 #include "in.h" 11 #include "in_systm.h" 12 #include "../net/if.h" 13 #include "../net/route.h" 14 #include "in_pcb.h" 15 #include "in_var.h" 16 #include "protosw.h" 17 18 struct in_addr zeroin_addr; 19 20 in_pcballoc(so, head) 21 struct socket *so; 22 struct inpcb *head; 23 { 24 struct mbuf *m; 25 register struct inpcb *inp; 26 27 m = m_getclr(M_DONTWAIT, MT_PCB); 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 (in_ifaddr == 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 (ifa_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 in_ifaddr *ia; 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_port == 0) 113 return (EADDRNOTAVAIL); 114 if (in_ifaddr) { 115 /* 116 * If the destination address is INADDR_ANY, 117 * use the primary local address. 118 * If the supplied address is INADDR_BROADCAST, 119 * and the primary interface supports broadcast, 120 * choose the broadcast address for that interface. 121 */ 122 #define satosin(sa) ((struct sockaddr_in *)(sa)) 123 if (sin->sin_addr.s_addr == INADDR_ANY) 124 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; 125 else if (sin->sin_addr.s_addr == INADDR_BROADCAST && 126 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) 127 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; 128 } 129 if (inp->inp_laddr.s_addr == INADDR_ANY) { 130 ia = (struct in_ifaddr *)ifa_ifwithnet((struct sockaddr *)sin); 131 if (ia == (struct in_ifaddr *)0) { 132 register struct route *ro; 133 struct ifnet *ifp; 134 135 /* 136 * If route is known or can be allocated now, 137 * our src addr is taken from the i/f, else punt. 138 */ 139 ro = &inp->inp_route; 140 if (ro->ro_rt && 141 satosin(&ro->ro_dst)->sin_addr.s_addr != 142 sin->sin_addr.s_addr) { 143 RTFREE(ro->ro_rt); 144 ro->ro_rt = (struct rtentry *)0; 145 } 146 if ((ro->ro_rt == (struct rtentry *)0) || 147 (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) { 148 /* No route yet, so try to acquire one */ 149 ro->ro_dst.sa_family = AF_INET; 150 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = 151 sin->sin_addr; 152 rtalloc(ro); 153 if (ro->ro_rt == 0) 154 ifp = (struct ifnet *)0; 155 else 156 ifp = ro->ro_rt->rt_ifp; 157 } 158 if (ifp) { 159 for (ia = in_ifaddr; ia; ia = ia->ia_next) 160 if (ia->ia_ifp == ifp) 161 break; 162 } else 163 ia = (struct in_ifaddr *)0; 164 if (ia == 0) 165 ia = in_ifaddr; 166 if (ia == 0) 167 return (EADDRNOTAVAIL); 168 } 169 ifaddr = (struct sockaddr_in *)&ia->ia_addr; 170 } 171 if (in_pcblookup(inp->inp_head, 172 sin->sin_addr, 173 sin->sin_port, 174 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, 175 inp->inp_lport, 176 0)) 177 return (EADDRINUSE); 178 if (inp->inp_laddr.s_addr == INADDR_ANY) { 179 if (inp->inp_lport == 0) 180 in_pcbbind(inp, (struct mbuf *)0); 181 inp->inp_laddr = ifaddr->sin_addr; 182 } 183 inp->inp_faddr = sin->sin_addr; 184 inp->inp_fport = sin->sin_port; 185 return (0); 186 } 187 188 in_pcbdisconnect(inp) 189 struct inpcb *inp; 190 { 191 192 inp->inp_faddr.s_addr = INADDR_ANY; 193 inp->inp_fport = 0; 194 if (inp->inp_socket->so_state & SS_NOFDREF) 195 in_pcbdetach(inp); 196 } 197 198 in_pcbdetach(inp) 199 struct inpcb *inp; 200 { 201 struct socket *so = inp->inp_socket; 202 203 so->so_pcb = 0; 204 sofree(so); 205 if (inp->inp_route.ro_rt) 206 rtfree(inp->inp_route.ro_rt); 207 remque(inp); 208 (void) m_free(dtom(inp)); 209 } 210 211 in_setsockaddr(inp, nam) 212 register struct inpcb *inp; 213 struct mbuf *nam; 214 { 215 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 216 217 nam->m_len = sizeof (*sin); 218 sin = mtod(nam, struct sockaddr_in *); 219 bzero((caddr_t)sin, sizeof (*sin)); 220 sin->sin_family = AF_INET; 221 sin->sin_port = inp->inp_lport; 222 sin->sin_addr = inp->inp_laddr; 223 } 224 225 in_setpeeraddr(inp, nam) 226 register struct inpcb *inp; 227 struct mbuf *nam; 228 { 229 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); 230 231 nam->m_len = sizeof (*sin); 232 sin = mtod(nam, struct sockaddr_in *); 233 bzero((caddr_t)sin, sizeof (*sin)); 234 sin->sin_family = AF_INET; 235 sin->sin_port = inp->inp_fport; 236 sin->sin_addr = inp->inp_faddr; 237 } 238 239 /* 240 * Pass some notification to all connections of a protocol 241 * associated with address dst. Call the 242 * protocol specific routine to handle each connection. 243 */ 244 in_pcbnotify(head, dst, errno, notify) 245 struct inpcb *head; 246 register struct in_addr *dst; 247 int errno, (*notify)(); 248 { 249 register struct inpcb *inp, *oinp; 250 int s = splimp(); 251 252 for (inp = head->inp_next; inp != head;) { 253 if (inp->inp_faddr.s_addr != dst->s_addr) { 254 next: 255 inp = inp->inp_next; 256 continue; 257 } 258 if (inp->inp_socket == 0) 259 goto next; 260 if (errno) 261 inp->inp_socket->so_error = errno; 262 oinp = inp; 263 inp = inp->inp_next; 264 (*notify)(oinp); 265 } 266 splx(s); 267 } 268 269 /* 270 * After a routing change, flush old routing 271 * and allocate a (hopefully) better one. 272 */ 273 in_rtchange(inp) 274 struct inpcb *inp; 275 { 276 if (inp->inp_route.ro_rt) { 277 rtfree(inp->inp_route.ro_rt); 278 inp->inp_route.ro_rt = 0; 279 /* 280 * A new route can be allocated the next time 281 * output is attempted. 282 */ 283 } 284 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 285 } 286 287 struct inpcb * 288 in_pcblookup(head, faddr, fport, laddr, lport, flags) 289 struct inpcb *head; 290 struct in_addr faddr, laddr; 291 u_short fport, lport; 292 int flags; 293 { 294 register struct inpcb *inp, *match = 0; 295 int matchwild = 3, wildcard; 296 297 for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 298 if (inp->inp_lport != lport) 299 continue; 300 wildcard = 0; 301 if (inp->inp_laddr.s_addr != INADDR_ANY) { 302 if (laddr.s_addr == INADDR_ANY) 303 wildcard++; 304 else if (inp->inp_laddr.s_addr != laddr.s_addr) 305 continue; 306 } else { 307 if (laddr.s_addr != INADDR_ANY) 308 wildcard++; 309 } 310 if (inp->inp_faddr.s_addr != INADDR_ANY) { 311 if (faddr.s_addr == INADDR_ANY) 312 wildcard++; 313 else if (inp->inp_faddr.s_addr != faddr.s_addr || 314 inp->inp_fport != fport) 315 continue; 316 } else { 317 if (faddr.s_addr != INADDR_ANY) 318 wildcard++; 319 } 320 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) 321 continue; 322 if (wildcard < matchwild) { 323 match = inp; 324 matchwild = wildcard; 325 if (matchwild == 0) 326 break; 327 } 328 } 329 return (match); 330 } 331