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