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.4 (Berkeley) 05/22/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 register struct ns_addr *dst; 105 106 if (nam->m_len != sizeof (*sns)) 107 return (EINVAL); 108 if (sns->sns_family != AF_NS) 109 return (EAFNOSUPPORT); 110 if (sns->sns_port==0 || ns_nullhost(sns->sns_addr)) 111 return (EADDRNOTAVAIL); 112 if (ns_nullhost(nsp->nsp_laddr)) { 113 register struct route *ro; 114 struct ifnet *ifp; 115 /* 116 * If route is known or can be allocated now, 117 * our src addr is taken from the i/f, else punt. 118 */ 119 ro = &nsp->nsp_route; 120 dst = &satons_addr(ro->ro_dst); 121 122 ia = (struct ns_ifaddr *)0; 123 if (ro->ro_rt) { 124 if ((!ns_neteq(nsp->nsp_lastdst, sns->sns_addr)) || 125 ((ifp = ro->ro_rt->rt_ifp) && 126 (ifp->if_flags & IFF_POINTOPOINT) && 127 (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr))) || 128 (nsp->nsp_socket->so_options & SO_DONTROUTE)) { 129 RTFREE(ro->ro_rt); 130 ro->ro_rt = (struct rtentry *)0; 131 } 132 } 133 if ((nsp->nsp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 134 (ro->ro_rt == (struct rtentry *)0 || 135 ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 136 /* No route yet, so try to acquire one */ 137 ro->ro_dst.sa_family = AF_NS; 138 *dst = sns->sns_addr; 139 dst->x_port = 0; 140 rtalloc(ro); 141 } 142 /* 143 * If we found a route, use the address 144 * corresponding to the outgoing interface 145 */ 146 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) 147 for (ia = ns_ifaddr; ia; ia = ia->ia_next) 148 if (ia->ia_ifp == ifp) 149 break; 150 if (ia == 0) { 151 u_short fport = sns->sns_addr.x_port; 152 sns->sns_addr.x_port = 0; 153 ia = (struct ns_ifaddr *) 154 ifa_ifwithdstaddr((struct sockaddr *)sns); 155 sns->sns_addr.x_port = fport; 156 if (ia == 0) 157 ia = ns_iaonnetof(&sns->sns_addr); 158 if (ia == 0) 159 ia = ns_ifaddr; 160 if (ia == 0) 161 return (EADDRNOTAVAIL); 162 } 163 nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net; 164 nsp->nsp_lastdst = sns->sns_addr; 165 } 166 if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0)) 167 return (EADDRINUSE); 168 if (ns_nullhost(nsp->nsp_laddr)) { 169 if (nsp->nsp_lport == 0) 170 (void) ns_pcbbind(nsp, (struct mbuf *)0); 171 nsp->nsp_laddr.x_host = ns_thishost; 172 } 173 nsp->nsp_faddr = sns->sns_addr; 174 /* Includes nsp->nsp_fport = sns->sns_port; */ 175 return (0); 176 } 177 178 ns_pcbdisconnect(nsp) 179 struct nspcb *nsp; 180 { 181 182 nsp->nsp_faddr = zerons_addr; 183 if (nsp->nsp_socket->so_state & SS_NOFDREF) 184 ns_pcbdetach(nsp); 185 } 186 187 ns_pcbdetach(nsp) 188 struct nspcb *nsp; 189 { 190 struct socket *so = nsp->nsp_socket; 191 192 so->so_pcb = 0; 193 sofree(so); 194 if (nsp->nsp_route.ro_rt) 195 rtfree(nsp->nsp_route.ro_rt); 196 remque(nsp); 197 (void) m_free(dtom(nsp)); 198 } 199 200 ns_setsockaddr(nsp, nam) 201 register struct nspcb *nsp; 202 struct mbuf *nam; 203 { 204 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 205 206 nam->m_len = sizeof (*sns); 207 sns = mtod(nam, struct sockaddr_ns *); 208 bzero((caddr_t)sns, sizeof (*sns)); 209 sns->sns_family = AF_NS; 210 sns->sns_addr = nsp->nsp_laddr; 211 } 212 213 ns_setpeeraddr(nsp, nam) 214 register struct nspcb *nsp; 215 struct mbuf *nam; 216 { 217 register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 218 219 nam->m_len = sizeof (*sns); 220 sns = mtod(nam, struct sockaddr_ns *); 221 bzero((caddr_t)sns, sizeof (*sns)); 222 sns->sns_family = AF_NS; 223 sns->sns_addr = nsp->nsp_faddr; 224 } 225 226 /* 227 * Pass some notification to all connections of a protocol 228 * associated with address dst. Call the 229 * protocol specific routine to handle each connection. 230 * Also pass an extra paramter via the nspcb. (which may in fact 231 * be a parameter list!) 232 */ 233 ns_pcbnotify(dst, errno, notify, param) 234 register struct ns_addr *dst; 235 long param; 236 int errno, (*notify)(); 237 { 238 register struct nspcb *nsp, *oinp; 239 int s = splimp(); 240 241 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) { 242 if (!ns_hosteq(*dst,nsp->nsp_faddr)) { 243 next: 244 nsp = nsp->nsp_next; 245 continue; 246 } 247 if (nsp->nsp_socket == 0) 248 goto next; 249 if (errno) 250 nsp->nsp_socket->so_error = errno; 251 oinp = nsp; 252 nsp = nsp->nsp_next; 253 oinp->nsp_notify_param = param; 254 (*notify)(oinp); 255 } 256 splx(s); 257 } 258 259 #ifdef notdef 260 /* 261 * After a routing change, flush old routing 262 * and allocate a (hopefully) better one. 263 */ 264 ns_rtchange(nsp) 265 struct nspcb *nsp; 266 { 267 if (nsp->nsp_route.ro_rt) { 268 rtfree(nsp->nsp_route.ro_rt); 269 nsp->nsp_route.ro_rt = 0; 270 /* 271 * A new route can be allocated the next time 272 * output is attempted. 273 */ 274 } 275 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 276 } 277 #endif 278 279 struct nspcb * 280 ns_pcblookup(faddr, lport, wildp) 281 struct ns_addr *faddr; 282 u_short lport; 283 { 284 register struct nspcb *nsp, *match = 0; 285 int matchwild = 3, wildcard; 286 u_short fport; 287 288 fport = faddr->x_port; 289 for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) { 290 if (nsp->nsp_lport != lport) 291 continue; 292 wildcard = 0; 293 if (ns_nullhost(nsp->nsp_faddr)) { 294 if (!ns_nullhost(*faddr)) 295 wildcard++; 296 } else { 297 if (ns_nullhost(*faddr)) 298 wildcard++; 299 else { 300 if (!ns_hosteq(nsp->nsp_faddr, *faddr)) 301 continue; 302 if( nsp->nsp_fport != fport) { 303 if(nsp->nsp_fport != 0) 304 continue; 305 else 306 wildcard++; 307 } 308 } 309 } 310 if (wildcard && wildp==0) 311 continue; 312 if (wildcard < matchwild) { 313 match = nsp; 314 matchwild = wildcard; 315 if (wildcard == 0) 316 break; 317 } 318 } 319 return (match); 320 } 321