ipx_pcb.c revision 139823
1139823Simp/*-
2139485Srwatson * Copyright (c) 2004 Robert N. M. Watson
311819Sjulian * Copyright (c) 1995, Mike Mitchell
411819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
511819Sjulian *	The Regents of the University of California.  All rights reserved.
611819Sjulian *
711819Sjulian * Redistribution and use in source and binary forms, with or without
811819Sjulian * modification, are permitted provided that the following conditions
911819Sjulian * are met:
1011819Sjulian * 1. Redistributions of source code must retain the above copyright
1111819Sjulian *    notice, this list of conditions and the following disclaimer.
1211819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1311819Sjulian *    notice, this list of conditions and the following disclaimer in the
1411819Sjulian *    documentation and/or other materials provided with the distribution.
1511819Sjulian * 3. All advertising materials mentioning features or use of this software
1611819Sjulian *    must display the following acknowledgement:
1711819Sjulian *	This product includes software developed by the University of
1811819Sjulian *	California, Berkeley and its contributors.
1911819Sjulian * 4. Neither the name of the University nor the names of its contributors
2011819Sjulian *    may be used to endorse or promote products derived from this software
2111819Sjulian *    without specific prior written permission.
2211819Sjulian *
2311819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2411819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2511819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2611819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2711819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2811819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2911819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3011819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3111819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3211819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3311819Sjulian * SUCH DAMAGE.
3411819Sjulian *
3512057Sjulian *	@(#)ipx_pcb.c
3611819Sjulian */
3711819Sjulian
38116189Sobrien#include <sys/cdefs.h>
39116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_pcb.c 139823 2005-01-07 01:45:51Z imp $");
40116189Sobrien
4111819Sjulian#include <sys/param.h>
4211819Sjulian#include <sys/systm.h>
4329024Sbde#include <sys/malloc.h>
4411819Sjulian#include <sys/socket.h>
4511819Sjulian#include <sys/socketvar.h>
4611819Sjulian
4711819Sjulian#include <net/if.h>
4811819Sjulian#include <net/route.h>
4911819Sjulian
5011819Sjulian#include <netipx/ipx.h>
5111819Sjulian#include <netipx/ipx_if.h>
5211819Sjulian#include <netipx/ipx_pcb.h>
5325652Sjhay#include <netipx/ipx_var.h>
5411819Sjulian
5533181Seivindstatic struct	ipx_addr zeroipx_addr;
56139584Srwatsonstatic u_short	ipxpcb_lport_cache;
5711819Sjulian
5811819Sjulianint
5983366Sjulianipx_pcballoc(so, head, td)
6011819Sjulian	struct socket *so;
61139444Srwatson	struct ipxpcbhead *head;
6283366Sjulian	struct thread *td;
6311819Sjulian{
6411819Sjulian	register struct ipxpcb *ipxp;
6511819Sjulian
6669781Sdwmalone	MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO);
6728270Swollman	if (ipxp == NULL)
6811819Sjulian		return (ENOBUFS);
6911819Sjulian	ipxp->ipxp_socket = so;
7050519Sjhay	if (ipxcksum)
7150519Sjhay		ipxp->ipxp_flags |= IPXP_CHECKSUM;
72139444Srwatson	LIST_INSERT_HEAD(head, ipxp, ipxp_list);
7311819Sjulian	so->so_pcb = (caddr_t)ipxp;
7411819Sjulian	return (0);
7511819Sjulian}
76139584Srwatson
7711819Sjulianint
7883366Sjulianipx_pcbbind(ipxp, nam, td)
7911819Sjulian	register struct ipxpcb *ipxp;
8028270Swollman	struct sockaddr *nam;
8183366Sjulian	struct thread *td;
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);
8825652Sjhay	if (nam == NULL)
8911819Sjulian		goto noname;
9028270Swollman	sipx = (struct sockaddr_ipx *)nam;
9111819Sjulian	if (!ipx_nullhost(sipx->sipx_addr)) {
9211819Sjulian		int tport = sipx->sipx_port;
9311819Sjulian
9411819Sjulian		sipx->sipx_port = 0;		/* yech... */
95139559Srwatson		if (ifa_ifwithaddr((struct sockaddr *)sipx) == NULL)
9611819Sjulian			return (EADDRNOTAVAIL);
9711819Sjulian		sipx->sipx_port = tport;
9811819Sjulian	}
9911819Sjulian	lport = sipx->sipx_port;
10011819Sjulian	if (lport) {
10111819Sjulian		u_short aport = ntohs(lport);
10225345Sjhay		int error;
10311819Sjulian
10425652Sjhay		if (aport < IPXPORT_RESERVED &&
10593593Sjhb		    td != NULL && (error = suser(td)) != 0)
10625345Sjhay			return (error);
10711819Sjulian		if (ipx_pcblookup(&zeroipx_addr, lport, 0))
10811819Sjulian			return (EADDRINUSE);
10911819Sjulian	}
11011819Sjulian	ipxp->ipxp_laddr = sipx->sipx_addr;
11111819Sjuliannoname:
11211819Sjulian	if (lport == 0)
11311819Sjulian		do {
114139445Srwatson			ipxpcb_lport_cache++;
115139445Srwatson			if ((ipxpcb_lport_cache < IPXPORT_RESERVED) ||
116139445Srwatson			    (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN))
117139445Srwatson				ipxpcb_lport_cache = IPXPORT_RESERVED;
118139445Srwatson			lport = htons(ipxpcb_lport_cache);
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
13183366Sjulianipx_pcbconnect(ipxp, nam, td)
13211819Sjulian	struct ipxpcb *ipxp;
13328270Swollman	struct sockaddr *nam;
13483366Sjulian	struct thread *td;
13511819Sjulian{
13611819Sjulian	struct ipx_ifaddr *ia;
13728270Swollman	register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
13811819Sjulian	register struct ipx_addr *dst;
13911819Sjulian	register struct route *ro;
14011819Sjulian	struct ifnet *ifp;
14111819Sjulian
14225652Sjhay	ia = NULL;
14325652Sjhay
14411819Sjulian	if (sipx->sipx_family != AF_IPX)
14511819Sjulian		return (EAFNOSUPPORT);
14625652Sjhay	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);
16297658Stanimura	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)) {
16725652Sjhay		if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) {
16811819Sjulian			/* can patch route to avoid rtalloc */
16911819Sjulian			*dst = sipx->sipx_addr;
17011819Sjulian		} else {
17111819Sjulian	flush:
17225652Sjhay			if (ro->ro_rt != NULL)
17311819Sjulian				RTFREE(ro->ro_rt);
17425652Sjhay			ro->ro_rt = NULL;
17511819Sjulian		}
17611819Sjulian	}/* else cached route is ok; do nothing */
17711819Sjulian	ipxp->ipxp_lastdst = sipx->sipx_addr;
17811819Sjulian	if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
17925652Sjhay	    (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
18011819Sjulian		    /* No route yet, so try to acquire one */
18111819Sjulian		    ro->ro_dst.sa_family = AF_IPX;
18211819Sjulian		    ro->ro_dst.sa_len = sizeof(ro->ro_dst);
18311819Sjulian		    *dst = sipx->sipx_addr;
18411819Sjulian		    dst->x_port = 0;
185139556Srwatson		    rtalloc_ign(ro, 0);
18697658Stanimura	}
18711819Sjulian	if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
188139584Srwatson		/*
18911819Sjulian		 * If route is known or can be allocated now,
19011819Sjulian		 * our src addr is taken from the i/f, else punt.
19111819Sjulian		 */
19211819Sjulian
19311819Sjulian		/*
19411819Sjulian		 * If we found a route, use the address
19511819Sjulian		 * corresponding to the outgoing interface
19611819Sjulian		 */
19725652Sjhay		if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
19825652Sjhay			for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
19911819Sjulian				if (ia->ia_ifp == ifp)
20011819Sjulian					break;
20125652Sjhay		if (ia == NULL) {
20211819Sjulian			u_short fport = sipx->sipx_addr.x_port;
20311819Sjulian			sipx->sipx_addr.x_port = 0;
20411819Sjulian			ia = (struct ipx_ifaddr *)
20511819Sjulian				ifa_ifwithdstaddr((struct sockaddr *)sipx);
20611819Sjulian			sipx->sipx_addr.x_port = fport;
20725652Sjhay			if (ia == NULL)
20811819Sjulian				ia = ipx_iaonnetof(&sipx->sipx_addr);
20925652Sjhay			if (ia == NULL)
21011819Sjulian				ia = ipx_ifaddr;
21125652Sjhay			if (ia == NULL)
21211819Sjulian				return (EADDRNOTAVAIL);
21311819Sjulian		}
21411819Sjulian		ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
21511819Sjulian	}
21625652Sjhay	if (ipx_nullhost(ipxp->ipxp_laddr)) {
217139584Srwatson		/*
21825652Sjhay		 * If route is known or can be allocated now,
21925652Sjhay		 * our src addr is taken from the i/f, else punt.
22025652Sjhay		 */
22125652Sjhay
22225652Sjhay		/*
22325652Sjhay		 * If we found a route, use the address
22425652Sjhay		 * corresponding to the outgoing interface
22525652Sjhay		 */
22625652Sjhay		if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
22725652Sjhay			for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
22825652Sjhay				if (ia->ia_ifp == ifp)
22925652Sjhay					break;
23025652Sjhay		if (ia == NULL) {
23125652Sjhay			u_short fport = sipx->sipx_addr.x_port;
23225652Sjhay			sipx->sipx_addr.x_port = 0;
23325652Sjhay			ia = (struct ipx_ifaddr *)
23425652Sjhay				ifa_ifwithdstaddr((struct sockaddr *)sipx);
23525652Sjhay			sipx->sipx_addr.x_port = fport;
23625652Sjhay			if (ia == NULL)
23725652Sjhay				ia = ipx_iaonnetof(&sipx->sipx_addr);
23825652Sjhay			if (ia == NULL)
23925652Sjhay				ia = ipx_ifaddr;
24025652Sjhay			if (ia == NULL)
24125652Sjhay				return (EADDRNOTAVAIL);
24225652Sjhay		}
24325652Sjhay		ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
24425652Sjhay	}
24511819Sjulian	if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
24611819Sjulian		return (EADDRINUSE);
24725652Sjhay	if (ipxp->ipxp_lport == 0)
24883366Sjulian		ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td);
24925652Sjhay
25025652Sjhay	/* XXX just leave it zero if we can't find a route */
25125652Sjhay
25211819Sjulian	ipxp->ipxp_faddr = sipx->sipx_addr;
25311819Sjulian	/* Includes ipxp->ipxp_fport = sipx->sipx_port; */
25411819Sjulian	return (0);
25511819Sjulian}
25611819Sjulian
25711819Sjulianvoid
25811819Sjulianipx_pcbdisconnect(ipxp)
25911819Sjulian	struct ipxpcb *ipxp;
26011819Sjulian{
26111819Sjulian
26211819Sjulian	ipxp->ipxp_faddr = zeroipx_addr;
26397658Stanimura	if (ipxp->ipxp_socket->so_state & SS_NOFDREF)
26411819Sjulian		ipx_pcbdetach(ipxp);
26511819Sjulian}
26611819Sjulian
26711819Sjulianvoid
26811819Sjulianipx_pcbdetach(ipxp)
26911819Sjulian	struct ipxpcb *ipxp;
27011819Sjulian{
27111819Sjulian	struct socket *so = ipxp->ipxp_socket;
27211819Sjulian
273136682Srwatson	ACCEPT_LOCK();
274130387Srwatson	SOCK_LOCK(so);
275139559Srwatson	so->so_pcb = NULL;
27686487Sdillon	sotryfree(so);
27725652Sjhay	if (ipxp->ipxp_route.ro_rt != NULL)
278139557Srwatson		RTFREE(ipxp->ipxp_route.ro_rt);
279139444Srwatson	LIST_REMOVE(ipxp, ipxp_list);
28028270Swollman	FREE(ipxp, M_PCB);
28111819Sjulian}
28211819Sjulian
28311819Sjulianvoid
28411819Sjulianipx_setsockaddr(ipxp, nam)
28511819Sjulian	register struct ipxpcb *ipxp;
28628270Swollman	struct sockaddr **nam;
28711819Sjulian{
28828270Swollman	struct sockaddr_ipx *sipx, ssipx;
289139584Srwatson
29028270Swollman	sipx = &ssipx;
29125652Sjhay	bzero((caddr_t)sipx, sizeof(*sipx));
29211819Sjulian	sipx->sipx_len = sizeof(*sipx);
29311819Sjulian	sipx->sipx_family = AF_IPX;
29411819Sjulian	sipx->sipx_addr = ipxp->ipxp_laddr;
295126425Srwatson	*nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT);
29611819Sjulian}
29711819Sjulian
29811819Sjulianvoid
29911819Sjulianipx_setpeeraddr(ipxp, nam)
30011819Sjulian	register struct ipxpcb *ipxp;
30128270Swollman	struct sockaddr **nam;
30211819Sjulian{
30328270Swollman	struct sockaddr_ipx *sipx, ssipx;
304139587Srwatson
30528270Swollman	sipx = &ssipx;
306139587Srwatson	bzero(sipx, sizeof(*sipx));
30711819Sjulian	sipx->sipx_len = sizeof(*sipx);
30811819Sjulian	sipx->sipx_family = AF_IPX;
30911819Sjulian	sipx->sipx_addr = ipxp->ipxp_faddr;
310139587Srwatson	*nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
31111819Sjulian}
31211819Sjulian
31311819Sjulianstruct ipxpcb *
31411819Sjulianipx_pcblookup(faddr, lport, wildp)
31511819Sjulian	struct ipx_addr *faddr;
31611819Sjulian	u_short lport;
31711819Sjulian	int wildp;
31811819Sjulian{
319139559Srwatson	register struct ipxpcb *ipxp, *match = NULL;
32011819Sjulian	int matchwild = 3, wildcard;
32111819Sjulian	u_short fport;
32211819Sjulian
32311819Sjulian	fport = faddr->x_port;
324139444Srwatson	LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
32511819Sjulian		if (ipxp->ipxp_lport != lport)
32611819Sjulian			continue;
32711819Sjulian		wildcard = 0;
32811819Sjulian		if (ipx_nullhost(ipxp->ipxp_faddr)) {
32911819Sjulian			if (!ipx_nullhost(*faddr))
33011819Sjulian				wildcard++;
33111819Sjulian		} else {
33211819Sjulian			if (ipx_nullhost(*faddr))
33311819Sjulian				wildcard++;
33411819Sjulian			else {
33511819Sjulian				if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
33611819Sjulian					continue;
33711819Sjulian				if (ipxp->ipxp_fport != fport) {
33811819Sjulian					if (ipxp->ipxp_fport != 0)
33911819Sjulian						continue;
34011819Sjulian					else
34111819Sjulian						wildcard++;
34211819Sjulian				}
34311819Sjulian			}
34411819Sjulian		}
34525652Sjhay		if (wildcard && wildp == 0)
34611819Sjulian			continue;
34711819Sjulian		if (wildcard < matchwild) {
34811819Sjulian			match = ipxp;
34911819Sjulian			matchwild = wildcard;
35011819Sjulian			if (wildcard == 0)
35111819Sjulian				break;
35211819Sjulian		}
35311819Sjulian	}
35411819Sjulian	return (match);
35511819Sjulian}
356