ipx.c revision 169463
1139823Simp/*-
211819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
311819Sjulian *	The Regents of the University of California.  All rights reserved.
411819Sjulian *
511819Sjulian * Redistribution and use in source and binary forms, with or without
611819Sjulian * modification, are permitted provided that the following conditions
711819Sjulian * are met:
811819Sjulian * 1. Redistributions of source code must retain the above copyright
911819Sjulian *    notice, this list of conditions and the following disclaimer.
1011819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1111819Sjulian *    notice, this list of conditions and the following disclaimer in the
1211819Sjulian *    documentation and/or other materials provided with the distribution.
13165899Srwatson * 4. Neither the name of the University nor the names of its contributors
14165899Srwatson *    may be used to endorse or promote products derived from this software
15165899Srwatson *    without specific prior written permission.
16165899Srwatson *
17165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20165899Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27165899Srwatson * SUCH DAMAGE.
28165899Srwatson *
29165899Srwatson * Copyright (c) 1995, Mike Mitchell
30165899Srwatson *
31165899Srwatson * Redistribution and use in source and binary forms, with or without
32165899Srwatson * modification, are permitted provided that the following conditions
33165899Srwatson * are met:
34165899Srwatson * 1. Redistributions of source code must retain the above copyright
35165899Srwatson *    notice, this list of conditions and the following disclaimer.
36165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright
37165899Srwatson *    notice, this list of conditions and the following disclaimer in the
38165899Srwatson *    documentation and/or other materials provided with the distribution.
3911819Sjulian * 3. All advertising materials mentioning features or use of this software
4011819Sjulian *    must display the following acknowledgement:
4111819Sjulian *	This product includes software developed by the University of
4211819Sjulian *	California, Berkeley and its contributors.
4311819Sjulian * 4. Neither the name of the University nor the names of its contributors
4411819Sjulian *    may be used to endorse or promote products derived from this software
4511819Sjulian *    without specific prior written permission.
4611819Sjulian *
4711819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4811819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4911819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5011819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5111819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5211819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5311819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5411819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5511819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5611819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5711819Sjulian * SUCH DAMAGE.
58139584Srwatson *
5912057Sjulian *	@(#)ipx.c
6011819Sjulian */
6111819Sjulian
62116189Sobrien#include <sys/cdefs.h>
63116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx.c 169463 2007-05-11 10:38:34Z rwatson $");
64116189Sobrien
6511819Sjulian#include <sys/param.h>
66134445Srwatson#include <sys/kernel.h>
6711819Sjulian#include <sys/systm.h>
6826965Sjhay#include <sys/malloc.h>
6924204Sbde#include <sys/sockio.h>
7011819Sjulian#include <sys/socket.h>
7111819Sjulian
7211819Sjulian#include <net/if.h>
7311819Sjulian#include <net/route.h>
7411819Sjulian
7511819Sjulian#include <netipx/ipx.h>
7611819Sjulian#include <netipx/ipx_if.h>
7725652Sjhay#include <netipx/ipx_var.h>
7811819Sjulian
79134445Srwatson/*
80134445Srwatson * XXXRW: Requires synchronization.
81134445Srwatson */
8211819Sjulianstruct ipx_ifaddr *ipx_ifaddr;
8311819Sjulian
8425652Sjhaystatic	void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
8525652Sjhaystatic	int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
8625652Sjhay		       struct sockaddr_ipx *sipx, int scrub);
8725652Sjhay
8811819Sjulian/*
8911819Sjulian * Generic internet control operations (ioctl's).
9011819Sjulian */
9111819Sjulianint
92169463Srwatsonipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
93169463Srwatson    struct thread *td)
9411819Sjulian{
95169463Srwatson	struct ifreq *ifr = (struct ifreq *)data;
96169463Srwatson	struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
97169463Srwatson	struct ipx_ifaddr *ia;
9811819Sjulian	struct ifaddr *ifa;
9911819Sjulian	struct ipx_ifaddr *oia;
10011819Sjulian	int dstIsNew, hostIsNew;
10111819Sjulian	int error = 0;
10211819Sjulian
10311819Sjulian	/*
10411819Sjulian	 * Find address for this interface, if it exists.
10511819Sjulian	 */
10625652Sjhay	if (ifp == NULL)
10711819Sjulian		return (EADDRNOTAVAIL);
10825652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
10911819Sjulian		if (ia->ia_ifp == ifp)
11011819Sjulian			break;
11111819Sjulian
11211819Sjulian	switch (cmd) {
11311819Sjulian
11411819Sjulian	case SIOCGIFADDR:
11525652Sjhay		if (ia == NULL)
11611819Sjulian			return (EADDRNOTAVAIL);
11711819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
11811819Sjulian		return (0);
11911819Sjulian
12011819Sjulian	case SIOCGIFBRDADDR:
12125652Sjhay		if (ia == NULL)
12211819Sjulian			return (EADDRNOTAVAIL);
12311819Sjulian		if ((ifp->if_flags & IFF_BROADCAST) == 0)
12411819Sjulian			return (EINVAL);
12511819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
12611819Sjulian		return (0);
12711819Sjulian
12811819Sjulian	case SIOCGIFDSTADDR:
12925652Sjhay		if (ia == NULL)
13011819Sjulian			return (EADDRNOTAVAIL);
13111819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
13211819Sjulian			return (EINVAL);
13311819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
13411819Sjulian		return (0);
13511819Sjulian	}
13611819Sjulian
13793593Sjhb	if (td && (error = suser(td)) != 0)
13825345Sjhay		return (error);
13911819Sjulian
14011819Sjulian	switch (cmd) {
14111819Sjulian	case SIOCAIFADDR:
14211819Sjulian	case SIOCDIFADDR:
14311819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX)
14425652Sjhay		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
14511819Sjulian			if (ia->ia_ifp == ifp  &&
14611819Sjulian			    ipx_neteq(ia->ia_addr.sipx_addr,
14711819Sjulian				  ifra->ifra_addr.sipx_addr))
14811819Sjulian			    break;
14911819Sjulian		    }
15041617Seivind		if (cmd == SIOCDIFADDR && ia == NULL)
15111819Sjulian			return (EADDRNOTAVAIL);
15211819Sjulian		/* FALLTHROUGH */
15311819Sjulian
15411819Sjulian	case SIOCSIFADDR:
15511819Sjulian	case SIOCSIFDSTADDR:
15625652Sjhay		if (ia == NULL) {
15711819Sjulian			oia = (struct ipx_ifaddr *)
15869781Sdwmalone				malloc(sizeof(*ia), M_IFADDR,
159111119Simp				M_WAITOK | M_ZERO);
16025652Sjhay			if (oia == NULL)
16111819Sjulian				return (ENOBUFS);
16225652Sjhay			if ((ia = ipx_ifaddr) != NULL) {
16325652Sjhay				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
16411819Sjulian					;
16511819Sjulian				ia->ia_next = oia;
16611819Sjulian			} else
16711819Sjulian				ipx_ifaddr = oia;
16811819Sjulian			ia = oia;
16920407Swollman			ifa = (struct ifaddr *)ia;
170109765Sfjoe			IFA_LOCK_INIT(ifa);
171111487Stjr			ifa->ifa_refcnt = 1;
17220407Swollman			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
17311819Sjulian			ia->ia_ifp = ifp;
17420407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
17511819Sjulian
17620407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
17711819Sjulian
17820407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
17911819Sjulian			if (ifp->if_flags & IFF_BROADCAST) {
18011819Sjulian				ia->ia_broadaddr.sipx_family = AF_IPX;
18111819Sjulian				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
18211819Sjulian				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
18311819Sjulian			}
18411819Sjulian		}
18511819Sjulian	}
18611819Sjulian
18711819Sjulian	switch (cmd) {
18811819Sjulian
18911819Sjulian	case SIOCSIFDSTADDR:
19011819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
19111819Sjulian			return (EINVAL);
19211819Sjulian		if (ia->ia_flags & IFA_ROUTE) {
19311819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
19411819Sjulian			ia->ia_flags &= ~IFA_ROUTE;
19511819Sjulian		}
19611819Sjulian		if (ifp->if_ioctl) {
19711819Sjulian			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
19811819Sjulian			if (error)
19911819Sjulian				return (error);
20011819Sjulian		}
20111819Sjulian		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
20211819Sjulian		return (0);
20311819Sjulian
20411819Sjulian	case SIOCSIFADDR:
20511819Sjulian		return (ipx_ifinit(ifp, ia,
20611819Sjulian				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
20711819Sjulian
20811819Sjulian	case SIOCDIFADDR:
20911819Sjulian		ipx_ifscrub(ifp, ia);
21020407Swollman		ifa = (struct ifaddr *)ia;
21120407Swollman		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
21211819Sjulian		oia = ia;
21311819Sjulian		if (oia == (ia = ipx_ifaddr)) {
21411819Sjulian			ipx_ifaddr = ia->ia_next;
21511819Sjulian		} else {
21611819Sjulian			while (ia->ia_next && (ia->ia_next != oia)) {
21711819Sjulian				ia = ia->ia_next;
21811819Sjulian			}
21911819Sjulian			if (ia->ia_next)
22011819Sjulian			    ia->ia_next = oia->ia_next;
22111819Sjulian			else
22211819Sjulian				printf("Didn't unlink ipxifadr from list\n");
22311819Sjulian		}
22411819Sjulian		IFAFREE((&oia->ia_ifa));
22511819Sjulian		return (0);
226139584Srwatson
22711819Sjulian	case SIOCAIFADDR:
22825652Sjhay		dstIsNew = 0;
22925652Sjhay		hostIsNew = 1;
23011819Sjulian		if (ia->ia_addr.sipx_family == AF_IPX) {
23111819Sjulian			if (ifra->ifra_addr.sipx_len == 0) {
23211819Sjulian				ifra->ifra_addr = ia->ia_addr;
23311819Sjulian				hostIsNew = 0;
23411819Sjulian			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
23511819Sjulian					 ia->ia_addr.sipx_addr))
23611819Sjulian				hostIsNew = 0;
23711819Sjulian		}
23811819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) &&
23911819Sjulian		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
24011819Sjulian			if (hostIsNew == 0)
24111819Sjulian				ipx_ifscrub(ifp, ia);
24211819Sjulian			ia->ia_dstaddr = ifra->ifra_dstaddr;
24311819Sjulian			dstIsNew  = 1;
24411819Sjulian		}
24511819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX &&
24611819Sjulian					    (hostIsNew || dstIsNew))
24711819Sjulian			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
24811819Sjulian		return (error);
24911819Sjulian
25011819Sjulian	default:
25125652Sjhay		if (ifp->if_ioctl == NULL)
25211819Sjulian			return (EOPNOTSUPP);
25311819Sjulian		return ((*ifp->if_ioctl)(ifp, cmd, data));
25411819Sjulian	}
25511819Sjulian}
25611819Sjulian
25711819Sjulian/*
25811819Sjulian* Delete any previous route for an old address.
25911819Sjulian*/
26025652Sjhaystatic void
261169463Srwatsonipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia)
26211819Sjulian{
263169463Srwatson
26411819Sjulian	if (ia->ia_flags & IFA_ROUTE) {
26511819Sjulian		if (ifp->if_flags & IFF_POINTOPOINT) {
26611819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
26711819Sjulian		} else
26811819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
26911819Sjulian		ia->ia_flags &= ~IFA_ROUTE;
27011819Sjulian	}
27111819Sjulian}
27211819Sjulian/*
27311819Sjulian * Initialize an interface's internet address
27411819Sjulian * and routing table entry.
27511819Sjulian */
27625652Sjhaystatic int
277169463Srwatsonipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
278169463Srwatson    struct sockaddr_ipx *sipx, int scrub)
27911819Sjulian{
28011819Sjulian	struct sockaddr_ipx oldaddr;
28111819Sjulian	int s = splimp(), error;
28211819Sjulian
28311819Sjulian	/*
28411819Sjulian	 * Set up new addresses.
28511819Sjulian	 */
28611819Sjulian	oldaddr = ia->ia_addr;
28711819Sjulian	ia->ia_addr = *sipx;
28825652Sjhay
28911819Sjulian	/*
29011819Sjulian	 * The convention we shall adopt for naming is that
29111819Sjulian	 * a supplied address of zero means that "we don't care".
29225652Sjhay	 * Use the MAC address of the interface. If it is an
29325652Sjhay	 * interface without a MAC address, like a serial line, the
29425652Sjhay	 * address must be supplied.
29511819Sjulian	 *
29611819Sjulian	 * Give the interface a chance to initialize
29711819Sjulian	 * if this is its first address,
29811819Sjulian	 * and to validate the address if necessary.
29911819Sjulian	 */
30025652Sjhay	if (ifp->if_ioctl != NULL &&
30125652Sjhay	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
30211819Sjulian		ia->ia_addr = oldaddr;
30311819Sjulian		splx(s);
30425652Sjhay		return (error);
30511819Sjulian	}
30625652Sjhay	splx(s);
30711819Sjulian	ia->ia_ifa.ifa_metric = ifp->if_metric;
30811819Sjulian	/*
30911819Sjulian	 * Add route for the network.
31011819Sjulian	 */
31111819Sjulian	if (scrub) {
31211819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
31311819Sjulian		ipx_ifscrub(ifp, ia);
31411819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
31511819Sjulian	}
31611819Sjulian	if (ifp->if_flags & IFF_POINTOPOINT)
31711819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
31811819Sjulian	else {
31911819Sjulian		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
32011819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
32111819Sjulian	}
32211819Sjulian	ia->ia_flags |= IFA_ROUTE;
32311819Sjulian	return (0);
32411819Sjulian}
32511819Sjulian
32611819Sjulian/*
32711819Sjulian * Return address info for specified internet network.
32811819Sjulian */
32911819Sjulianstruct ipx_ifaddr *
330169463Srwatsonipx_iaonnetof(struct ipx_addr *dst)
33111819Sjulian{
332169463Srwatson	struct ipx_ifaddr *ia;
333169463Srwatson	struct ipx_addr *compare;
334169463Srwatson	struct ifnet *ifp;
33525652Sjhay	struct ipx_ifaddr *ia_maybe = NULL;
33611819Sjulian	union ipx_net net = dst->x_net;
33711819Sjulian
33825652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
33925652Sjhay		if ((ifp = ia->ia_ifp) != NULL) {
34011819Sjulian			if (ifp->if_flags & IFF_POINTOPOINT) {
34111819Sjulian				compare = &satoipx_addr(ia->ia_dstaddr);
34211819Sjulian				if (ipx_hosteq(*dst, *compare))
34311819Sjulian					return (ia);
34411819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
34511819Sjulian					ia_maybe = ia;
34611819Sjulian			} else {
34711819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
34811819Sjulian					return (ia);
34911819Sjulian			}
35011819Sjulian		}
35111819Sjulian	}
35211819Sjulian	return (ia_maybe);
35311819Sjulian}
35426965Sjhay
35526965Sjhay
35626965Sjhayvoid
357169463Srwatsonipx_printhost(struct ipx_addr *addr)
35826965Sjhay{
35926965Sjhay	u_short port;
36026965Sjhay	struct ipx_addr work = *addr;
361169463Srwatson	char *p; u_char *q;
362169463Srwatson	char *net = "", *host = "";
36326965Sjhay	char cport[10], chost[15], cnet[15];
36426965Sjhay
36526965Sjhay	port = ntohs(work.x_port);
36626965Sjhay
36726965Sjhay	if (ipx_nullnet(work) && ipx_nullhost(work)) {
36826965Sjhay
36926965Sjhay		if (port)
37026965Sjhay			printf("*.%x", port);
37126965Sjhay		else
37226965Sjhay			printf("*.*");
37326965Sjhay
37426965Sjhay		return;
37526965Sjhay	}
37626965Sjhay
37726965Sjhay	if (ipx_wildnet(work))
37826965Sjhay		net = "any";
37926965Sjhay	else if (ipx_nullnet(work))
38026965Sjhay		net = "*";
38126965Sjhay	else {
38226965Sjhay		q = work.x_net.c_net;
38341514Sarchie		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
38426965Sjhay			q[0], q[1], q[2], q[3]);
38526965Sjhay		for (p = cnet; *p == '0' && p < cnet + 8; p++)
38626965Sjhay			continue;
38726965Sjhay		net = p;
38826965Sjhay	}
38926965Sjhay
39026965Sjhay	if (ipx_wildhost(work))
39126965Sjhay		host = "any";
39226965Sjhay	else if (ipx_nullhost(work))
39326965Sjhay		host = "*";
39426965Sjhay	else {
39526965Sjhay		q = work.x_host.c_host;
39641514Sarchie		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
39726965Sjhay			q[0], q[1], q[2], q[3], q[4], q[5]);
39826965Sjhay		for (p = chost; *p == '0' && p < chost + 12; p++)
39926965Sjhay			continue;
40026965Sjhay		host = p;
40126965Sjhay	}
40226965Sjhay
40326965Sjhay	if (port) {
40426965Sjhay		if (strcmp(host, "*") == 0) {
40526965Sjhay			host = "";
40641514Sarchie			snprintf(cport, sizeof(cport), "%x", port);
40726965Sjhay		} else
40841514Sarchie			snprintf(cport, sizeof(cport), ".%x", port);
40926965Sjhay	} else
41026965Sjhay		*cport = 0;
41126965Sjhay
41226965Sjhay	printf("%s.%s%s", net, host, cport);
41326965Sjhay}
414