1 /* 2 * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)ns_pcb.c 7.7 (Berkeley) 04/22/89 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "dir.h" 23 #include "user.h" 24 #include "mbuf.h" 25 #include "socket.h" 26 #include "socketvar.h" 27 #include "../net/if.h" 28 #include "../net/route.h" 29 #include "protosw.h" 30 31 #include "ns.h" 32 #include "ns_if.h" 33 #include "ns_pcb.h" 34 35 struct ns_addr zerons_addr; 36 37 ns_pcballoc(so, head) 38 struct socket *so; 39 struct nspcb *head; 40 { 41 struct mbuf *m; 42 register struct nspcb *nsp; 43 44 m = m_getclr(M_DONTWAIT, MT_PCB); 45 if (m == NULL) 46 return (ENOBUFS); 47 nsp = mtod(m, struct nspcb *); 48 nsp->nsp_socket = so; 49 insque(nsp, head); 50 so->so_pcb = (caddr_t)nsp; 51 return (0); 52 } 53 54 ns_pcbbind(nsp, nam) 55 register struct nspcb *nsp; 56 struct mbuf *nam; 57 { 58 register struct sockaddr_ns *sns; 59 u_short lport = 0; 60 61 if (nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr)) 62 return (EINVAL); 63 if (nam == 0) 64 goto noname; 65 sns = mtod(nam, struct sockaddr_ns *); 66 if (nam->m_len != sizeof (*sns)) 67 return (EINVAL); 68 if (!ns_nullhost(sns->sns_addr)) { 69 int tport = sns->sns_port; 70 71 sns->sns_port = 0; /* yech... */ 72 if (ifa_ifwithaddr((struct sockaddr *)sns) == 0) 73 return (EADDRNOTAVAIL); 74 sns->sns_port = tport; 75 } 76 lport = sns->sns_port; 77 if (lport) { 78 u_short aport = ntohs(lport); 79 80 if (aport < NSPORT_RESERVED && u.u_uid != 0) 81 return (EACCES); 82 if (ns_pcblookup(&zerons_addr, lport, 0)) 83 return (EADDRINUSE); 84 } 85 nsp->nsp_laddr = sns->sns_addr; 86 noname: 87 if (lport == 0) 88 do { 89 if (nspcb.nsp_lport++ < NSPORT_RESERVED) 90 nspcb.nsp_lport = NSPORT_RESERVED; 91 lport = htons(nspcb.nsp_lport); 92 } while (ns_pcblookup(&zerons_addr, lport, 0)); 93 nsp->nsp_lport = lport; 94 return (0); 95 } 96 97 /* 98 * Connect from a socket to a specified address. 99 * Both address and port must be specified in argument sns. 100 * If don't have a local address for this socket yet, 101 * then pick one. 102 */ 103 ns_pcbconnect(nsp, nam) 104 struct nspcb *nsp; 105 struct mbuf *nam; 106 { 107 struct ns_ifaddr *ia; 108 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 109 register struct ns_addr *dst; 110 register struct route *ro; 111 struct ifnet *ifp; 112 113 if (nam->m_len != sizeof (*sns)) 114 return (EINVAL); 115 if (sns->sns_family != AF_NS) 116 return (EAFNOSUPPORT); 117 if (sns->sns_port==0 || ns_nullhost(sns->sns_addr)) 118 return (EADDRNOTAVAIL); 119 /* 120 * If we haven't bound which network number to use as ours, 121 * we will use the number of the outgoing interface. 122 * This depends on having done a routing lookup, which 123 * we will probably have to do anyway, so we might 124 * as well do it now. On the other hand if we are 125 * sending to multiple destinations we may have already 126 * done the lookup, so see if we can use the route 127 * from before. In any case, we only 128 * chose a port number once, even if sending to multiple 129 * destinations. 130 */ 131 ro = &nsp->nsp_route; 132 dst = &satons_addr(ro->ro_dst); 133 if (ro->ro_rt) { 134 if (nsp->nsp_socket->so_options & SO_DONTROUTE) 135 goto flush; 136 if (!ns_neteq(nsp->nsp_lastdst, sns->sns_addr)) 137 goto flush; 138 if (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr)) { 139 if (((ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) 140 == RTF_GATEWAY) 141 || ((ifp = ro->ro_rt->rt_ifp) && 142 !(ifp->if_flags & IFF_POINTOPOINT))) { 143 /* can patch route to avoid rtalloc */ 144 *dst = sns->sns_addr; 145 } else { 146 flush: 147 RTFREE(ro->ro_rt); 148 ro->ro_rt = (struct rtentry *)0; 149 } 150 }/* else cached route is ok; do nothing */ 151 } 152 nsp->nsp_lastdst = sns->sns_addr; 153 if ((nsp->nsp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 154 (ro->ro_rt == (struct rtentry *)0 || 155 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 156 /* No route yet, so try to acquire one */ 157 ro->ro_dst.sa_family = AF_NS; 158 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 159 *dst = sns->sns_addr; 160 dst->x_port = 0; 161 rtalloc(ro); 162 } 163 if (ns_neteqnn(nsp->nsp_laddr.x_net, ns_zeronet)) { 164 /* 165 * If route is known or can be allocated now, 166 * our src addr is taken from the i/f, else punt. 167 */ 168 169 ia = (struct ns_ifaddr *)0; 170 /* 171 * If we found a route, use the address 172 * corresponding to the outgoing interface 173 */ 174 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) 175 for (ia = ns_ifaddr; ia; ia = ia->ia_next) 176 if (ia->ia_ifp == ifp) 177 break; 178 if (ia == 0) { 179 u_short fport = sns->sns_addr.x_port; 180 sns->sns_addr.x_port = 0; 181 ia = (struct ns_ifaddr *) 182 ifa_ifwithdstaddr((struct sockaddr *)sns); 183 sns->sns_addr.x_port = fport; 184 if (ia == 0) 185 ia = ns_iaonnetof(&sns->sns_addr); 186 if (ia == 0) 187 ia = ns_ifaddr; 188 if (ia == 0) 189 return (EADDRNOTAVAIL); 190 } 191 nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net; 192 } 193 if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0)) 194 return (EADDRINUSE); 195 if (ns_nullhost(nsp->nsp_laddr)) { 196 if (nsp->nsp_lport == 0) 197 (void) ns_pcbbind(nsp, (struct mbuf *)0); 198 nsp->nsp_laddr.x_host = ns_thishost; 199 } 200 nsp->nsp_faddr = sns->sns_addr; 201 /* Includes nsp->nsp_fport = sns->sns_port; */ 202 return (0); 203 } 204 205 ns_pcbdisconnect(nsp) 206 struct nspcb *nsp; 207 { 208 209 nsp->nsp_faddr = zerons_addr; 210 if (nsp->nsp_socket->so_state & SS_NOFDREF) 211 ns_pcbdetach(nsp); 212 } 213 214 ns_pcbdetach(nsp) 215 struct nspcb *nsp; 216 { 217 struct socket *so = nsp->nsp_socket; 218 219 so->so_pcb = 0; 220 sofree(so); 221 if (nsp->nsp_route.ro_rt) 222 rtfree(nsp->nsp_route.ro_rt); 223 remque(nsp); 224 (void) m_free(dtom(nsp)); 225 } 226 227 ns_setsockaddr(nsp, nam) 228 register struct nspcb *nsp; 229 struct mbuf *nam; 230 { 231 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 232 233 nam->m_len = sizeof (*sns); 234 sns = mtod(nam, struct sockaddr_ns *); 235 bzero((caddr_t)sns, sizeof (*sns)); 236 sns->sns_len = sizeof(*sns); 237 sns->sns_family = AF_NS; 238 sns->sns_addr = nsp->nsp_laddr; 239 } 240 241 ns_setpeeraddr(nsp, nam) 242 register struct nspcb *nsp; 243 struct mbuf *nam; 244 { 245 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 246 247 nam->m_len = sizeof (*sns); 248 sns = mtod(nam, struct sockaddr_ns *); 249 bzero((caddr_t)sns, sizeof (*sns)); 250 sns->sns_len = sizeof(*sns); 251 sns->sns_family = AF_NS; 252 sns->sns_addr = nsp->nsp_faddr; 253 } 254 255 /* 256 * Pass some notification to all connections of a protocol 257 * associated with address dst. Call the 258 * protocol specific routine to handle each connection. 259 * Also pass an extra paramter via the nspcb. (which may in fact 260 * be a parameter list!) 261 */ 262 ns_pcbnotify(dst, errno, notify, param) 263 register struct ns_addr *dst; 264 long param; 265 int errno, (*notify)(); 266 { 267 register struct nspcb *nsp, *oinp; 268 int s = splimp(); 269 270 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) { 271 if (!ns_hosteq(*dst,nsp->nsp_faddr)) { 272 next: 273 nsp = nsp->nsp_next; 274 continue; 275 } 276 if (nsp->nsp_socket == 0) 277 goto next; 278 if (errno) 279 nsp->nsp_socket->so_error = errno; 280 oinp = nsp; 281 nsp = nsp->nsp_next; 282 oinp->nsp_notify_param = param; 283 (*notify)(oinp); 284 } 285 splx(s); 286 } 287 288 #ifdef notdef 289 /* 290 * After a routing change, flush old routing 291 * and allocate a (hopefully) better one. 292 */ 293 ns_rtchange(nsp) 294 struct nspcb *nsp; 295 { 296 if (nsp->nsp_route.ro_rt) { 297 rtfree(nsp->nsp_route.ro_rt); 298 nsp->nsp_route.ro_rt = 0; 299 /* 300 * A new route can be allocated the next time 301 * output is attempted. 302 */ 303 } 304 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 305 } 306 #endif 307 308 struct nspcb * 309 ns_pcblookup(faddr, lport, wildp) 310 struct ns_addr *faddr; 311 u_short lport; 312 { 313 register struct nspcb *nsp, *match = 0; 314 int matchwild = 3, wildcard; 315 u_short fport; 316 317 fport = faddr->x_port; 318 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) { 319 if (nsp->nsp_lport != lport) 320 continue; 321 wildcard = 0; 322 if (ns_nullhost(nsp->nsp_faddr)) { 323 if (!ns_nullhost(*faddr)) 324 wildcard++; 325 } else { 326 if (ns_nullhost(*faddr)) 327 wildcard++; 328 else { 329 if (!ns_hosteq(nsp->nsp_faddr, *faddr)) 330 continue; 331 if (nsp->nsp_fport != fport) { 332 if (nsp->nsp_fport != 0) 333 continue; 334 else 335 wildcard++; 336 } 337 } 338 } 339 if (wildcard && wildp==0) 340 continue; 341 if (wildcard < matchwild) { 342 match = nsp; 343 matchwild = wildcard; 344 if (wildcard == 0) 345 break; 346 } 347 } 348 return (match); 349 } 350