123212Smckusick /* 233371Ssklower * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 333371Ssklower * All rights reserved. 423212Smckusick * 533371Ssklower * Redistribution and use in source and binary forms are permitted 6*34856Sbostic * provided that the above copyright notice and this paragraph are 7*34856Sbostic * duplicated in all such forms and that any documentation, 8*34856Sbostic * advertising materials, and other materials related to such 9*34856Sbostic * distribution and use acknowledge that the software was developed 10*34856Sbostic * by the University of California, Berkeley. The name of the 11*34856Sbostic * University may not be used to endorse or promote products derived 12*34856Sbostic * from this software without specific prior written permission. 13*34856Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34856Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34856Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633371Ssklower * 17*34856Sbostic * @(#)ns_pcb.c 7.5 (Berkeley) 06/29/88 1823212Smckusick */ 1921489Ssklower 2021489Ssklower #include "param.h" 2121489Ssklower #include "systm.h" 2221489Ssklower #include "dir.h" 2321489Ssklower #include "user.h" 2421489Ssklower #include "mbuf.h" 2521489Ssklower #include "socket.h" 2621489Ssklower #include "socketvar.h" 2721489Ssklower #include "../net/if.h" 2821489Ssklower #include "../net/route.h" 2921489Ssklower #include "protosw.h" 3021489Ssklower 3121489Ssklower #include "ns.h" 3221489Ssklower #include "ns_if.h" 3321489Ssklower #include "ns_pcb.h" 3421489Ssklower 3521489Ssklower struct ns_addr zerons_addr; 3621489Ssklower 3721489Ssklower ns_pcballoc(so, head) 3821489Ssklower struct socket *so; 3924226Ssklower struct nspcb *head; 4021489Ssklower { 4121489Ssklower struct mbuf *m; 4221489Ssklower register struct nspcb *nsp; 4321489Ssklower 4421489Ssklower m = m_getclr(M_DONTWAIT, MT_PCB); 4521489Ssklower if (m == NULL) 4621489Ssklower return (ENOBUFS); 4721489Ssklower nsp = mtod(m, struct nspcb *); 4821489Ssklower nsp->nsp_socket = so; 4921489Ssklower insque(nsp, head); 5021489Ssklower so->so_pcb = (caddr_t)nsp; 5121489Ssklower return (0); 5221489Ssklower } 5321489Ssklower 5421489Ssklower ns_pcbbind(nsp, nam) 5521489Ssklower register struct nspcb *nsp; 5621489Ssklower struct mbuf *nam; 5721489Ssklower { 5821489Ssklower register struct sockaddr_ns *sns; 5921489Ssklower u_short lport = 0; 6021489Ssklower 6121489Ssklower if(nsp->nsp_lport || !ns_nullhost(nsp->nsp_laddr)) 6221489Ssklower return (EINVAL); 6321489Ssklower if (nam == 0) 6421489Ssklower goto noname; 6521489Ssklower sns = mtod(nam, struct sockaddr_ns *); 6621489Ssklower if (nam->m_len != sizeof (*sns)) 6721489Ssklower return (EINVAL); 6821489Ssklower if (!ns_nullhost(sns->sns_addr)) { 6921489Ssklower int tport = sns->sns_port; 7021489Ssklower 7121489Ssklower sns->sns_port = 0; /* yech... */ 7221489Ssklower if (ifa_ifwithaddr((struct sockaddr *)sns) == 0) 7321489Ssklower return (EADDRNOTAVAIL); 7421489Ssklower sns->sns_port = tport; 7521489Ssklower } 7621489Ssklower lport = sns->sns_port; 7721489Ssklower if (lport) { 7821489Ssklower u_short aport = ntohs(lport); 7921489Ssklower 8021489Ssklower if (aport < NSPORT_RESERVED && u.u_uid != 0) 8121489Ssklower return (EACCES); 8221489Ssklower if (ns_pcblookup(&zerons_addr, lport, 0)) 8321489Ssklower return (EADDRINUSE); 8421489Ssklower } 8521489Ssklower nsp->nsp_laddr = sns->sns_addr; 8621489Ssklower noname: 8721489Ssklower if (lport == 0) 8821489Ssklower do { 8921489Ssklower if (nspcb.nsp_lport++ < NSPORT_RESERVED) 9021489Ssklower nspcb.nsp_lport = NSPORT_RESERVED; 9121489Ssklower lport = htons(nspcb.nsp_lport); 9221489Ssklower } while (ns_pcblookup(&zerons_addr, lport, 0)); 9321489Ssklower nsp->nsp_lport = lport; 9421489Ssklower return (0); 9521489Ssklower } 9621489Ssklower 9721489Ssklower /* 9821489Ssklower * Connect from a socket to a specified address. 9921489Ssklower * Both address and port must be specified in argument sns. 10021489Ssklower * If don't have a local address for this socket yet, 10121489Ssklower * then pick one. 10221489Ssklower */ 10321489Ssklower ns_pcbconnect(nsp, nam) 10421489Ssklower struct nspcb *nsp; 10521489Ssklower struct mbuf *nam; 10621489Ssklower { 10721489Ssklower struct ns_ifaddr *ia; 10821489Ssklower register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 10925044Ssklower register struct ns_addr *dst; 11021489Ssklower 11121489Ssklower if (nam->m_len != sizeof (*sns)) 11221489Ssklower return (EINVAL); 11321489Ssklower if (sns->sns_family != AF_NS) 11421489Ssklower return (EAFNOSUPPORT); 11521489Ssklower if (sns->sns_port==0 || ns_nullhost(sns->sns_addr)) 11621489Ssklower return (EADDRNOTAVAIL); 11733040Skarels if (ns_nullhost(nsp->nsp_laddr)) { 11825044Ssklower register struct route *ro; 11925044Ssklower struct ifnet *ifp; 12033040Skarels /* 12133040Skarels * If route is known or can be allocated now, 12233040Skarels * our src addr is taken from the i/f, else punt. 12333040Skarels */ 12425044Ssklower ro = &nsp->nsp_route; 12525044Ssklower dst = &satons_addr(ro->ro_dst); 12625044Ssklower 12733040Skarels ia = (struct ns_ifaddr *)0; 12833040Skarels if (ro->ro_rt) { 12933040Skarels if ((!ns_neteq(nsp->nsp_lastdst, sns->sns_addr)) || 13033040Skarels ((ifp = ro->ro_rt->rt_ifp) && 13133040Skarels (ifp->if_flags & IFF_POINTOPOINT) && 13233040Skarels (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr))) || 13333040Skarels (nsp->nsp_socket->so_options & SO_DONTROUTE)) { 13421489Ssklower RTFREE(ro->ro_rt); 13521489Ssklower ro->ro_rt = (struct rtentry *)0; 13621489Ssklower } 13733040Skarels } 13833040Skarels if ((nsp->nsp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ 13933040Skarels (ro->ro_rt == (struct rtentry *)0 || 14033040Skarels ro->ro_rt->rt_ifp == (struct ifnet *)0)) { 14133040Skarels /* No route yet, so try to acquire one */ 14233040Skarels ro->ro_dst.sa_family = AF_NS; 14333040Skarels *dst = sns->sns_addr; 14433040Skarels dst->x_port = 0; 14533040Skarels rtalloc(ro); 14633040Skarels } 14733040Skarels /* 14833040Skarels * If we found a route, use the address 14933040Skarels * corresponding to the outgoing interface 15033040Skarels */ 15133040Skarels if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) 15233040Skarels for (ia = ns_ifaddr; ia; ia = ia->ia_next) 15333040Skarels if (ia->ia_ifp == ifp) 15433040Skarels break; 15533040Skarels if (ia == 0) { 15633040Skarels u_short fport = sns->sns_addr.x_port; 15733040Skarels sns->sns_addr.x_port = 0; 15833040Skarels ia = (struct ns_ifaddr *) 15933040Skarels ifa_ifwithdstaddr((struct sockaddr *)sns); 16033040Skarels sns->sns_addr.x_port = fport; 16121489Ssklower if (ia == 0) 16233040Skarels ia = ns_iaonnetof(&sns->sns_addr); 16333040Skarels if (ia == 0) 16421489Ssklower ia = ns_ifaddr; 16521489Ssklower if (ia == 0) 16621489Ssklower return (EADDRNOTAVAIL); 16721489Ssklower } 16825044Ssklower nsp->nsp_laddr.x_net = satons_addr(ia->ia_addr).x_net; 16925044Ssklower nsp->nsp_lastdst = sns->sns_addr; 17021489Ssklower } 17121489Ssklower if (ns_pcblookup(&sns->sns_addr, nsp->nsp_lport, 0)) 17221489Ssklower return (EADDRINUSE); 17321489Ssklower if (ns_nullhost(nsp->nsp_laddr)) { 17421489Ssklower if (nsp->nsp_lport == 0) 17524226Ssklower (void) ns_pcbbind(nsp, (struct mbuf *)0); 17621489Ssklower nsp->nsp_laddr.x_host = ns_thishost; 17721489Ssklower } 17821489Ssklower nsp->nsp_faddr = sns->sns_addr; 17921489Ssklower /* Includes nsp->nsp_fport = sns->sns_port; */ 18021489Ssklower return (0); 18121489Ssklower } 18221489Ssklower 18321489Ssklower ns_pcbdisconnect(nsp) 18421489Ssklower struct nspcb *nsp; 18521489Ssklower { 18621489Ssklower 18721489Ssklower nsp->nsp_faddr = zerons_addr; 18821489Ssklower if (nsp->nsp_socket->so_state & SS_NOFDREF) 18921489Ssklower ns_pcbdetach(nsp); 19021489Ssklower } 19121489Ssklower 19221489Ssklower ns_pcbdetach(nsp) 19321489Ssklower struct nspcb *nsp; 19421489Ssklower { 19521489Ssklower struct socket *so = nsp->nsp_socket; 19621489Ssklower 19721489Ssklower so->so_pcb = 0; 19821489Ssklower sofree(so); 19921489Ssklower if (nsp->nsp_route.ro_rt) 20021489Ssklower rtfree(nsp->nsp_route.ro_rt); 20121489Ssklower remque(nsp); 20221489Ssklower (void) m_free(dtom(nsp)); 20321489Ssklower } 20421489Ssklower 20521489Ssklower ns_setsockaddr(nsp, nam) 20621489Ssklower register struct nspcb *nsp; 20721489Ssklower struct mbuf *nam; 20821489Ssklower { 20921489Ssklower register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 21021489Ssklower 21121489Ssklower nam->m_len = sizeof (*sns); 21221489Ssklower sns = mtod(nam, struct sockaddr_ns *); 21321489Ssklower bzero((caddr_t)sns, sizeof (*sns)); 21421489Ssklower sns->sns_family = AF_NS; 21521489Ssklower sns->sns_addr = nsp->nsp_laddr; 21621489Ssklower } 21721489Ssklower 21821489Ssklower ns_setpeeraddr(nsp, nam) 21921489Ssklower register struct nspcb *nsp; 22021489Ssklower struct mbuf *nam; 22121489Ssklower { 22221489Ssklower register struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 22321489Ssklower 22421489Ssklower nam->m_len = sizeof (*sns); 22521489Ssklower sns = mtod(nam, struct sockaddr_ns *); 22621489Ssklower bzero((caddr_t)sns, sizeof (*sns)); 22721489Ssklower sns->sns_family = AF_NS; 22821489Ssklower sns->sns_addr = nsp->nsp_faddr; 22921489Ssklower } 23021489Ssklower 23121489Ssklower /* 23221489Ssklower * Pass some notification to all connections of a protocol 23321489Ssklower * associated with address dst. Call the 23421489Ssklower * protocol specific routine to handle each connection. 23521489Ssklower * Also pass an extra paramter via the nspcb. (which may in fact 23621489Ssklower * be a parameter list!) 23721489Ssklower */ 23821489Ssklower ns_pcbnotify(dst, errno, notify, param) 23921489Ssklower register struct ns_addr *dst; 24021489Ssklower long param; 24121489Ssklower int errno, (*notify)(); 24221489Ssklower { 24321489Ssklower register struct nspcb *nsp, *oinp; 24421489Ssklower int s = splimp(); 24521489Ssklower 24621489Ssklower for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb);) { 24721489Ssklower if (!ns_hosteq(*dst,nsp->nsp_faddr)) { 24821489Ssklower next: 24921489Ssklower nsp = nsp->nsp_next; 25021489Ssklower continue; 25121489Ssklower } 25221489Ssklower if (nsp->nsp_socket == 0) 25321489Ssklower goto next; 25421489Ssklower if (errno) 25521489Ssklower nsp->nsp_socket->so_error = errno; 25621489Ssklower oinp = nsp; 25721489Ssklower nsp = nsp->nsp_next; 25821489Ssklower oinp->nsp_notify_param = param; 25921489Ssklower (*notify)(oinp); 26021489Ssklower } 26121489Ssklower splx(s); 26221489Ssklower } 26321489Ssklower 26428958Skarels #ifdef notdef 26521489Ssklower /* 26621489Ssklower * After a routing change, flush old routing 26721489Ssklower * and allocate a (hopefully) better one. 26821489Ssklower */ 26921489Ssklower ns_rtchange(nsp) 27021489Ssklower struct nspcb *nsp; 27121489Ssklower { 27221489Ssklower if (nsp->nsp_route.ro_rt) { 27321489Ssklower rtfree(nsp->nsp_route.ro_rt); 27421489Ssklower nsp->nsp_route.ro_rt = 0; 27521489Ssklower /* 27621489Ssklower * A new route can be allocated the next time 27721489Ssklower * output is attempted. 27821489Ssklower */ 27921489Ssklower } 28021489Ssklower /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */ 28121489Ssklower } 28228958Skarels #endif 28321489Ssklower 28421489Ssklower struct nspcb * 28521489Ssklower ns_pcblookup(faddr, lport, wildp) 28621489Ssklower struct ns_addr *faddr; 28721489Ssklower u_short lport; 28821489Ssklower { 28921489Ssklower register struct nspcb *nsp, *match = 0; 29021489Ssklower int matchwild = 3, wildcard; 29121489Ssklower u_short fport; 29221489Ssklower 29321489Ssklower fport = faddr->x_port; 29421489Ssklower for (nsp = (&nspcb)->nsp_next; nsp != (&nspcb); nsp = nsp->nsp_next) { 29521489Ssklower if (nsp->nsp_lport != lport) 29621489Ssklower continue; 29721489Ssklower wildcard = 0; 29821489Ssklower if (ns_nullhost(nsp->nsp_faddr)) { 29921489Ssklower if (!ns_nullhost(*faddr)) 30021489Ssklower wildcard++; 30121489Ssklower } else { 30221489Ssklower if (ns_nullhost(*faddr)) 30321489Ssklower wildcard++; 30421489Ssklower else { 30521489Ssklower if (!ns_hosteq(nsp->nsp_faddr, *faddr)) 30621489Ssklower continue; 30721489Ssklower if( nsp->nsp_fport != fport) { 30821489Ssklower if(nsp->nsp_fport != 0) 30921489Ssklower continue; 31021489Ssklower else 31121489Ssklower wildcard++; 31221489Ssklower } 31321489Ssklower } 31421489Ssklower } 31521489Ssklower if (wildcard && wildp==0) 31621489Ssklower continue; 31721489Ssklower if (wildcard < matchwild) { 31821489Ssklower match = nsp; 31921489Ssklower matchwild = wildcard; 32021489Ssklower if (wildcard == 0) 32121489Ssklower break; 32221489Ssklower } 32321489Ssklower } 32421489Ssklower return (match); 32521489Ssklower } 326