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