ipx.c revision 11819
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 *
3411819Sjulian *	@(#)ipx.c
3511819Sjulian */
3611819Sjulian
3711819Sjulian#include <sys/param.h>
3811819Sjulian#include <sys/systm.h>
3911819Sjulian#include <sys/mbuf.h>
4011819Sjulian#include <sys/ioctl.h>
4111819Sjulian#include <sys/protosw.h>
4211819Sjulian#include <sys/errno.h>
4311819Sjulian#include <sys/socket.h>
4411819Sjulian#include <sys/socketvar.h>
4511819Sjulian
4611819Sjulian#include <net/if.h>
4711819Sjulian#include <net/route.h>
4811819Sjulian
4911819Sjulian#include <netipx/ipx.h>
5011819Sjulian#include <netipx/ipx_if.h>
5111819Sjulian
5211819Sjulian#ifdef IPX
5311819Sjulian
5411819Sjulianstruct ipx_ifaddr *ipx_ifaddr;
5511819Sjulianint ipx_interfaces;
5611819Sjulian
5711819Sjulian/*
5811819Sjulian * Generic internet control operations (ioctl's).
5911819Sjulian */
6011819Sjulian/* ARGSUSED */
6111819Sjulianint
6211819Sjulianipx_control(so, cmd, data, ifp)
6311819Sjulian	struct socket *so;
6411819Sjulian	int cmd;
6511819Sjulian	caddr_t data;
6611819Sjulian	register struct ifnet *ifp;
6711819Sjulian{
6811819Sjulian	register struct ifreq *ifr = (struct ifreq *)data;
6911819Sjulian	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
7011819Sjulian	register struct ipx_ifaddr *ia;
7111819Sjulian	struct ifaddr *ifa;
7211819Sjulian	struct ipx_ifaddr *oia;
7311819Sjulian	int dstIsNew, hostIsNew;
7411819Sjulian	int error = 0;
7511819Sjulian
7611819Sjulian	/*
7711819Sjulian	 * Find address for this interface, if it exists.
7811819Sjulian	 */
7911819Sjulian	if (ifp == 0)
8011819Sjulian		return (EADDRNOTAVAIL);
8111819Sjulian	for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
8211819Sjulian		if (ia->ia_ifp == ifp)
8311819Sjulian			break;
8411819Sjulian
8511819Sjulian	switch (cmd) {
8611819Sjulian
8711819Sjulian	case SIOCGIFADDR:
8811819Sjulian		if (ia == (struct ipx_ifaddr *)0)
8911819Sjulian			return (EADDRNOTAVAIL);
9011819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
9111819Sjulian		return (0);
9211819Sjulian
9311819Sjulian	case SIOCGIFBRDADDR:
9411819Sjulian		if (ia == (struct ipx_ifaddr *)0)
9511819Sjulian			return (EADDRNOTAVAIL);
9611819Sjulian		if ((ifp->if_flags & IFF_BROADCAST) == 0)
9711819Sjulian			return (EINVAL);
9811819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
9911819Sjulian		return (0);
10011819Sjulian
10111819Sjulian	case SIOCGIFDSTADDR:
10211819Sjulian		if (ia == (struct ipx_ifaddr *)0)
10311819Sjulian			return (EADDRNOTAVAIL);
10411819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
10511819Sjulian			return (EINVAL);
10611819Sjulian		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
10711819Sjulian		return (0);
10811819Sjulian	}
10911819Sjulian
11011819Sjulian	if ((so->so_state & SS_PRIV) == 0)
11111819Sjulian		return (EPERM);
11211819Sjulian
11311819Sjulian	switch (cmd) {
11411819Sjulian	case SIOCAIFADDR:
11511819Sjulian	case SIOCDIFADDR:
11611819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX)
11711819Sjulian		    for (oia = ia; ia; ia = ia->ia_next) {
11811819Sjulian			if (ia->ia_ifp == ifp  &&
11911819Sjulian			    ipx_neteq(ia->ia_addr.sipx_addr,
12011819Sjulian				  ifra->ifra_addr.sipx_addr))
12111819Sjulian			    break;
12211819Sjulian		    }
12311819Sjulian		if (cmd == SIOCDIFADDR && ia == 0)
12411819Sjulian			return (EADDRNOTAVAIL);
12511819Sjulian		/* FALLTHROUGH */
12611819Sjulian
12711819Sjulian	case SIOCSIFADDR:
12811819Sjulian	case SIOCSIFDSTADDR:
12911819Sjulian		if (ia == (struct ipx_ifaddr *)0) {
13011819Sjulian			oia = (struct ipx_ifaddr *)
13111819Sjulian				malloc(sizeof *ia, M_IFADDR, M_WAITOK);
13211819Sjulian			if (oia == (struct ipx_ifaddr *)NULL)
13311819Sjulian				return (ENOBUFS);
13411819Sjulian			bzero((caddr_t)oia, sizeof(*oia));
13511819Sjulian			if ((ia = ipx_ifaddr)) {
13611819Sjulian				for ( ; ia->ia_next; ia = ia->ia_next)
13711819Sjulian					;
13811819Sjulian				ia->ia_next = oia;
13911819Sjulian			} else
14011819Sjulian				ipx_ifaddr = oia;
14111819Sjulian			ia = oia;
14211819Sjulian			if ((ifa = ifp->if_addrlist)) {
14311819Sjulian				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
14411819Sjulian					;
14511819Sjulian				ifa->ifa_next = (struct ifaddr *) ia;
14611819Sjulian			} else
14711819Sjulian				ifp->if_addrlist = (struct ifaddr *) ia;
14811819Sjulian			ia->ia_ifp = ifp;
14911819Sjulian			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
15011819Sjulian
15111819Sjulian			ia->ia_ifa.ifa_netmask =
15211819Sjulian				(struct sockaddr *)&ipx_netmask;
15311819Sjulian
15411819Sjulian			ia->ia_ifa.ifa_dstaddr =
15511819Sjulian				(struct sockaddr *)&ia->ia_dstaddr;
15611819Sjulian			if (ifp->if_flags & IFF_BROADCAST) {
15711819Sjulian				ia->ia_broadaddr.sipx_family = AF_IPX;
15811819Sjulian				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
15911819Sjulian				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
16011819Sjulian			}
16111819Sjulian			ipx_interfaces++;
16211819Sjulian		}
16311819Sjulian	}
16411819Sjulian
16511819Sjulian	switch (cmd) {
16611819Sjulian
16711819Sjulian	case SIOCSIFDSTADDR:
16811819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
16911819Sjulian			return (EINVAL);
17011819Sjulian		if (ia->ia_flags & IFA_ROUTE) {
17111819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
17211819Sjulian			ia->ia_flags &= ~IFA_ROUTE;
17311819Sjulian		}
17411819Sjulian		if (ifp->if_ioctl) {
17511819Sjulian			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
17611819Sjulian			if (error)
17711819Sjulian				return (error);
17811819Sjulian		}
17911819Sjulian		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
18011819Sjulian		return (0);
18111819Sjulian
18211819Sjulian	case SIOCSIFADDR:
18311819Sjulian		return (ipx_ifinit(ifp, ia,
18411819Sjulian				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
18511819Sjulian
18611819Sjulian	case SIOCDIFADDR:
18711819Sjulian		ipx_ifscrub(ifp, ia);
18811819Sjulian		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
18911819Sjulian			ifp->if_addrlist = ifa->ifa_next;
19011819Sjulian		else {
19111819Sjulian			while (ifa->ifa_next &&
19211819Sjulian			       (ifa->ifa_next != (struct ifaddr *)ia))
19311819Sjulian				    ifa = ifa->ifa_next;
19411819Sjulian			if (ifa->ifa_next)
19511819Sjulian			    ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
19611819Sjulian			else
19711819Sjulian				printf("Couldn't unlink ipxifaddr from ifp\n");
19811819Sjulian		}
19911819Sjulian		oia = ia;
20011819Sjulian		if (oia == (ia = ipx_ifaddr)) {
20111819Sjulian			ipx_ifaddr = ia->ia_next;
20211819Sjulian		} else {
20311819Sjulian			while (ia->ia_next && (ia->ia_next != oia)) {
20411819Sjulian				ia = ia->ia_next;
20511819Sjulian			}
20611819Sjulian			if (ia->ia_next)
20711819Sjulian			    ia->ia_next = oia->ia_next;
20811819Sjulian			else
20911819Sjulian				printf("Didn't unlink ipxifadr from list\n");
21011819Sjulian		}
21111819Sjulian		IFAFREE((&oia->ia_ifa));
21211819Sjulian		if (0 == --ipx_interfaces) {
21311819Sjulian			/*
21411819Sjulian			 * We reset to virginity and start all over again
21511819Sjulian			 */
21611819Sjulian			ipx_thishost = ipx_zerohost;
21711819Sjulian		}
21811819Sjulian		return (0);
21911819Sjulian
22011819Sjulian	case SIOCAIFADDR:
22111819Sjulian		dstIsNew = 0; hostIsNew = 1;
22211819Sjulian		if (ia->ia_addr.sipx_family == AF_IPX) {
22311819Sjulian			if (ifra->ifra_addr.sipx_len == 0) {
22411819Sjulian				ifra->ifra_addr = ia->ia_addr;
22511819Sjulian				hostIsNew = 0;
22611819Sjulian			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
22711819Sjulian					 ia->ia_addr.sipx_addr))
22811819Sjulian				hostIsNew = 0;
22911819Sjulian		}
23011819Sjulian		if ((ifp->if_flags & IFF_POINTOPOINT) &&
23111819Sjulian		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
23211819Sjulian			if (hostIsNew == 0)
23311819Sjulian				ipx_ifscrub(ifp, ia);
23411819Sjulian			ia->ia_dstaddr = ifra->ifra_dstaddr;
23511819Sjulian			dstIsNew  = 1;
23611819Sjulian		}
23711819Sjulian		if (ifra->ifra_addr.sipx_family == AF_IPX &&
23811819Sjulian					    (hostIsNew || dstIsNew))
23911819Sjulian			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
24011819Sjulian		return (error);
24111819Sjulian
24211819Sjulian	default:
24311819Sjulian		if (ifp->if_ioctl == 0)
24411819Sjulian			return (EOPNOTSUPP);
24511819Sjulian		return ((*ifp->if_ioctl)(ifp, cmd, data));
24611819Sjulian	}
24711819Sjulian}
24811819Sjulian
24911819Sjulian/*
25011819Sjulian* Delete any previous route for an old address.
25111819Sjulian*/
25211819Sjulianvoid
25311819Sjulianipx_ifscrub(ifp, ia)
25411819Sjulian	register struct ifnet *ifp;
25511819Sjulian	register struct ipx_ifaddr *ia;
25611819Sjulian{
25711819Sjulian	if (ia->ia_flags & IFA_ROUTE) {
25811819Sjulian		if (ifp->if_flags & IFF_POINTOPOINT) {
25911819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
26011819Sjulian		} else
26111819Sjulian			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
26211819Sjulian		ia->ia_flags &= ~IFA_ROUTE;
26311819Sjulian	}
26411819Sjulian}
26511819Sjulian/*
26611819Sjulian * Initialize an interface's internet address
26711819Sjulian * and routing table entry.
26811819Sjulian */
26911819Sjulianint
27011819Sjulianipx_ifinit(ifp, ia, sipx, scrub)
27111819Sjulian	register struct ifnet *ifp;
27211819Sjulian	register struct ipx_ifaddr *ia;
27311819Sjulian	register struct sockaddr_ipx *sipx;
27411819Sjulian	int scrub;
27511819Sjulian{
27611819Sjulian	struct sockaddr_ipx oldaddr;
27711819Sjulian	register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host;
27811819Sjulian	int s = splimp(), error;
27911819Sjulian
28011819Sjulian	/*
28111819Sjulian	 * Set up new addresses.
28211819Sjulian	 */
28311819Sjulian	oldaddr = ia->ia_addr;
28411819Sjulian	ia->ia_addr = *sipx;
28511819Sjulian	/*
28611819Sjulian	 * The convention we shall adopt for naming is that
28711819Sjulian	 * a supplied address of zero means that "we don't care".
28811819Sjulian	 * if there is a single interface, use the address of that
28911819Sjulian	 * interface as our 6 byte host address.
29011819Sjulian	 * if there are multiple interfaces, use any address already
29111819Sjulian	 * used.
29211819Sjulian	 *
29311819Sjulian	 * Give the interface a chance to initialize
29411819Sjulian	 * if this is its first address,
29511819Sjulian	 * and to validate the address if necessary.
29611819Sjulian	 */
29711819Sjulian	if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) {
29811819Sjulian		if (ifp->if_ioctl &&
29911819Sjulian		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
30011819Sjulian			ia->ia_addr = oldaddr;
30111819Sjulian			splx(s);
30211819Sjulian			return (error);
30311819Sjulian		}
30411819Sjulian		ipx_thishost = *h;
30511819Sjulian	} else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost)
30611819Sjulian	    || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) {
30711819Sjulian		*h = ipx_thishost;
30811819Sjulian		if (ifp->if_ioctl &&
30911819Sjulian		     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
31011819Sjulian			ia->ia_addr = oldaddr;
31111819Sjulian			splx(s);
31211819Sjulian			return (error);
31311819Sjulian		}
31411819Sjulian		if (!ipx_hosteqnh(ipx_thishost,*h)) {
31511819Sjulian			ia->ia_addr = oldaddr;
31611819Sjulian			splx(s);
31711819Sjulian			return (EINVAL);
31811819Sjulian		}
31911819Sjulian	} else {
32011819Sjulian		ia->ia_addr = oldaddr;
32111819Sjulian		splx(s);
32211819Sjulian		return (EINVAL);
32311819Sjulian	}
32411819Sjulian	ia->ia_ifa.ifa_metric = ifp->if_metric;
32511819Sjulian	/*
32611819Sjulian	 * Add route for the network.
32711819Sjulian	 */
32811819Sjulian	if (scrub) {
32911819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
33011819Sjulian		ipx_ifscrub(ifp, ia);
33111819Sjulian		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
33211819Sjulian	}
33311819Sjulian	if (ifp->if_flags & IFF_POINTOPOINT)
33411819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
33511819Sjulian	else {
33611819Sjulian		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
33711819Sjulian		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
33811819Sjulian	}
33911819Sjulian	ia->ia_flags |= IFA_ROUTE;
34011819Sjulian	return (0);
34111819Sjulian}
34211819Sjulian
34311819Sjulian/*
34411819Sjulian * Return address info for specified internet network.
34511819Sjulian */
34611819Sjulianstruct ipx_ifaddr *
34711819Sjulianipx_iaonnetof(dst)
34811819Sjulian	register struct ipx_addr *dst;
34911819Sjulian{
35011819Sjulian	register struct ipx_ifaddr *ia;
35111819Sjulian	register struct ipx_addr *compare;
35211819Sjulian	register struct ifnet *ifp;
35311819Sjulian	struct ipx_ifaddr *ia_maybe = 0;
35411819Sjulian	union ipx_net net = dst->x_net;
35511819Sjulian
35611819Sjulian	for (ia = ipx_ifaddr; ia; ia = ia->ia_next) {
35711819Sjulian		if ((ifp = ia->ia_ifp)) {
35811819Sjulian			if (ifp->if_flags & IFF_POINTOPOINT) {
35911819Sjulian				compare = &satoipx_addr(ia->ia_dstaddr);
36011819Sjulian				if (ipx_hosteq(*dst, *compare))
36111819Sjulian					return (ia);
36211819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
36311819Sjulian					ia_maybe = ia;
36411819Sjulian			} else {
36511819Sjulian				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
36611819Sjulian					return (ia);
36711819Sjulian			}
36811819Sjulian		}
36911819Sjulian	}
37011819Sjulian	return (ia_maybe);
37111819Sjulian}
37211819Sjulian#endif
373