ipx.c revision 67893
1251876Speter/*
2251876Speter * Copyright (c) 1995, Mike Mitchell
3251876Speter * Copyright (c) 1984, 1985, 1986, 1987, 1993
4251876Speter *	The Regents of the University of California.  All rights reserved.
5251876Speter *
6251876Speter * Redistribution and use in source and binary forms, with or without
7251876Speter * modification, are permitted provided that the following conditions
8251876Speter * are met:
9251876Speter * 1. Redistributions of source code must retain the above copyright
10251876Speter *    notice, this list of conditions and the following disclaimer.
11251876Speter * 2. Redistributions in binary form must reproduce the above copyright
12251876Speter *    notice, this list of conditions and the following disclaimer in the
13251876Speter *    documentation and/or other materials provided with the distribution.
14251876Speter * 3. All advertising materials mentioning features or use of this software
15251876Speter *    must display the following acknowledgement:
16251876Speter *	This product includes software developed by the University of
17251876Speter *	California, Berkeley and its contributors.
18251876Speter * 4. Neither the name of the University nor the names of its contributors
19251876Speter *    may be used to endorse or promote products derived from this software
20251876Speter *    without specific prior written permission.
21251876Speter *
22251876Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23251876Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24251876Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25251876Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26251876Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27251876Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28251876Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29251876Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30251876Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31251876Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32251876Speter * SUCH DAMAGE.
33251876Speter *
34251876Speter *	@(#)ipx.c
35251876Speter *
36251876Speter * $FreeBSD: head/sys/netipx/ipx.c 67893 2000-10-29 16:06:56Z phk $
37251876Speter */
38251876Speter
39251876Speter#include <sys/param.h>
40251876Speter#include <sys/systm.h>
41251876Speter#include <sys/malloc.h>
42251876Speter#include <sys/sockio.h>
43251876Speter#include <sys/socket.h>
44251876Speter
45251876Speter#include <net/if.h>
46251876Speter#include <net/route.h>
47251876Speter
48251876Speter#include <netipx/ipx.h>
49251876Speter#include <netipx/ipx_if.h>
50251876Speter#include <netipx/ipx_var.h>
51251876Speter
52251876Speterstruct ipx_ifaddr *ipx_ifaddr;
53251876Speter
54251876Speterstatic	void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
55251876Speterstatic	int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
56251876Speter		       struct sockaddr_ipx *sipx, int scrub);
57251876Speter
58251876Speter/*
59251876Speter * Generic internet control operations (ioctl's).
60251876Speter */
61251876Speterint
62251876Speteripx_control(so, cmd, data, ifp, p)
63251876Speter	struct socket *so;
64251876Speter	u_long cmd;
65251876Speter	caddr_t data;
66251876Speter	register struct ifnet *ifp;
67251876Speter	struct proc *p;
68251876Speter{
69251876Speter	register struct ifreq *ifr = (struct ifreq *)data;
70251876Speter	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
71251876Speter	register struct ipx_ifaddr *ia;
72251876Speter	struct ifaddr *ifa;
73251876Speter	struct ipx_ifaddr *oia;
74251876Speter	int dstIsNew, hostIsNew;
75251876Speter	int error = 0;
76251876Speter
77251876Speter	/*
78251876Speter	 * Find address for this interface, if it exists.
79251876Speter	 */
80251876Speter	if (ifp == NULL)
81251876Speter		return (EADDRNOTAVAIL);
82251876Speter	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
83251876Speter		if (ia->ia_ifp == ifp)
84251876Speter			break;
85251876Speter
86251876Speter	switch (cmd) {
87251876Speter
88251876Speter	case SIOCGIFADDR:
89251876Speter		if (ia == NULL)
90251876Speter			return (EADDRNOTAVAIL);
91251876Speter		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
92251876Speter		return (0);
93251876Speter
94251876Speter	case SIOCGIFBRDADDR:
95251876Speter		if (ia == NULL)
96251876Speter			return (EADDRNOTAVAIL);
97251876Speter		if ((ifp->if_flags & IFF_BROADCAST) == 0)
98251876Speter			return (EINVAL);
99251876Speter		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
100251876Speter		return (0);
101251876Speter
102251876Speter	case SIOCGIFDSTADDR:
103251876Speter		if (ia == NULL)
104251876Speter			return (EADDRNOTAVAIL);
105251876Speter		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
106251876Speter			return (EINVAL);
107251876Speter		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
108251876Speter		return (0);
109251876Speter	}
110251876Speter
111251876Speter	if (p && (error = suser(p)) != 0)
112251876Speter		return (error);
113251876Speter
114251876Speter	switch (cmd) {
115251876Speter	case SIOCAIFADDR:
116251876Speter	case SIOCDIFADDR:
117251876Speter		if (ifra->ifra_addr.sipx_family == AF_IPX)
118251876Speter		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
119251876Speter			if (ia->ia_ifp == ifp  &&
120251876Speter			    ipx_neteq(ia->ia_addr.sipx_addr,
121251876Speter				  ifra->ifra_addr.sipx_addr))
122251876Speter			    break;
123251876Speter		    }
124251876Speter		if (cmd == SIOCDIFADDR && ia == NULL)
125251876Speter			return (EADDRNOTAVAIL);
126251876Speter		/* FALLTHROUGH */
127251876Speter
128251876Speter	case SIOCSIFADDR:
129251876Speter	case SIOCSIFDSTADDR:
130251876Speter		if (ia == NULL) {
131251876Speter			oia = (struct ipx_ifaddr *)
132251876Speter				malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
133251876Speter			if (oia == NULL)
134251876Speter				return (ENOBUFS);
135251876Speter			bzero((caddr_t)oia, sizeof(*oia));
136251876Speter			if ((ia = ipx_ifaddr) != NULL) {
137251876Speter				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
138251876Speter					;
139251876Speter				ia->ia_next = oia;
140251876Speter			} else
141251876Speter				ipx_ifaddr = oia;
142251876Speter			ia = oia;
143251876Speter			ifa = (struct ifaddr *)ia;
144251876Speter			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
145251876Speter			ia->ia_ifp = ifp;
146251876Speter			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
147251876Speter
148251876Speter			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
149251876Speter
150251876Speter			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
151251876Speter			if (ifp->if_flags & IFF_BROADCAST) {
152251876Speter				ia->ia_broadaddr.sipx_family = AF_IPX;
153251876Speter				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
154251876Speter				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
155251876Speter			}
156251876Speter		}
157251876Speter	}
158251876Speter
159251876Speter	switch (cmd) {
160251876Speter
161251876Speter	case SIOCSIFDSTADDR:
162251876Speter		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
163251876Speter			return (EINVAL);
164251876Speter		if (ia->ia_flags & IFA_ROUTE) {
165251876Speter			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
166251876Speter			ia->ia_flags &= ~IFA_ROUTE;
167251876Speter		}
168251876Speter		if (ifp->if_ioctl) {
169251876Speter			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
170251876Speter			if (error)
171251876Speter				return (error);
172251876Speter		}
173251876Speter		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
174251876Speter		return (0);
175251876Speter
176251876Speter	case SIOCSIFADDR:
177251876Speter		return (ipx_ifinit(ifp, ia,
178251876Speter				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
179251876Speter
180251876Speter	case SIOCDIFADDR:
181251876Speter		ipx_ifscrub(ifp, ia);
182251876Speter		ifa = (struct ifaddr *)ia;
183251876Speter		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
184251876Speter		oia = ia;
185251876Speter		if (oia == (ia = ipx_ifaddr)) {
186251876Speter			ipx_ifaddr = ia->ia_next;
187251876Speter		} else {
188251876Speter			while (ia->ia_next && (ia->ia_next != oia)) {
189251876Speter				ia = ia->ia_next;
190251876Speter			}
191251876Speter			if (ia->ia_next)
192251876Speter			    ia->ia_next = oia->ia_next;
193251876Speter			else
194251876Speter				printf("Didn't unlink ipxifadr from list\n");
195251876Speter		}
196251876Speter		IFAFREE((&oia->ia_ifa));
197251876Speter		return (0);
198251876Speter
199251876Speter	case SIOCAIFADDR:
200251876Speter		dstIsNew = 0;
201251876Speter		hostIsNew = 1;
202251876Speter		if (ia->ia_addr.sipx_family == AF_IPX) {
203251876Speter			if (ifra->ifra_addr.sipx_len == 0) {
204251876Speter				ifra->ifra_addr = ia->ia_addr;
205251876Speter				hostIsNew = 0;
206251876Speter			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
207251876Speter					 ia->ia_addr.sipx_addr))
208251876Speter				hostIsNew = 0;
209251876Speter		}
210251876Speter		if ((ifp->if_flags & IFF_POINTOPOINT) &&
211251876Speter		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
212251876Speter			if (hostIsNew == 0)
213251876Speter				ipx_ifscrub(ifp, ia);
214251876Speter			ia->ia_dstaddr = ifra->ifra_dstaddr;
215251876Speter			dstIsNew  = 1;
216251876Speter		}
217251876Speter		if (ifra->ifra_addr.sipx_family == AF_IPX &&
218251876Speter					    (hostIsNew || dstIsNew))
219251876Speter			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
220251876Speter		return (error);
221251876Speter
222251876Speter	default:
223251876Speter		if (ifp->if_ioctl == NULL)
224251876Speter			return (EOPNOTSUPP);
225251876Speter		return ((*ifp->if_ioctl)(ifp, cmd, data));
226251876Speter	}
227251876Speter}
228251876Speter
229251876Speter/*
230251876Speter* Delete any previous route for an old address.
231251876Speter*/
232251876Speterstatic void
233251876Speteripx_ifscrub(ifp, ia)
234251876Speter	register struct ifnet *ifp;
235251876Speter	register struct ipx_ifaddr *ia;
236251876Speter{
237251876Speter	if (ia->ia_flags & IFA_ROUTE) {
238251876Speter		if (ifp->if_flags & IFF_POINTOPOINT) {
239251876Speter			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
240251876Speter		} else
241251876Speter			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
242251876Speter		ia->ia_flags &= ~IFA_ROUTE;
243251876Speter	}
244251876Speter}
245251876Speter/*
246251876Speter * Initialize an interface's internet address
247251876Speter * and routing table entry.
248251876Speter */
249251876Speterstatic int
250251876Speteripx_ifinit(ifp, ia, sipx, scrub)
251251876Speter	register struct ifnet *ifp;
252251876Speter	register struct ipx_ifaddr *ia;
253251876Speter	register struct sockaddr_ipx *sipx;
254251876Speter	int scrub;
255251876Speter{
256251876Speter	struct sockaddr_ipx oldaddr;
257251876Speter	int s = splimp(), error;
258251876Speter
259251876Speter	/*
260251876Speter	 * Set up new addresses.
261251876Speter	 */
262251876Speter	oldaddr = ia->ia_addr;
263251876Speter	ia->ia_addr = *sipx;
264251876Speter
265251876Speter	/*
266251876Speter	 * The convention we shall adopt for naming is that
267251876Speter	 * a supplied address of zero means that "we don't care".
268251876Speter	 * Use the MAC address of the interface. If it is an
269251876Speter	 * interface without a MAC address, like a serial line, the
270251876Speter	 * address must be supplied.
271251876Speter	 *
272251876Speter	 * Give the interface a chance to initialize
273251876Speter	 * if this is its first address,
274251876Speter	 * and to validate the address if necessary.
275251876Speter	 */
276251876Speter	if (ifp->if_ioctl != NULL &&
277251876Speter	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
278251876Speter		ia->ia_addr = oldaddr;
279251876Speter		splx(s);
280251876Speter		return (error);
281251876Speter	}
282251876Speter	splx(s);
283251876Speter	ia->ia_ifa.ifa_metric = ifp->if_metric;
284251876Speter	/*
285251876Speter	 * Add route for the network.
286251876Speter	 */
287251876Speter	if (scrub) {
288251876Speter		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
289251876Speter		ipx_ifscrub(ifp, ia);
290251876Speter		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
291251876Speter	}
292251876Speter	if (ifp->if_flags & IFF_POINTOPOINT)
293251876Speter		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
294251876Speter	else {
295251876Speter		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
296251876Speter		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
297251876Speter	}
298251876Speter	ia->ia_flags |= IFA_ROUTE;
299251876Speter	return (0);
300251876Speter}
301251876Speter
302251876Speter/*
303251876Speter * Return address info for specified internet network.
304251876Speter */
305251876Speterstruct ipx_ifaddr *
306251876Speteripx_iaonnetof(dst)
307251876Speter	register struct ipx_addr *dst;
308251876Speter{
309251876Speter	register struct ipx_ifaddr *ia;
310251876Speter	register struct ipx_addr *compare;
311251876Speter	register struct ifnet *ifp;
312251876Speter	struct ipx_ifaddr *ia_maybe = NULL;
313251876Speter	union ipx_net net = dst->x_net;
314251876Speter
315251876Speter	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
316251876Speter		if ((ifp = ia->ia_ifp) != NULL) {
317251876Speter			if (ifp->if_flags & IFF_POINTOPOINT) {
318251876Speter				compare = &satoipx_addr(ia->ia_dstaddr);
319251876Speter				if (ipx_hosteq(*dst, *compare))
320251876Speter					return (ia);
321251876Speter				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
322251876Speter					ia_maybe = ia;
323251876Speter			} else {
324251876Speter				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
325251876Speter					return (ia);
326251876Speter			}
327251876Speter		}
328251876Speter	}
329251876Speter	return (ia_maybe);
330251876Speter}
331251876Speter
332251876Speter
333251876Spetervoid
334251876Speteripx_printhost(addr)
335251876Speterregister struct ipx_addr *addr;
336251876Speter{
337251876Speter	u_short port;
338251876Speter	struct ipx_addr work = *addr;
339251876Speter	register char *p; register u_char *q;
340251876Speter	register char *net = "", *host = "";
341251876Speter	char cport[10], chost[15], cnet[15];
342251876Speter
343251876Speter	port = ntohs(work.x_port);
344251876Speter
345251876Speter	if (ipx_nullnet(work) && ipx_nullhost(work)) {
346251876Speter
347251876Speter		if (port)
348251876Speter			printf("*.%x", port);
349251876Speter		else
350251876Speter			printf("*.*");
351251876Speter
352251876Speter		return;
353251876Speter	}
354251876Speter
355251876Speter	if (ipx_wildnet(work))
356251876Speter		net = "any";
357251876Speter	else if (ipx_nullnet(work))
358251876Speter		net = "*";
359251876Speter	else {
360251876Speter		q = work.x_net.c_net;
361251876Speter		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
362251876Speter			q[0], q[1], q[2], q[3]);
363251876Speter		for (p = cnet; *p == '0' && p < cnet + 8; p++)
364251876Speter			continue;
365251876Speter		net = p;
366253734Speter	}
367251876Speter
368251876Speter	if (ipx_wildhost(work))
369251876Speter		host = "any";
370251876Speter	else if (ipx_nullhost(work))
371251876Speter		host = "*";
372251876Speter	else {
373251876Speter		q = work.x_host.c_host;
374251876Speter		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
375251876Speter			q[0], q[1], q[2], q[3], q[4], q[5]);
376251876Speter		for (p = chost; *p == '0' && p < chost + 12; p++)
377251876Speter			continue;
378251876Speter		host = p;
379251876Speter	}
380251876Speter
381251876Speter	if (port) {
382251876Speter		if (strcmp(host, "*") == 0) {
383251876Speter			host = "";
384251876Speter			snprintf(cport, sizeof(cport), "%x", port);
385251876Speter		} else
386251876Speter			snprintf(cport, sizeof(cport), ".%x", port);
387251876Speter	} else
388251876Speter		*cport = 0;
389251876Speter
390251876Speter	printf("%s.%s%s", net, host, cport);
391251876Speter}
392251876Speter