ipx_pcb.c revision 25345
111819Sjulian/*
211819Sjulian * Copyright (c) 1995, Mike Mitchell
311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
411819Sjulian *	The Regents of the University of California.  All rights reserved.
511819Sjulian *
611819Sjulian * Redistribution and use in source and binary forms, with or without
711819Sjulian * modification, are permitted provided that the following conditions
811819Sjulian * are met:
911819Sjulian * 1. Redistributions of source code must retain the above copyright
1011819Sjulian *    notice, this list of conditions and the following disclaimer.
1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211819Sjulian *    notice, this list of conditions and the following disclaimer in the
1311819Sjulian *    documentation and/or other materials provided with the distribution.
1411819Sjulian * 3. All advertising materials mentioning features or use of this software
1511819Sjulian *    must display the following acknowledgement:
1611819Sjulian *	This product includes software developed by the University of
1711819Sjulian *	California, Berkeley and its contributors.
1811819Sjulian * 4. Neither the name of the University nor the names of its contributors
1911819Sjulian *    may be used to endorse or promote products derived from this software
2011819Sjulian *    without specific prior written permission.
2111819Sjulian *
2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2511819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3211819Sjulian * SUCH DAMAGE.
3311819Sjulian *
3412057Sjulian *	@(#)ipx_pcb.c
3512057Sjulian *
3625345Sjhay * $Id: ipx_pcb.c,v 1.7 1997/02/22 09:41:56 peter Exp $
3711819Sjulian */
3811819Sjulian
3911819Sjulian#include <sys/param.h>
4014546Sdg#include <sys/queue.h>
4111819Sjulian#include <sys/systm.h>
4211819Sjulian#include <sys/mbuf.h>
4325345Sjhay#include <sys/proc.h>
4425345Sjhay#include <sys/protosw.h>
4511819Sjulian#include <sys/errno.h>
4611819Sjulian#include <sys/socket.h>
4711819Sjulian#include <sys/socketvar.h>
4811819Sjulian
4911819Sjulian#include <net/if.h>
5011819Sjulian#include <net/route.h>
5111819Sjulian
5211819Sjulian#include <netipx/ipx.h>
5311819Sjulian#include <netipx/ipx_if.h>
5411819Sjulian#include <netipx/ipx_pcb.h>
5511819Sjulian
5611819Sjulianstruct	ipx_addr zeroipx_addr;
5711819Sjulian
5811819Sjulianint
5925345Sjhayipx_pcballoc(so, head, p)
6011819Sjulian	struct socket *so;
6111819Sjulian	struct ipxpcb *head;
6225345Sjhay	struct proc *p;
6311819Sjulian{
6411819Sjulian	struct mbuf *m;
6511819Sjulian	register struct ipxpcb *ipxp;
6611819Sjulian
6711819Sjulian	m = m_getclr(M_DONTWAIT, MT_PCB);
6811819Sjulian	if (m == NULL)
6911819Sjulian		return (ENOBUFS);
7011819Sjulian	ipxp = mtod(m, struct ipxpcb *);
7111819Sjulian	ipxp->ipxp_socket = so;
7211819Sjulian	insque(ipxp, head);
7311819Sjulian	so->so_pcb = (caddr_t)ipxp;
7411819Sjulian	return (0);
7511819Sjulian}
7611819Sjulian
7711819Sjulianint
7825345Sjhayipx_pcbbind(ipxp, nam, p)
7911819Sjulian	register struct ipxpcb *ipxp;
8011819Sjulian	struct mbuf *nam;
8125345Sjhay	struct proc *p;
8211819Sjulian{
8311819Sjulian	register struct sockaddr_ipx *sipx;
8411819Sjulian	u_short lport = 0;
8511819Sjulian
8611819Sjulian	if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr))
8711819Sjulian		return (EINVAL);
8811819Sjulian	if (nam == 0)
8911819Sjulian		goto noname;
9011819Sjulian	sipx = mtod(nam, struct sockaddr_ipx *);
9111819Sjulian	if (nam->m_len != sizeof (*sipx))
9211819Sjulian		return (EINVAL);
9311819Sjulian	if (!ipx_nullhost(sipx->sipx_addr)) {
9411819Sjulian		int tport = sipx->sipx_port;
9511819Sjulian
9611819Sjulian		sipx->sipx_port = 0;		/* yech... */
9711819Sjulian		if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0)
9811819Sjulian			return (EADDRNOTAVAIL);
9911819Sjulian		sipx->sipx_port = tport;
10011819Sjulian	}
10111819Sjulian	lport = sipx->sipx_port;
10211819Sjulian	if (lport) {
10311819Sjulian		u_short aport = ntohs(lport);
10425345Sjhay		int error;
10511819Sjulian
10611819Sjulian		if (aport < IPXPORT_MAX &&
10725345Sjhay		    p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
10825345Sjhay			return (error);
10911819Sjulian		if (ipx_pcblookup(&zeroipx_addr, lport, 0))
11011819Sjulian			return (EADDRINUSE);
11111819Sjulian	}
11211819Sjulian	ipxp->ipxp_laddr = sipx->sipx_addr;
11311819Sjuliannoname:
11411819Sjulian	if (lport == 0)
11511819Sjulian		do {
11611819Sjulian			if (ipxpcb.ipxp_lport++ < IPXPORT_MAX)
11711819Sjulian				ipxpcb.ipxp_lport = IPXPORT_MAX;
11811819Sjulian			lport = htons(ipxpcb.ipxp_lport);
11911819Sjulian		} while (ipx_pcblookup(&zeroipx_addr, lport, 0));
12011819Sjulian	ipxp->ipxp_lport = lport;
12111819Sjulian	return (0);
12211819Sjulian}
12311819Sjulian
12411819Sjulian/*
12511819Sjulian * Connect from a socket to a specified address.
12611819Sjulian * Both address and port must be specified in argument sipx.
12711819Sjulian * If don't have a local address for this socket yet,
12811819Sjulian * then pick one.
12911819Sjulian */
13011819Sjulianint
13125345Sjhayipx_pcbconnect(ipxp, nam, p)
13211819Sjulian	struct ipxpcb *ipxp;
13311819Sjulian	struct mbuf *nam;
13425345Sjhay	struct proc *p;
13511819Sjulian{
13611819Sjulian	struct ipx_ifaddr *ia;
13711819Sjulian	register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
13811819Sjulian	register struct ipx_addr *dst;
13911819Sjulian	register struct route *ro;
14011819Sjulian	struct ifnet *ifp;
14111819Sjulian
14211819Sjulian	if (nam->m_len != sizeof (*sipx))
14311819Sjulian		return (EINVAL);
14411819Sjulian	if (sipx->sipx_family != AF_IPX)
14511819Sjulian		return (EAFNOSUPPORT);
14611819Sjulian	if (sipx->sipx_port==0 || ipx_nullhost(sipx->sipx_addr))
14711819Sjulian		return (EADDRNOTAVAIL);
14811819Sjulian	/*
14911819Sjulian	 * If we haven't bound which network number to use as ours,
15011819Sjulian	 * we will use the number of the outgoing interface.
15111819Sjulian	 * This depends on having done a routing lookup, which
15211819Sjulian	 * we will probably have to do anyway, so we might
15311819Sjulian	 * as well do it now.  On the other hand if we are
15411819Sjulian	 * sending to multiple destinations we may have already
15511819Sjulian	 * done the lookup, so see if we can use the route
15611819Sjulian	 * from before.  In any case, we only
15711819Sjulian	 * chose a port number once, even if sending to multiple
15811819Sjulian	 * destinations.
15911819Sjulian	 */
16011819Sjulian	ro = &ipxp->ipxp_route;
16111819Sjulian	dst = &satoipx_addr(ro->ro_dst);
16211819Sjulian	if (ipxp->ipxp_socket->so_options & SO_DONTROUTE)
16311819Sjulian		goto flush;
16411819Sjulian	if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr))
16511819Sjulian		goto flush;
16611819Sjulian	if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) {
16711819Sjulian		if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) {
16811819Sjulian			/* can patch route to avoid rtalloc */
16911819Sjulian			*dst = sipx->sipx_addr;
17011819Sjulian		} else {
17111819Sjulian	flush:
17211819Sjulian			if (ro->ro_rt)
17311819Sjulian				RTFREE(ro->ro_rt);
17411819Sjulian			ro->ro_rt = (struct rtentry *)0;
17511819Sjulian			ipxp->ipxp_laddr.x_net = ipx_zeronet;
17611819Sjulian		}
17711819Sjulian	}/* else cached route is ok; do nothing */
17811819Sjulian	ipxp->ipxp_lastdst = sipx->sipx_addr;
17911819Sjulian	if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
18011819Sjulian	    (ro->ro_rt == (struct rtentry *)0 ||
18111819Sjulian	     ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
18211819Sjulian		    /* No route yet, so try to acquire one */
18311819Sjulian		    ro->ro_dst.sa_family = AF_IPX;
18411819Sjulian		    ro->ro_dst.sa_len = sizeof(ro->ro_dst);
18511819Sjulian		    *dst = sipx->sipx_addr;
18611819Sjulian		    dst->x_port = 0;
18711819Sjulian		    rtalloc(ro);
18811819Sjulian	}
18911819Sjulian	if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
19011819Sjulian		/*
19111819Sjulian		 * If route is known or can be allocated now,
19211819Sjulian		 * our src addr is taken from the i/f, else punt.
19311819Sjulian		 */
19411819Sjulian
19511819Sjulian		ia = (struct ipx_ifaddr *)0;
19611819Sjulian		/*
19711819Sjulian		 * If we found a route, use the address
19811819Sjulian		 * corresponding to the outgoing interface
19911819Sjulian		 */
20011819Sjulian		if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp))
20111819Sjulian			for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
20211819Sjulian				if (ia->ia_ifp == ifp)
20311819Sjulian					break;
20411819Sjulian		if (ia == 0) {
20511819Sjulian			u_short fport = sipx->sipx_addr.x_port;
20611819Sjulian			sipx->sipx_addr.x_port = 0;
20711819Sjulian			ia = (struct ipx_ifaddr *)
20811819Sjulian				ifa_ifwithdstaddr((struct sockaddr *)sipx);
20911819Sjulian			sipx->sipx_addr.x_port = fport;
21011819Sjulian			if (ia == 0)
21111819Sjulian				ia = ipx_iaonnetof(&sipx->sipx_addr);
21211819Sjulian			if (ia == 0)
21311819Sjulian				ia = ipx_ifaddr;
21411819Sjulian			if (ia == 0)
21511819Sjulian				return (EADDRNOTAVAIL);
21611819Sjulian		}
21711819Sjulian		ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
21811819Sjulian	}
21911819Sjulian	if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
22011819Sjulian		return (EADDRINUSE);
22111819Sjulian	if (ipx_nullhost(ipxp->ipxp_laddr)) {
22211819Sjulian		if (ipxp->ipxp_lport == 0)
22325345Sjhay			(void) ipx_pcbbind(ipxp, (struct mbuf *)0, p);
22411819Sjulian		ipxp->ipxp_laddr.x_host = ipx_thishost;
22511819Sjulian	}
22611819Sjulian	ipxp->ipxp_faddr = sipx->sipx_addr;
22711819Sjulian	/* Includes ipxp->ipxp_fport = sipx->sipx_port; */
22811819Sjulian	return (0);
22911819Sjulian}
23011819Sjulian
23111819Sjulianvoid
23211819Sjulianipx_pcbdisconnect(ipxp)
23311819Sjulian	struct ipxpcb *ipxp;
23411819Sjulian{
23511819Sjulian
23611819Sjulian	ipxp->ipxp_faddr = zeroipx_addr;
23711819Sjulian	if (ipxp->ipxp_socket->so_state & SS_NOFDREF)
23811819Sjulian		ipx_pcbdetach(ipxp);
23911819Sjulian}
24011819Sjulian
24111819Sjulianvoid
24211819Sjulianipx_pcbdetach(ipxp)
24311819Sjulian	struct ipxpcb *ipxp;
24411819Sjulian{
24511819Sjulian	struct socket *so = ipxp->ipxp_socket;
24611819Sjulian
24711819Sjulian	so->so_pcb = 0;
24811819Sjulian	sofree(so);
24911819Sjulian	if (ipxp->ipxp_route.ro_rt)
25011819Sjulian		rtfree(ipxp->ipxp_route.ro_rt);
25111819Sjulian	remque(ipxp);
25211819Sjulian	(void) m_free(dtom(ipxp));
25311819Sjulian}
25411819Sjulian
25511819Sjulianvoid
25611819Sjulianipx_setsockaddr(ipxp, nam)
25711819Sjulian	register struct ipxpcb *ipxp;
25811819Sjulian	struct mbuf *nam;
25911819Sjulian{
26011819Sjulian	register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
26111819Sjulian
26211819Sjulian	nam->m_len = sizeof (*sipx);
26311819Sjulian	sipx = mtod(nam, struct sockaddr_ipx *);
26411819Sjulian	bzero((caddr_t)sipx, sizeof (*sipx));
26511819Sjulian	sipx->sipx_len = sizeof(*sipx);
26611819Sjulian	sipx->sipx_family = AF_IPX;
26711819Sjulian	sipx->sipx_addr = ipxp->ipxp_laddr;
26811819Sjulian}
26911819Sjulian
27011819Sjulianvoid
27111819Sjulianipx_setpeeraddr(ipxp, nam)
27211819Sjulian	register struct ipxpcb *ipxp;
27311819Sjulian	struct mbuf *nam;
27411819Sjulian{
27511819Sjulian	register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
27611819Sjulian
27711819Sjulian	nam->m_len = sizeof (*sipx);
27811819Sjulian	sipx = mtod(nam, struct sockaddr_ipx *);
27911819Sjulian	bzero((caddr_t)sipx, sizeof (*sipx));
28011819Sjulian	sipx->sipx_len = sizeof(*sipx);
28111819Sjulian	sipx->sipx_family = AF_IPX;
28211819Sjulian	sipx->sipx_addr = ipxp->ipxp_faddr;
28311819Sjulian}
28411819Sjulian
28511819Sjulian/*
28611819Sjulian * Pass some notification to all connections of a protocol
28711819Sjulian * associated with address dst.  Call the
28811819Sjulian * protocol specific routine to handle each connection.
28911819Sjulian * Also pass an extra paramter via the ipxpcb. (which may in fact
29011819Sjulian * be a parameter list!)
29111819Sjulian */
29211819Sjulianvoid
29311819Sjulianipx_pcbnotify(dst, errno, notify, param)
29411819Sjulian	register struct ipx_addr *dst;
29511991Sjulian	int errno;
29611991Sjulian	void (*notify)(struct ipxpcb *);
29711819Sjulian	long param;
29811819Sjulian{
29911819Sjulian	register struct ipxpcb *ipxp, *oinp;
30011819Sjulian	int s = splimp();
30111819Sjulian
30211819Sjulian	for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) {
30311819Sjulian		if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) {
30411819Sjulian	next:
30511819Sjulian			ipxp = ipxp->ipxp_next;
30611819Sjulian			continue;
30711819Sjulian		}
30811819Sjulian		if (ipxp->ipxp_socket == 0)
30911819Sjulian			goto next;
31011819Sjulian		if (errno)
31111819Sjulian			ipxp->ipxp_socket->so_error = errno;
31211819Sjulian		oinp = ipxp;
31311819Sjulian		ipxp = ipxp->ipxp_next;
31411819Sjulian		oinp->ipxp_notify_param = param;
31511819Sjulian		(*notify)(oinp);
31611819Sjulian	}
31711819Sjulian	splx(s);
31811819Sjulian}
31911819Sjulian
32011819Sjulian#ifdef notdef
32111819Sjulian/*
32211819Sjulian * After a routing change, flush old routing
32311819Sjulian * and allocate a (hopefully) better one.
32411819Sjulian */
32511819Sjulianipx_rtchange(ipxp)
32611819Sjulian	struct ipxpcb *ipxp;
32711819Sjulian{
32811819Sjulian	if (ipxp->ipxp_route.ro_rt) {
32911819Sjulian		rtfree(ipxp->ipxp_route.ro_rt);
33011819Sjulian		ipxp->ipxp_route.ro_rt = 0;
33111819Sjulian		/*
33211819Sjulian		 * A new route can be allocated the next time
33311819Sjulian		 * output is attempted.
33411819Sjulian		 */
33511819Sjulian	}
33611819Sjulian	/* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
33711819Sjulian}
33811819Sjulian#endif
33911819Sjulian
34011819Sjulianstruct ipxpcb *
34111819Sjulianipx_pcblookup(faddr, lport, wildp)
34211819Sjulian	struct ipx_addr *faddr;
34311819Sjulian	u_short lport;
34411819Sjulian	int wildp;
34511819Sjulian{
34611819Sjulian	register struct ipxpcb *ipxp, *match = 0;
34711819Sjulian	int matchwild = 3, wildcard;
34811819Sjulian	u_short fport;
34911819Sjulian
35011819Sjulian	fport = faddr->x_port;
35111819Sjulian	for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) {
35211819Sjulian		if (ipxp->ipxp_lport != lport)
35311819Sjulian			continue;
35411819Sjulian		wildcard = 0;
35511819Sjulian		if (ipx_nullhost(ipxp->ipxp_faddr)) {
35611819Sjulian			if (!ipx_nullhost(*faddr))
35711819Sjulian				wildcard++;
35811819Sjulian		} else {
35911819Sjulian			if (ipx_nullhost(*faddr))
36011819Sjulian				wildcard++;
36111819Sjulian			else {
36211819Sjulian				if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
36311819Sjulian					continue;
36411819Sjulian				if (ipxp->ipxp_fport != fport) {
36511819Sjulian					if (ipxp->ipxp_fport != 0)
36611819Sjulian						continue;
36711819Sjulian					else
36811819Sjulian						wildcard++;
36911819Sjulian				}
37011819Sjulian			}
37111819Sjulian		}
37211819Sjulian		if (wildcard && wildp==0)
37311819Sjulian			continue;
37411819Sjulian		if (wildcard < matchwild) {
37511819Sjulian			match = ipxp;
37611819Sjulian			matchwild = wildcard;
37711819Sjulian			if (wildcard == 0)
37811819Sjulian				break;
37911819Sjulian		}
38011819Sjulian	}
38111819Sjulian	return (match);
38211819Sjulian}
383