ipx.c revision 183113
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 183113 2008-09-17 15:49:44Z attilio $");
64116189Sobrien
6511819Sjulian#include <sys/param.h>
66134445Srwatson#include <sys/kernel.h>
6711819Sjulian#include <sys/systm.h>
6826965Sjhay#include <sys/malloc.h>
69170689Srwatson#include <sys/priv.h>
7024204Sbde#include <sys/sockio.h>
7111819Sjulian#include <sys/socket.h>
7211819Sjulian
7311819Sjulian#include <net/if.h>
7411819Sjulian#include <net/route.h>
7511819Sjulian
7611819Sjulian#include <netipx/ipx.h>
7711819Sjulian#include <netipx/ipx_if.h>
7825652Sjhay#include <netipx/ipx_var.h>
7911819Sjulian
80134445Srwatson/*
81134445Srwatson * XXXRW: Requires synchronization.
82134445Srwatson */
8311819Sjulianstruct ipx_ifaddr *ipx_ifaddr;
8411819Sjulian
8525652Sjhaystatic	void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
8625652Sjhaystatic	int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
8725652Sjhay		       struct sockaddr_ipx *sipx, int scrub);
8825652Sjhay
8911819Sjulian/*
9011819Sjulian * Generic internet control operations (ioctl's).
9111819Sjulian */
9211819Sjulianint
93169463Srwatsonipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
94169463Srwatson    struct thread *td)
9511819Sjulian{
96169463Srwatson	struct ifreq *ifr = (struct ifreq *)data;
97169463Srwatson	struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
98169463Srwatson	struct ipx_ifaddr *ia;
9911819Sjulian	struct ifaddr *ifa;
10011819Sjulian	struct ipx_ifaddr *oia;
10111819Sjulian	int dstIsNew, hostIsNew;
102183113Sattilio	int error = 0, priv;
10311819Sjulian
10411819Sjulian	/*
10511819Sjulian	 * Find address for this interface, if it exists.
10611819Sjulian	 */
10725652Sjhay	if (ifp == NULL)
10811819Sjulian		return (EADDRNOTAVAIL);
10925652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
11011819Sjulian		if (ia->ia_ifp == ifp)
11111819Sjulian			break;
11211819Sjulian
11311819Sjulian	switch (cmd) {
11411819Sjulian
11511819Sjulian	case SIOCGIFADDR:
11625652Sjhay		if (ia == NULL)
11711819Sjulian			return (EADDRNOTAVAIL);
11811819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
11911819Sjulian		return (0);
12011819Sjulian
12111819Sjulian	case SIOCGIFBRDADDR:
12225652Sjhay		if (ia == NULL)
12311819Sjulian			return (EADDRNOTAVAIL);
12411819Sjulian		if ((ifp->if_flags & IFF_BROADCAST) == 0)
12511819Sjulian			return (EINVAL);
12611819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
12711819Sjulian		return (0);
12811819Sjulian
12911819Sjulian	case SIOCGIFDSTADDR:
13025652Sjhay		if (ia == NULL)
13111819Sjulian			return (EADDRNOTAVAIL);
13211819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
13311819Sjulian			return (EINVAL);
13411819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
13511819Sjulian		return (0);
13611819Sjulian	}
13711819Sjulian
13811819Sjulian	switch (cmd) {
13911819Sjulian	case SIOCAIFADDR:
14011819Sjulian	case SIOCDIFADDR:
141183113Sattilio		priv = (cmd == SIOCAIFADDR) ? PRIV_NET_ADDIFADDR :
142183113Sattilio		    PRIV_NET_DELIFADDR;
143183113Sattilio		if (td && (error = priv_check(td, priv)) != 0)
144183113Sattilio			return (error);
14511819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX)
14625652Sjhay		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
14711819Sjulian			if (ia->ia_ifp == ifp  &&
14811819Sjulian			    ipx_neteq(ia->ia_addr.sipx_addr,
14911819Sjulian				  ifra->ifra_addr.sipx_addr))
15011819Sjulian			    break;
15111819Sjulian		    }
15241617Seivind		if (cmd == SIOCDIFADDR && ia == NULL)
15311819Sjulian			return (EADDRNOTAVAIL);
15411819Sjulian		/* FALLTHROUGH */
15511819Sjulian
15611819Sjulian	case SIOCSIFADDR:
15711819Sjulian	case SIOCSIFDSTADDR:
158183113Sattilio		if (td && (error = priv_check(td, PRIV_NET_SETLLADDR)) != 0)
159183113Sattilio			return (error);
16025652Sjhay		if (ia == NULL) {
16111819Sjulian			oia = (struct ipx_ifaddr *)
16269781Sdwmalone				malloc(sizeof(*ia), M_IFADDR,
163111119Simp				M_WAITOK | M_ZERO);
16425652Sjhay			if (oia == NULL)
16511819Sjulian				return (ENOBUFS);
16625652Sjhay			if ((ia = ipx_ifaddr) != NULL) {
16725652Sjhay				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
16811819Sjulian					;
16911819Sjulian				ia->ia_next = oia;
17011819Sjulian			} else
17111819Sjulian				ipx_ifaddr = oia;
17211819Sjulian			ia = oia;
17320407Swollman			ifa = (struct ifaddr *)ia;
174109765Sfjoe			IFA_LOCK_INIT(ifa);
175111487Stjr			ifa->ifa_refcnt = 1;
17620407Swollman			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
17711819Sjulian			ia->ia_ifp = ifp;
17820407Swollman			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
17911819Sjulian
18020407Swollman			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
18111819Sjulian
18220407Swollman			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
18311819Sjulian			if (ifp->if_flags & IFF_BROADCAST) {
18411819Sjulian				ia->ia_broadaddr.sipx_family = AF_IPX;
18511819Sjulian				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
18611819Sjulian				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
18711819Sjulian			}
18811819Sjulian		}
189183113Sattilio		break;
190183113Sattilio	default:
191183113Sattilio		if (td && (error = priv_check(td, PRIV_NET_HWIOCTL)) != 0)
192183113Sattilio			return (error);
19311819Sjulian	}
19411819Sjulian
19511819Sjulian	switch (cmd) {
19611819Sjulian
19711819Sjulian	case SIOCSIFDSTADDR:
19811819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
19911819Sjulian			return (EINVAL);
20011819Sjulian		if (ia->ia_flags & IFA_ROUTE) {
20111819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
20211819Sjulian			ia->ia_flags &= ~IFA_ROUTE;
20311819Sjulian		}
20411819Sjulian		if (ifp->if_ioctl) {
20511819Sjulian			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
20611819Sjulian			if (error)
20711819Sjulian				return (error);
20811819Sjulian		}
20911819Sjulian		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
21011819Sjulian		return (0);
21111819Sjulian
21211819Sjulian	case SIOCSIFADDR:
21311819Sjulian		return (ipx_ifinit(ifp, ia,
21411819Sjulian				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
21511819Sjulian
21611819Sjulian	case SIOCDIFADDR:
21711819Sjulian		ipx_ifscrub(ifp, ia);
21820407Swollman		ifa = (struct ifaddr *)ia;
21920407Swollman		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
22011819Sjulian		oia = ia;
22111819Sjulian		if (oia == (ia = ipx_ifaddr)) {
22211819Sjulian			ipx_ifaddr = ia->ia_next;
22311819Sjulian		} else {
22411819Sjulian			while (ia->ia_next && (ia->ia_next != oia)) {
22511819Sjulian				ia = ia->ia_next;
22611819Sjulian			}
22711819Sjulian			if (ia->ia_next)
22811819Sjulian			    ia->ia_next = oia->ia_next;
22911819Sjulian			else
23011819Sjulian				printf("Didn't unlink ipxifadr from list\n");
23111819Sjulian		}
23211819Sjulian		IFAFREE((&oia->ia_ifa));
23311819Sjulian		return (0);
234139584Srwatson
23511819Sjulian	case SIOCAIFADDR:
23625652Sjhay		dstIsNew = 0;
23725652Sjhay		hostIsNew = 1;
23811819Sjulian		if (ia->ia_addr.sipx_family == AF_IPX) {
23911819Sjulian			if (ifra->ifra_addr.sipx_len == 0) {
24011819Sjulian				ifra->ifra_addr = ia->ia_addr;
24111819Sjulian				hostIsNew = 0;
24211819Sjulian			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
24311819Sjulian					 ia->ia_addr.sipx_addr))
24411819Sjulian				hostIsNew = 0;
24511819Sjulian		}
24611819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) &&
24711819Sjulian		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
24811819Sjulian			if (hostIsNew == 0)
24911819Sjulian				ipx_ifscrub(ifp, ia);
25011819Sjulian			ia->ia_dstaddr = ifra->ifra_dstaddr;
25111819Sjulian			dstIsNew  = 1;
25211819Sjulian		}
25311819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX &&
25411819Sjulian					    (hostIsNew || dstIsNew))
25511819Sjulian			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
25611819Sjulian		return (error);
25711819Sjulian
25811819Sjulian	default:
25925652Sjhay		if (ifp->if_ioctl == NULL)
26011819Sjulian			return (EOPNOTSUPP);
26111819Sjulian		return ((*ifp->if_ioctl)(ifp, cmd, data));
26211819Sjulian	}
26311819Sjulian}
26411819Sjulian
26511819Sjulian/*
26611819Sjulian* Delete any previous route for an old address.
26711819Sjulian*/
26825652Sjhaystatic void
269169463Srwatsonipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia)
27011819Sjulian{
271169463Srwatson
27211819Sjulian	if (ia->ia_flags & IFA_ROUTE) {
27311819Sjulian		if (ifp->if_flags & IFF_POINTOPOINT) {
27411819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
27511819Sjulian		} else
27611819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
27711819Sjulian		ia->ia_flags &= ~IFA_ROUTE;
27811819Sjulian	}
27911819Sjulian}
28011819Sjulian/*
28111819Sjulian * Initialize an interface's internet address
28211819Sjulian * and routing table entry.
28311819Sjulian */
28425652Sjhaystatic int
285169463Srwatsonipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
286169463Srwatson    struct sockaddr_ipx *sipx, int scrub)
28711819Sjulian{
28811819Sjulian	struct sockaddr_ipx oldaddr;
28911819Sjulian	int s = splimp(), error;
29011819Sjulian
29111819Sjulian	/*
29211819Sjulian	 * Set up new addresses.
29311819Sjulian	 */
29411819Sjulian	oldaddr = ia->ia_addr;
29511819Sjulian	ia->ia_addr = *sipx;
29625652Sjhay
29711819Sjulian	/*
29811819Sjulian	 * The convention we shall adopt for naming is that
29911819Sjulian	 * a supplied address of zero means that "we don't care".
30025652Sjhay	 * Use the MAC address of the interface. If it is an
30125652Sjhay	 * interface without a MAC address, like a serial line, the
30225652Sjhay	 * address must be supplied.
30311819Sjulian	 *
30411819Sjulian	 * Give the interface a chance to initialize
30511819Sjulian	 * if this is its first address,
30611819Sjulian	 * and to validate the address if necessary.
30711819Sjulian	 */
30825652Sjhay	if (ifp->if_ioctl != NULL &&
30925652Sjhay	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
31011819Sjulian		ia->ia_addr = oldaddr;
31111819Sjulian		splx(s);
31225652Sjhay		return (error);
31311819Sjulian	}
31425652Sjhay	splx(s);
31511819Sjulian	ia->ia_ifa.ifa_metric = ifp->if_metric;
31611819Sjulian	/*
31711819Sjulian	 * Add route for the network.
31811819Sjulian	 */
31911819Sjulian	if (scrub) {
32011819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
32111819Sjulian		ipx_ifscrub(ifp, ia);
32211819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
32311819Sjulian	}
32411819Sjulian	if (ifp->if_flags & IFF_POINTOPOINT)
32511819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
32611819Sjulian	else {
32711819Sjulian		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
32811819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
32911819Sjulian	}
33011819Sjulian	ia->ia_flags |= IFA_ROUTE;
33111819Sjulian	return (0);
33211819Sjulian}
33311819Sjulian
33411819Sjulian/*
33511819Sjulian * Return address info for specified internet network.
33611819Sjulian */
33711819Sjulianstruct ipx_ifaddr *
338169463Srwatsonipx_iaonnetof(struct ipx_addr *dst)
33911819Sjulian{
340169463Srwatson	struct ipx_ifaddr *ia;
341169463Srwatson	struct ipx_addr *compare;
342169463Srwatson	struct ifnet *ifp;
34325652Sjhay	struct ipx_ifaddr *ia_maybe = NULL;
34411819Sjulian	union ipx_net net = dst->x_net;
34511819Sjulian
34625652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
34725652Sjhay		if ((ifp = ia->ia_ifp) != NULL) {
34811819Sjulian			if (ifp->if_flags & IFF_POINTOPOINT) {
34911819Sjulian				compare = &satoipx_addr(ia->ia_dstaddr);
35011819Sjulian				if (ipx_hosteq(*dst, *compare))
35111819Sjulian					return (ia);
35211819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
35311819Sjulian					ia_maybe = ia;
35411819Sjulian			} else {
35511819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
35611819Sjulian					return (ia);
35711819Sjulian			}
35811819Sjulian		}
35911819Sjulian	}
36011819Sjulian	return (ia_maybe);
36111819Sjulian}
36226965Sjhay
36326965Sjhay
36426965Sjhayvoid
365169463Srwatsonipx_printhost(struct ipx_addr *addr)
36626965Sjhay{
36726965Sjhay	u_short port;
36826965Sjhay	struct ipx_addr work = *addr;
369169463Srwatson	char *p; u_char *q;
370169463Srwatson	char *net = "", *host = "";
37126965Sjhay	char cport[10], chost[15], cnet[15];
37226965Sjhay
37326965Sjhay	port = ntohs(work.x_port);
37426965Sjhay
37526965Sjhay	if (ipx_nullnet(work) && ipx_nullhost(work)) {
37626965Sjhay
37726965Sjhay		if (port)
37826965Sjhay			printf("*.%x", port);
37926965Sjhay		else
38026965Sjhay			printf("*.*");
38126965Sjhay
38226965Sjhay		return;
38326965Sjhay	}
38426965Sjhay
38526965Sjhay	if (ipx_wildnet(work))
38626965Sjhay		net = "any";
38726965Sjhay	else if (ipx_nullnet(work))
38826965Sjhay		net = "*";
38926965Sjhay	else {
39026965Sjhay		q = work.x_net.c_net;
39141514Sarchie		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
39226965Sjhay			q[0], q[1], q[2], q[3]);
39326965Sjhay		for (p = cnet; *p == '0' && p < cnet + 8; p++)
39426965Sjhay			continue;
39526965Sjhay		net = p;
39626965Sjhay	}
39726965Sjhay
39826965Sjhay	if (ipx_wildhost(work))
39926965Sjhay		host = "any";
40026965Sjhay	else if (ipx_nullhost(work))
40126965Sjhay		host = "*";
40226965Sjhay	else {
40326965Sjhay		q = work.x_host.c_host;
40441514Sarchie		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
40526965Sjhay			q[0], q[1], q[2], q[3], q[4], q[5]);
40626965Sjhay		for (p = chost; *p == '0' && p < chost + 12; p++)
40726965Sjhay			continue;
40826965Sjhay		host = p;
40926965Sjhay	}
41026965Sjhay
41126965Sjhay	if (port) {
41226965Sjhay		if (strcmp(host, "*") == 0) {
41326965Sjhay			host = "";
41441514Sarchie			snprintf(cport, sizeof(cport), "%x", port);
41526965Sjhay		} else
41641514Sarchie			snprintf(cport, sizeof(cport), ".%x", port);
41726965Sjhay	} else
41826965Sjhay		*cport = 0;
41926965Sjhay
42026965Sjhay	printf("%s.%s%s", net, host, cport);
42126965Sjhay}
422