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