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