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.6 (Berkeley) 09/02/88 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 *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_family = AF_NS; 236 sns->sns_addr = nsp->nsp_laddr; 237 } 238 239 ns_setpeeraddr(nsp, nam) 240 register struct nspcb *nsp; 241 struct mbuf *nam; 242 { 243 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 244 245 nam->m_len = sizeof (*sns); 246 sns = mtod(nam, struct sockaddr_ns *); 247 bzero((caddr_t)sns, sizeof (*sns)); 248 sns->sns_family = AF_NS; 249 sns->sns_addr = nsp->nsp_faddr; 250 } 251 252 /* 253 * Pass some notification to all connections of a protocol 254 * associated with address dst. Call the 255 * protocol specific routine to handle each connection. 256 * Also pass an extra paramter via the nspcb. (which may in fact 257 * be a parameter list!) 258 */ 259 ns_pcbnotify(dst, errno, notify, param) 260 register struct ns_addr *dst; 261 long param; 262 int errno, (*notify)(); 263 { 264 register struct nspcb *nsp, *oinp; 265 int s = splimp(); 266 267 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) { 268 if (!ns_hosteq(*dst,nsp->nsp_faddr)) { 269 next: 270 nsp = nsp->nsp_next; 271 continue; 272 } 273 if (nsp->nsp_socket == 0) 274 goto next; 275 if (errno) 276 nsp->nsp_socket->so_error = errno; 277 oinp = nsp; 278 nsp = nsp->nsp_next; 279 oinp->nsp_notify_param = param; 280 (*notify)(oinp); 281 } 282 splx(s); 283 } 284 285 #ifdef notdef 286 /* 287 * After a routing change, flush old routing 288 * and allocate a (hopefully) better one. 289 */ 290 ns_rtchange(nsp) 291 struct nspcb *nsp; 292 { 293 if (nsp->nsp_route.ro_rt) { 294 rtfree(nsp->nsp_route.ro_rt); 295 nsp->nsp_route.ro_rt = 0; 296 /* 297 * A new route can be allocated the next time 298 * output is attempted. 299 */ 300 } 301 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 302 } 303 #endif 304 305 struct nspcb * 306 ns_pcblookup(faddr, lport, wildp) 307 struct ns_addr *faddr; 308 u_short lport; 309 { 310 register struct nspcb *nsp, *match = 0; 311 int matchwild = 3, wildcard; 312 u_short fport; 313 314 fport = faddr->x_port; 315 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) { 316 if (nsp->nsp_lport != lport) 317 continue; 318 wildcard = 0; 319 if (ns_nullhost(nsp->nsp_faddr)) { 320 if (!ns_nullhost(*faddr)) 321 wildcard++; 322 } else { 323 if (ns_nullhost(*faddr)) 324 wildcard++; 325 else { 326 if (!ns_hosteq(nsp->nsp_faddr, *faddr)) 327 continue; 328 if( nsp->nsp_fport != fport) { 329 if(nsp->nsp_fport != 0) 330 continue; 331 else 332 wildcard++; 333 } 334 } 335 } 336 if (wildcard && wildp==0) 337 continue; 338 if (wildcard < matchwild) { 339 match = nsp; 340 matchwild = wildcard; 341 if (wildcard == 0) 342 break; 343 } 344 } 345 return (match); 346 } 347