ipx_pcb.c revision 11991
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 *
3411991Sjulian *	@(#)$Id$
3511819Sjulian */
3611819Sjulian
3711819Sjulian#include <sys/param.h>
3811819Sjulian#include <sys/systm.h>
3911819Sjulian#include <sys/mbuf.h>
4011819Sjulian#include <sys/errno.h>
4111819Sjulian#include <sys/socket.h>
4211819Sjulian#include <sys/socketvar.h>
4311819Sjulian#include <sys/protosw.h>
4411819Sjulian
4511819Sjulian#include <net/if.h>
4611819Sjulian#include <net/route.h>
4711819Sjulian
4811819Sjulian#include <netipx/ipx.h>
4911819Sjulian#include <netipx/ipx_if.h>
5011819Sjulian#include <netipx/ipx_pcb.h>
5111819Sjulian
5211819Sjulianstruct	ipx_addr zeroipx_addr;
5311819Sjulian
5411819Sjulianint
5511819Sjulianipx_pcballoc(so, head)
5611819Sjulian	struct socket *so;
5711819Sjulian	struct ipxpcb *head;
5811819Sjulian{
5911819Sjulian	struct mbuf *m;
6011819Sjulian	register struct ipxpcb *ipxp;
6111819Sjulian
6211819Sjulian	m = m_getclr(M_DONTWAIT, MT_PCB);
6311819Sjulian	if (m == NULL)
6411819Sjulian		return (ENOBUFS);
6511819Sjulian	ipxp = mtod(m, struct ipxpcb *);
6611819Sjulian	ipxp->ipxp_socket = so;
6711819Sjulian	insque(ipxp, head);
6811819Sjulian	so->so_pcb = (caddr_t)ipxp;
6911819Sjulian	return (0);
7011819Sjulian}
7111819Sjulian
7211819Sjulianint
7311819Sjulianipx_pcbbind(ipxp, nam)
7411819Sjulian	register struct ipxpcb *ipxp;
7511819Sjulian	struct mbuf *nam;
7611819Sjulian{
7711819Sjulian	register struct sockaddr_ipx *sipx;
7811819Sjulian	u_short lport = 0;
7911819Sjulian
8011819Sjulian	if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr))
8111819Sjulian		return (EINVAL);
8211819Sjulian	if (nam == 0)
8311819Sjulian		goto noname;
8411819Sjulian	sipx = mtod(nam, struct sockaddr_ipx *);
8511819Sjulian	if (nam->m_len != sizeof (*sipx))
8611819Sjulian		return (EINVAL);
8711819Sjulian	if (!ipx_nullhost(sipx->sipx_addr)) {
8811819Sjulian		int tport = sipx->sipx_port;
8911819Sjulian
9011819Sjulian		sipx->sipx_port = 0;		/* yech... */
9111819Sjulian		if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0)
9211819Sjulian			return (EADDRNOTAVAIL);
9311819Sjulian		sipx->sipx_port = tport;
9411819Sjulian	}
9511819Sjulian	lport = sipx->sipx_port;
9611819Sjulian	if (lport) {
9711819Sjulian		u_short aport = ntohs(lport);
9811819Sjulian
9911819Sjulian		if (aport < IPXPORT_MAX &&
10011819Sjulian		    (ipxp->ipxp_socket->so_state & SS_PRIV) == 0)
10111819Sjulian			return (EACCES);
10211819Sjulian		if (ipx_pcblookup(&zeroipx_addr, lport, 0))
10311819Sjulian			return (EADDRINUSE);
10411819Sjulian	}
10511819Sjulian	ipxp->ipxp_laddr = sipx->sipx_addr;
10611819Sjuliannoname:
10711819Sjulian	if (lport == 0)
10811819Sjulian		do {
10911819Sjulian			if (ipxpcb.ipxp_lport++ < IPXPORT_MAX)
11011819Sjulian				ipxpcb.ipxp_lport = IPXPORT_MAX;
11111819Sjulian			lport = htons(ipxpcb.ipxp_lport);
11211819Sjulian		} while (ipx_pcblookup(&zeroipx_addr, lport, 0));
11311819Sjulian	ipxp->ipxp_lport = lport;
11411819Sjulian	return (0);
11511819Sjulian}
11611819Sjulian
11711819Sjulian/*
11811819Sjulian * Connect from a socket to a specified address.
11911819Sjulian * Both address and port must be specified in argument sipx.
12011819Sjulian * If don't have a local address for this socket yet,
12111819Sjulian * then pick one.
12211819Sjulian */
12311819Sjulianint
12411819Sjulianipx_pcbconnect(ipxp, nam)
12511819Sjulian	struct ipxpcb *ipxp;
12611819Sjulian	struct mbuf *nam;
12711819Sjulian{
12811819Sjulian	struct ipx_ifaddr *ia;
12911819Sjulian	register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
13011819Sjulian	register struct ipx_addr *dst;
13111819Sjulian	register struct route *ro;
13211819Sjulian	struct ifnet *ifp;
13311819Sjulian
13411819Sjulian	if (nam->m_len != sizeof (*sipx))
13511819Sjulian		return (EINVAL);
13611819Sjulian	if (sipx->sipx_family != AF_IPX)
13711819Sjulian		return (EAFNOSUPPORT);
13811819Sjulian	if (sipx->sipx_port==0 || ipx_nullhost(sipx->sipx_addr))
13911819Sjulian		return (EADDRNOTAVAIL);
14011819Sjulian	/*
14111819Sjulian	 * If we haven't bound which network number to use as ours,
14211819Sjulian	 * we will use the number of the outgoing interface.
14311819Sjulian	 * This depends on having done a routing lookup, which
14411819Sjulian	 * we will probably have to do anyway, so we might
14511819Sjulian	 * as well do it now.  On the other hand if we are
14611819Sjulian	 * sending to multiple destinations we may have already
14711819Sjulian	 * done the lookup, so see if we can use the route
14811819Sjulian	 * from before.  In any case, we only
14911819Sjulian	 * chose a port number once, even if sending to multiple
15011819Sjulian	 * destinations.
15111819Sjulian	 */
15211819Sjulian	ro = &ipxp->ipxp_route;
15311819Sjulian	dst = &satoipx_addr(ro->ro_dst);
15411819Sjulian	if (ipxp->ipxp_socket->so_options & SO_DONTROUTE)
15511819Sjulian		goto flush;
15611819Sjulian	if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr))
15711819Sjulian		goto flush;
15811819Sjulian	if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) {
15911819Sjulian		if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) {
16011819Sjulian			/* can patch route to avoid rtalloc */
16111819Sjulian			*dst = sipx->sipx_addr;
16211819Sjulian		} else {
16311819Sjulian	flush:
16411819Sjulian			if (ro->ro_rt)
16511819Sjulian				RTFREE(ro->ro_rt);
16611819Sjulian			ro->ro_rt = (struct rtentry *)0;
16711819Sjulian			ipxp->ipxp_laddr.x_net = ipx_zeronet;
16811819Sjulian		}
16911819Sjulian	}/* else cached route is ok; do nothing */
17011819Sjulian	ipxp->ipxp_lastdst = sipx->sipx_addr;
17111819Sjulian	if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
17211819Sjulian	    (ro->ro_rt == (struct rtentry *)0 ||
17311819Sjulian	     ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
17411819Sjulian		    /* No route yet, so try to acquire one */
17511819Sjulian		    ro->ro_dst.sa_family = AF_IPX;
17611819Sjulian		    ro->ro_dst.sa_len = sizeof(ro->ro_dst);
17711819Sjulian		    *dst = sipx->sipx_addr;
17811819Sjulian		    dst->x_port = 0;
17911819Sjulian		    rtalloc(ro);
18011819Sjulian	}
18111819Sjulian	if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
18211819Sjulian		/*
18311819Sjulian		 * If route is known or can be allocated now,
18411819Sjulian		 * our src addr is taken from the i/f, else punt.
18511819Sjulian		 */
18611819Sjulian
18711819Sjulian		ia = (struct ipx_ifaddr *)0;
18811819Sjulian		/*
18911819Sjulian		 * If we found a route, use the address
19011819Sjulian		 * corresponding to the outgoing interface
19111819Sjulian		 */
19211819Sjulian		if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp))
19311819Sjulian			for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
19411819Sjulian				if (ia->ia_ifp == ifp)
19511819Sjulian					break;
19611819Sjulian		if (ia == 0) {
19711819Sjulian			u_short fport = sipx->sipx_addr.x_port;
19811819Sjulian			sipx->sipx_addr.x_port = 0;
19911819Sjulian			ia = (struct ipx_ifaddr *)
20011819Sjulian				ifa_ifwithdstaddr((struct sockaddr *)sipx);
20111819Sjulian			sipx->sipx_addr.x_port = fport;
20211819Sjulian			if (ia == 0)
20311819Sjulian				ia = ipx_iaonnetof(&sipx->sipx_addr);
20411819Sjulian			if (ia == 0)
20511819Sjulian				ia = ipx_ifaddr;
20611819Sjulian			if (ia == 0)
20711819Sjulian				return (EADDRNOTAVAIL);
20811819Sjulian		}
20911819Sjulian		ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
21011819Sjulian	}
21111819Sjulian	if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
21211819Sjulian		return (EADDRINUSE);
21311819Sjulian	if (ipx_nullhost(ipxp->ipxp_laddr)) {
21411819Sjulian		if (ipxp->ipxp_lport == 0)
21511819Sjulian			(void) ipx_pcbbind(ipxp, (struct mbuf *)0);
21611819Sjulian		ipxp->ipxp_laddr.x_host = ipx_thishost;
21711819Sjulian	}
21811819Sjulian	ipxp->ipxp_faddr = sipx->sipx_addr;
21911819Sjulian	/* Includes ipxp->ipxp_fport = sipx->sipx_port; */
22011819Sjulian	return (0);
22111819Sjulian}
22211819Sjulian
22311819Sjulianvoid
22411819Sjulianipx_pcbdisconnect(ipxp)
22511819Sjulian	struct ipxpcb *ipxp;
22611819Sjulian{
22711819Sjulian
22811819Sjulian	ipxp->ipxp_faddr = zeroipx_addr;
22911819Sjulian	if (ipxp->ipxp_socket->so_state & SS_NOFDREF)
23011819Sjulian		ipx_pcbdetach(ipxp);
23111819Sjulian}
23211819Sjulian
23311819Sjulianvoid
23411819Sjulianipx_pcbdetach(ipxp)
23511819Sjulian	struct ipxpcb *ipxp;
23611819Sjulian{
23711819Sjulian	struct socket *so = ipxp->ipxp_socket;
23811819Sjulian
23911819Sjulian	so->so_pcb = 0;
24011819Sjulian	sofree(so);
24111819Sjulian	if (ipxp->ipxp_route.ro_rt)
24211819Sjulian		rtfree(ipxp->ipxp_route.ro_rt);
24311819Sjulian	remque(ipxp);
24411819Sjulian	(void) m_free(dtom(ipxp));
24511819Sjulian}
24611819Sjulian
24711819Sjulianvoid
24811819Sjulianipx_setsockaddr(ipxp, nam)
24911819Sjulian	register struct ipxpcb *ipxp;
25011819Sjulian	struct mbuf *nam;
25111819Sjulian{
25211819Sjulian	register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
25311819Sjulian
25411819Sjulian	nam->m_len = sizeof (*sipx);
25511819Sjulian	sipx = mtod(nam, struct sockaddr_ipx *);
25611819Sjulian	bzero((caddr_t)sipx, sizeof (*sipx));
25711819Sjulian	sipx->sipx_len = sizeof(*sipx);
25811819Sjulian	sipx->sipx_family = AF_IPX;
25911819Sjulian	sipx->sipx_addr = ipxp->ipxp_laddr;
26011819Sjulian}
26111819Sjulian
26211819Sjulianvoid
26311819Sjulianipx_setpeeraddr(ipxp, nam)
26411819Sjulian	register struct ipxpcb *ipxp;
26511819Sjulian	struct mbuf *nam;
26611819Sjulian{
26711819Sjulian	register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
26811819Sjulian
26911819Sjulian	nam->m_len = sizeof (*sipx);
27011819Sjulian	sipx = mtod(nam, struct sockaddr_ipx *);
27111819Sjulian	bzero((caddr_t)sipx, sizeof (*sipx));
27211819Sjulian	sipx->sipx_len = sizeof(*sipx);
27311819Sjulian	sipx->sipx_family = AF_IPX;
27411819Sjulian	sipx->sipx_addr = ipxp->ipxp_faddr;
27511819Sjulian}
27611819Sjulian
27711819Sjulian/*
27811819Sjulian * Pass some notification to all connections of a protocol
27911819Sjulian * associated with address dst.  Call the
28011819Sjulian * protocol specific routine to handle each connection.
28111819Sjulian * Also pass an extra paramter via the ipxpcb. (which may in fact
28211819Sjulian * be a parameter list!)
28311819Sjulian */
28411819Sjulianvoid
28511819Sjulianipx_pcbnotify(dst, errno, notify, param)
28611819Sjulian	register struct ipx_addr *dst;
28711991Sjulian	int errno;
28811991Sjulian	void (*notify)(struct ipxpcb *);
28911819Sjulian	long param;
29011819Sjulian{
29111819Sjulian	register struct ipxpcb *ipxp, *oinp;
29211819Sjulian	int s = splimp();
29311819Sjulian
29411819Sjulian	for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) {
29511819Sjulian		if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) {
29611819Sjulian	next:
29711819Sjulian			ipxp = ipxp->ipxp_next;
29811819Sjulian			continue;
29911819Sjulian		}
30011819Sjulian		if (ipxp->ipxp_socket == 0)
30111819Sjulian			goto next;
30211819Sjulian		if (errno)
30311819Sjulian			ipxp->ipxp_socket->so_error = errno;
30411819Sjulian		oinp = ipxp;
30511819Sjulian		ipxp = ipxp->ipxp_next;
30611819Sjulian		oinp->ipxp_notify_param = param;
30711819Sjulian		(*notify)(oinp);
30811819Sjulian	}
30911819Sjulian	splx(s);
31011819Sjulian}
31111819Sjulian
31211819Sjulian#ifdef notdef
31311819Sjulian/*
31411819Sjulian * After a routing change, flush old routing
31511819Sjulian * and allocate a (hopefully) better one.
31611819Sjulian */
31711819Sjulianipx_rtchange(ipxp)
31811819Sjulian	struct ipxpcb *ipxp;
31911819Sjulian{
32011819Sjulian	if (ipxp->ipxp_route.ro_rt) {
32111819Sjulian		rtfree(ipxp->ipxp_route.ro_rt);
32211819Sjulian		ipxp->ipxp_route.ro_rt = 0;
32311819Sjulian		/*
32411819Sjulian		 * A new route can be allocated the next time
32511819Sjulian		 * output is attempted.
32611819Sjulian		 */
32711819Sjulian	}
32811819Sjulian	/* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
32911819Sjulian}
33011819Sjulian#endif
33111819Sjulian
33211819Sjulianstruct ipxpcb *
33311819Sjulianipx_pcblookup(faddr, lport, wildp)
33411819Sjulian	struct ipx_addr *faddr;
33511819Sjulian	u_short lport;
33611819Sjulian	int wildp;
33711819Sjulian{
33811819Sjulian	register struct ipxpcb *ipxp, *match = 0;
33911819Sjulian	int matchwild = 3, wildcard;
34011819Sjulian	u_short fport;
34111819Sjulian
34211819Sjulian	fport = faddr->x_port;
34311819Sjulian	for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) {
34411819Sjulian		if (ipxp->ipxp_lport != lport)
34511819Sjulian			continue;
34611819Sjulian		wildcard = 0;
34711819Sjulian		if (ipx_nullhost(ipxp->ipxp_faddr)) {
34811819Sjulian			if (!ipx_nullhost(*faddr))
34911819Sjulian				wildcard++;
35011819Sjulian		} else {
35111819Sjulian			if (ipx_nullhost(*faddr))
35211819Sjulian				wildcard++;
35311819Sjulian			else {
35411819Sjulian				if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
35511819Sjulian					continue;
35611819Sjulian				if (ipxp->ipxp_fport != fport) {
35711819Sjulian					if (ipxp->ipxp_fport != 0)
35811819Sjulian						continue;
35911819Sjulian					else
36011819Sjulian						wildcard++;
36111819Sjulian				}
36211819Sjulian			}
36311819Sjulian		}
36411819Sjulian		if (wildcard && wildp==0)
36511819Sjulian			continue;
36611819Sjulian		if (wildcard < matchwild) {
36711819Sjulian			match = ipxp;
36811819Sjulian			matchwild = wildcard;
36911819Sjulian			if (wildcard == 0)
37011819Sjulian				break;
37111819Sjulian		}
37211819Sjulian	}
37311819Sjulian	return (match);
37411819Sjulian}
375