ipx.c revision 165899
1/*-
2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * Copyright (c) 1995, Mike Mitchell
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 *    notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 *    notice, this list of conditions and the following disclaimer in the
38 *    documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 *    must display the following acknowledgement:
41 *	This product includes software developed by the University of
42 *	California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 *    may be used to endorse or promote products derived from this software
45 *    without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 *	@(#)ipx.c
60 */
61
62#include <sys/cdefs.h>
63__FBSDID("$FreeBSD: head/sys/netipx/ipx.c 165899 2007-01-08 22:14:00Z rwatson $");
64
65#include <sys/param.h>
66#include <sys/kernel.h>
67#include <sys/systm.h>
68#include <sys/malloc.h>
69#include <sys/sockio.h>
70#include <sys/socket.h>
71
72#include <net/if.h>
73#include <net/route.h>
74
75#include <netipx/ipx.h>
76#include <netipx/ipx_if.h>
77#include <netipx/ipx_var.h>
78
79/*
80 * XXXRW: Requires synchronization.
81 */
82struct ipx_ifaddr *ipx_ifaddr;
83
84static	void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
85static	int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
86		       struct sockaddr_ipx *sipx, int scrub);
87
88/*
89 * Generic internet control operations (ioctl's).
90 */
91int
92ipx_control(so, cmd, data, ifp, td)
93	struct socket *so;
94	u_long cmd;
95	caddr_t data;
96	register struct ifnet *ifp;
97	struct thread *td;
98{
99	register struct ifreq *ifr = (struct ifreq *)data;
100	register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
101	register struct ipx_ifaddr *ia;
102	struct ifaddr *ifa;
103	struct ipx_ifaddr *oia;
104	int dstIsNew, hostIsNew;
105	int error = 0;
106
107	/*
108	 * Find address for this interface, if it exists.
109	 */
110	if (ifp == NULL)
111		return (EADDRNOTAVAIL);
112	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
113		if (ia->ia_ifp == ifp)
114			break;
115
116	switch (cmd) {
117
118	case SIOCGIFADDR:
119		if (ia == NULL)
120			return (EADDRNOTAVAIL);
121		*(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
122		return (0);
123
124	case SIOCGIFBRDADDR:
125		if (ia == NULL)
126			return (EADDRNOTAVAIL);
127		if ((ifp->if_flags & IFF_BROADCAST) == 0)
128			return (EINVAL);
129		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
130		return (0);
131
132	case SIOCGIFDSTADDR:
133		if (ia == NULL)
134			return (EADDRNOTAVAIL);
135		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
136			return (EINVAL);
137		*(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
138		return (0);
139	}
140
141	if (td && (error = suser(td)) != 0)
142		return (error);
143
144	switch (cmd) {
145	case SIOCAIFADDR:
146	case SIOCDIFADDR:
147		if (ifra->ifra_addr.sipx_family == AF_IPX)
148		    for (oia = ia; ia != NULL; ia = ia->ia_next) {
149			if (ia->ia_ifp == ifp  &&
150			    ipx_neteq(ia->ia_addr.sipx_addr,
151				  ifra->ifra_addr.sipx_addr))
152			    break;
153		    }
154		if (cmd == SIOCDIFADDR && ia == NULL)
155			return (EADDRNOTAVAIL);
156		/* FALLTHROUGH */
157
158	case SIOCSIFADDR:
159	case SIOCSIFDSTADDR:
160		if (ia == NULL) {
161			oia = (struct ipx_ifaddr *)
162				malloc(sizeof(*ia), M_IFADDR,
163				M_WAITOK | M_ZERO);
164			if (oia == NULL)
165				return (ENOBUFS);
166			if ((ia = ipx_ifaddr) != NULL) {
167				for ( ; ia->ia_next != NULL; ia = ia->ia_next)
168					;
169				ia->ia_next = oia;
170			} else
171				ipx_ifaddr = oia;
172			ia = oia;
173			ifa = (struct ifaddr *)ia;
174			IFA_LOCK_INIT(ifa);
175			ifa->ifa_refcnt = 1;
176			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
177			ia->ia_ifp = ifp;
178			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
179
180			ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
181
182			ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
183			if (ifp->if_flags & IFF_BROADCAST) {
184				ia->ia_broadaddr.sipx_family = AF_IPX;
185				ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
186				ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
187			}
188		}
189	}
190
191	switch (cmd) {
192
193	case SIOCSIFDSTADDR:
194		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
195			return (EINVAL);
196		if (ia->ia_flags & IFA_ROUTE) {
197			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
198			ia->ia_flags &= ~IFA_ROUTE;
199		}
200		if (ifp->if_ioctl) {
201			error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
202			if (error)
203				return (error);
204		}
205		*(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
206		return (0);
207
208	case SIOCSIFADDR:
209		return (ipx_ifinit(ifp, ia,
210				(struct sockaddr_ipx *)&ifr->ifr_addr, 1));
211
212	case SIOCDIFADDR:
213		ipx_ifscrub(ifp, ia);
214		ifa = (struct ifaddr *)ia;
215		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
216		oia = ia;
217		if (oia == (ia = ipx_ifaddr)) {
218			ipx_ifaddr = ia->ia_next;
219		} else {
220			while (ia->ia_next && (ia->ia_next != oia)) {
221				ia = ia->ia_next;
222			}
223			if (ia->ia_next)
224			    ia->ia_next = oia->ia_next;
225			else
226				printf("Didn't unlink ipxifadr from list\n");
227		}
228		IFAFREE((&oia->ia_ifa));
229		return (0);
230
231	case SIOCAIFADDR:
232		dstIsNew = 0;
233		hostIsNew = 1;
234		if (ia->ia_addr.sipx_family == AF_IPX) {
235			if (ifra->ifra_addr.sipx_len == 0) {
236				ifra->ifra_addr = ia->ia_addr;
237				hostIsNew = 0;
238			} else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
239					 ia->ia_addr.sipx_addr))
240				hostIsNew = 0;
241		}
242		if ((ifp->if_flags & IFF_POINTOPOINT) &&
243		    (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
244			if (hostIsNew == 0)
245				ipx_ifscrub(ifp, ia);
246			ia->ia_dstaddr = ifra->ifra_dstaddr;
247			dstIsNew  = 1;
248		}
249		if (ifra->ifra_addr.sipx_family == AF_IPX &&
250					    (hostIsNew || dstIsNew))
251			error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
252		return (error);
253
254	default:
255		if (ifp->if_ioctl == NULL)
256			return (EOPNOTSUPP);
257		return ((*ifp->if_ioctl)(ifp, cmd, data));
258	}
259}
260
261/*
262* Delete any previous route for an old address.
263*/
264static void
265ipx_ifscrub(ifp, ia)
266	register struct ifnet *ifp;
267	register struct ipx_ifaddr *ia;
268{
269	if (ia->ia_flags & IFA_ROUTE) {
270		if (ifp->if_flags & IFF_POINTOPOINT) {
271			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
272		} else
273			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
274		ia->ia_flags &= ~IFA_ROUTE;
275	}
276}
277/*
278 * Initialize an interface's internet address
279 * and routing table entry.
280 */
281static int
282ipx_ifinit(ifp, ia, sipx, scrub)
283	register struct ifnet *ifp;
284	register struct ipx_ifaddr *ia;
285	register struct sockaddr_ipx *sipx;
286	int scrub;
287{
288	struct sockaddr_ipx oldaddr;
289	int s = splimp(), error;
290
291	/*
292	 * Set up new addresses.
293	 */
294	oldaddr = ia->ia_addr;
295	ia->ia_addr = *sipx;
296
297	/*
298	 * The convention we shall adopt for naming is that
299	 * a supplied address of zero means that "we don't care".
300	 * Use the MAC address of the interface. If it is an
301	 * interface without a MAC address, like a serial line, the
302	 * address must be supplied.
303	 *
304	 * Give the interface a chance to initialize
305	 * if this is its first address,
306	 * and to validate the address if necessary.
307	 */
308	if (ifp->if_ioctl != NULL &&
309	    (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
310		ia->ia_addr = oldaddr;
311		splx(s);
312		return (error);
313	}
314	splx(s);
315	ia->ia_ifa.ifa_metric = ifp->if_metric;
316	/*
317	 * Add route for the network.
318	 */
319	if (scrub) {
320		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
321		ipx_ifscrub(ifp, ia);
322		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
323	}
324	if (ifp->if_flags & IFF_POINTOPOINT)
325		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
326	else {
327		ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
328		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
329	}
330	ia->ia_flags |= IFA_ROUTE;
331	return (0);
332}
333
334/*
335 * Return address info for specified internet network.
336 */
337struct ipx_ifaddr *
338ipx_iaonnetof(dst)
339	register struct ipx_addr *dst;
340{
341	register struct ipx_ifaddr *ia;
342	register struct ipx_addr *compare;
343	register struct ifnet *ifp;
344	struct ipx_ifaddr *ia_maybe = NULL;
345	union ipx_net net = dst->x_net;
346
347	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
348		if ((ifp = ia->ia_ifp) != NULL) {
349			if (ifp->if_flags & IFF_POINTOPOINT) {
350				compare = &satoipx_addr(ia->ia_dstaddr);
351				if (ipx_hosteq(*dst, *compare))
352					return (ia);
353				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
354					ia_maybe = ia;
355			} else {
356				if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
357					return (ia);
358			}
359		}
360	}
361	return (ia_maybe);
362}
363
364
365void
366ipx_printhost(addr)
367register struct ipx_addr *addr;
368{
369	u_short port;
370	struct ipx_addr work = *addr;
371	register char *p; register u_char *q;
372	register char *net = "", *host = "";
373	char cport[10], chost[15], cnet[15];
374
375	port = ntohs(work.x_port);
376
377	if (ipx_nullnet(work) && ipx_nullhost(work)) {
378
379		if (port)
380			printf("*.%x", port);
381		else
382			printf("*.*");
383
384		return;
385	}
386
387	if (ipx_wildnet(work))
388		net = "any";
389	else if (ipx_nullnet(work))
390		net = "*";
391	else {
392		q = work.x_net.c_net;
393		snprintf(cnet, sizeof(cnet), "%x%x%x%x",
394			q[0], q[1], q[2], q[3]);
395		for (p = cnet; *p == '0' && p < cnet + 8; p++)
396			continue;
397		net = p;
398	}
399
400	if (ipx_wildhost(work))
401		host = "any";
402	else if (ipx_nullhost(work))
403		host = "*";
404	else {
405		q = work.x_host.c_host;
406		snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
407			q[0], q[1], q[2], q[3], q[4], q[5]);
408		for (p = chost; *p == '0' && p < chost + 12; p++)
409			continue;
410		host = p;
411	}
412
413	if (port) {
414		if (strcmp(host, "*") == 0) {
415			host = "";
416			snprintf(cport, sizeof(cport), "%x", port);
417		} else
418			snprintf(cport, sizeof(cport), ".%x", port);
419	} else
420		*cport = 0;
421
422	printf("%s.%s%s", net, host, cport);
423}
424