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