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) 1/20/88 13: */ 14: 15: #include "param.h" 16: #ifdef NS 17: #include "systm.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: #endif