1/*	$NetBSD: iso.c,v 1.57 2009/08/07 14:04:34 wiz Exp $	*/
2
3/*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*-
30 * Copyright (c) 1991, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the University nor the names of its contributors
42 *    may be used to endorse or promote products derived from this software
43 *    without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 *	@(#)iso.c	8.3 (Berkeley) 1/9/95
58 */
59
60/***********************************************************
61		Copyright IBM Corporation 1987
62
63                      All Rights Reserved
64
65Permission to use, copy, modify, and distribute this software and its
66documentation for any purpose and without fee is hereby granted,
67provided that the above copyright notice appear in all copies and that
68both that copyright notice and this permission notice appear in
69supporting documentation, and that the name of IBM not be
70used in advertising or publicity pertaining to distribution of the
71software without specific, written prior permission.
72
73IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
74ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
75IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
76ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
77WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
78ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
79SOFTWARE.
80
81******************************************************************/
82
83/*
84 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
85 */
86/*
87 * iso.c: miscellaneous routines to support the iso address family
88 */
89
90#include <sys/cdefs.h>
91__KERNEL_RCSID(0, "$NetBSD: iso.c,v 1.57 2009/08/07 14:04:34 wiz Exp $");
92
93#include <sys/param.h>
94#include <sys/systm.h>
95#include <sys/ioctl.h>
96#include <sys/mbuf.h>
97#include <sys/domain.h>
98#include <sys/protosw.h>
99#include <sys/socket.h>
100#include <sys/socketvar.h>
101#include <sys/errno.h>
102#include <sys/proc.h>
103#include <sys/kauth.h>
104
105#include <net/if.h>
106#include <net/if_types.h>
107#include <net/route.h>
108
109#include <netiso/iso.h>
110#include <netiso/iso_var.h>
111#include <netiso/iso_snpac.h>
112#include <netiso/iso_pcb.h>
113#include <netiso/clnp.h>
114#include <netiso/argo_debug.h>
115
116#include "opt_iso.h"
117#ifdef ISO
118
119int             iso_interfaces = 0;	/* number of external interfaces */
120
121/*
122 * FUNCTION:		iso_addrmatch1
123 *
124 * PURPOSE:		decide if the two iso_addrs passed are equal
125 *
126 * RETURNS:		true if the addrs match, false if they do not
127 *
128 * SIDE EFFECTS:
129 *
130 * NOTES:
131 */
132int
133iso_addrmatch1(const struct iso_addr *isoaa, const struct iso_addr *isoab)
134{
135	u_int           compare_len;
136
137#ifdef ARGO_DEBUG
138	if (argo_debug[D_ROUTE]) {
139		printf("iso_addrmatch1: comparing lengths: %d to %d\n", isoaa->isoa_len,
140		    isoab->isoa_len);
141		printf("a:\n");
142		dump_buf(isoaa->isoa_genaddr, isoaa->isoa_len);
143		printf("b:\n");
144		dump_buf(isoab->isoa_genaddr, isoab->isoa_len);
145	}
146#endif
147
148	if ((compare_len = isoaa->isoa_len) != isoab->isoa_len) {
149#ifdef ARGO_DEBUG
150		if (argo_debug[D_ROUTE]) {
151			printf("iso_addrmatch1: returning false because of lengths\n");
152		}
153#endif
154		return 0;
155	}
156#ifdef notdef
157	/* TODO : generalize this to all afis with masks */
158	if (isoaa->isoa_afi == AFI_37) {
159		/*
160		 * must not compare 2 least significant digits, or for that
161		 * matter, the DSP
162		 */
163		compare_len = ADDR37_IDI_LEN - 1;
164	}
165#endif
166
167#ifdef ARGO_DEBUG
168	if (argo_debug[D_ROUTE]) {
169		int             i;
170		const char           *a, *b;
171
172		a = isoaa->isoa_genaddr;
173		b = isoab->isoa_genaddr;
174
175		for (i = 0; i < compare_len; i++) {
176			printf("<%x=%x>", a[i] & 0xff, b[i] & 0xff);
177			if (a[i] != b[i]) {
178				printf("\naddrs are not equal at byte %d\n", i);
179				return (0);
180			}
181		}
182		printf("\n");
183		printf("addrs are equal\n");
184		return (1);
185	}
186#endif
187	return (!memcmp(isoaa->isoa_genaddr, isoab->isoa_genaddr, compare_len));
188}
189
190/*
191 * FUNCTION:		iso_addrmatch
192 *
193 * PURPOSE:		decide if the two sockadrr_isos passed are equal
194 *
195 * RETURNS:		true if the addrs match, false if they do not
196 *
197 * SIDE EFFECTS:
198 *
199 * NOTES:
200 */
201int
202iso_addrmatch(const struct sockaddr_iso *sisoa,
203	const struct sockaddr_iso *sisob)
204{
205	return (iso_addrmatch1(&sisoa->siso_addr, &sisob->siso_addr));
206}
207#ifdef notdef
208/*
209 * FUNCTION:		iso_netmatch
210 *
211 * PURPOSE:		similar to iso_addrmatch but takes sockaddr_iso
212 *			as argument.
213 *
214 * RETURNS:		true if same net, false if not
215 *
216 * SIDE EFFECTS:
217 *
218 * NOTES:
219 */
220int
221iso_netmatch(const struct sockaddr_iso *sisoa,
222	const struct sockaddr_iso *sisob)
223{
224	u_char          bufa[sizeof(struct sockaddr_iso)];
225	u_char          bufb[sizeof(struct sockaddr_iso)];
226	int    lena, lenb;
227
228	lena = iso_netof(&sisoa->siso_addr, bufa);
229	lenb = iso_netof(&sisob->siso_addr, bufb);
230
231#ifdef ARGO_DEBUG
232	if (argo_debug[D_ROUTE]) {
233		printf("iso_netmatch: comparing lengths: %d to %d\n", lena, lenb);
234		printf("a:\n");
235		dump_buf(bufa, lena);
236		printf("b:\n");
237		dump_buf(bufb, lenb);
238	}
239#endif
240
241	return ((lena == lenb) && (!memcmp(bufa, bufb, lena)));
242}
243#endif /* notdef */
244
245/*
246 * FUNCTION:		iso_hashchar
247 *
248 * PURPOSE:		Hash all character in the buffer specified into
249 *			a long. Return the long.
250 *
251 * RETURNS:		The hash value.
252 *
253 * SIDE EFFECTS:
254 *
255 * NOTES:		The hash is achieved by exclusive ORing 4 byte
256 *			quantities.
257 */
258u_long
259iso_hashchar(void *bufv, int len)
260{
261	char *buf = bufv;
262	u_long h = 0;
263	int    i;
264
265	for (i = 0; i < len; i += 4) {
266		u_long l = 0;
267
268		if ((len - i) < 4) {
269			/* buffer not multiple of 4 */
270			switch (len - i) {
271			case 3:
272				l |= buf[i + 2] << 8;
273			case 2:
274				l |= buf[i + 1] << 16;
275			case 1:
276				l |= buf[i] << 24;
277				break;
278			default:
279				printf("iso_hashchar: unexpected value x%x\n", len - i);
280				break;
281			}
282		} else {
283			l |= buf[i] << 24;
284			l |= buf[i + 1] << 16;
285			l |= buf[i + 2] << 8;
286			l |= buf[i + 3];
287		}
288
289		h ^= l;
290	}
291
292	h ^= (u_long) (len % 4);
293
294	return (h);
295}
296
297#ifdef notdef
298/*
299 * FUNCTION:		iso_hash
300 *
301 * PURPOSE:		Fill in fields of afhash structure based upon addr
302 *			passed.
303 *
304 * RETURNS:		none
305 *
306 * SIDE EFFECTS:
307 *
308 * NOTES:
309 */
310void
311iso_hash(
312	struct sockaddr_iso *siso,	/* address to perform hash on */
313	struct afhash  *hp)	/* RETURN: hash info here */
314{
315	u_long buf[sizeof(struct sockaddr_iso) / 4 + 1];
316	int    bufsize;
317
318
319	memset(buf, 0, sizeof(buf));
320
321	bufsize = iso_netof(&siso->siso_addr, buf);
322	hp->afh_nethash = iso_hashchar((void *) buf, bufsize);
323
324#ifdef ARGO_DEBUG
325	if (argo_debug[D_ROUTE]) {
326		printf("iso_hash: iso_netof: bufsize = %d\n", bufsize);
327	}
328#endif
329
330	hp->afh_hosthash = iso_hashchar((void *) & siso->siso_addr,
331					siso->siso_addr.isoa_len);
332
333#ifdef ARGO_DEBUG
334	if (argo_debug[D_ROUTE]) {
335		printf("iso_hash: %s: nethash = x%x, hosthash = x%x\n",
336		    clnp_iso_addrp(&siso->siso_addr), hp->afh_nethash,
337		    hp->afh_hosthash);
338	}
339#endif
340}
341/*
342 * FUNCTION:		iso_netof
343 *
344 * PURPOSE:		Extract the network portion of the iso address.
345 *			The network portion of the iso address varies depending
346 *			on the type of address. The network portion of the
347 *			address will include the IDP. The network portion is:
348 *
349 *			TYPE			DESC
350 *			t37			The AFI and x.121 (IDI)
351 *			osinet			The AFI, orgid, snetid
352 *			rfc986			The AFI, vers and network part
353 *						of internet address.
354 *
355 * RETURNS:		number of bytes placed into buf.
356 *
357 * SIDE EFFECTS:
358 *
359 * NOTES:		Buf is assumed to be big enough
360 */
361u_int
362iso_netof(
363	struct iso_addr *isoa,	/* address */
364	void *        buf)	/* RESULT: network portion of address here */
365{
366	u_int           len = 1;/* length of afi */
367
368	switch (isoa->isoa_afi) {
369	case AFI_37:
370		/*
371		 * Due to classic x.25 tunnel vision, there is no
372		 * net portion of an x.121 address.  For our purposes
373		 * the AFI will do, so that all x.25 -type addresses
374		 * map to the single x.25 SNPA. (Cannot have more than
375		 * one, obviously).
376		 */
377
378		break;
379
380		/* case AFI_OSINET: */
381	case AFI_RFC986:{
382			u_short         idi;	/* value of idi */
383
384			/* osinet and rfc986 have idi in the same place */
385			CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi);
386
387			if (idi == IDI_OSINET)
388				/*
389				 * Network portion of OSINET address can only
390				 * be the IDI. Clearly, with one x25 interface,
391				 * one could get to several orgids, and
392				 * several snetids.
393				 */
394#if 0
395				len += (ADDROSINET_IDI_LEN +
396					OVLOSINET_ORGID_LEN +
397					OVLOSINET_SNETID_LEN);
398#endif
399				len += ADDROSINET_IDI_LEN;
400			else if (idi == IDI_RFC986) {
401				struct ovl_rfc986 *o986 =
402					(struct ovl_rfc986 *) isoa;
403
404				/*
405				 * bump len to include idi and version (1
406				 * byte)
407				 */
408				len += ADDRRFC986_IDI_LEN + 1;
409
410#ifdef ARGO_DEBUG
411				if (argo_debug[D_ROUTE]) {
412					printf("iso_netof: isoa ");
413					dump_buf(isoa, sizeof(*isoa));
414					printf("iso_netof: inetaddr 0x%x ",
415					    inetaddr);
416				}
417#endif
418
419				/*
420				 * bump len by size of network portion of
421				 * inet address
422				 */
423				if (IN_CLASSA(o986->o986_inetaddr)) {
424					len += 4 - IN_CLASSA_NSHIFT / 8;
425#ifdef ARGO_DEBUG
426					if (argo_debug[D_ROUTE]) {
427						printf("iso_netof: class A net len is now %d\n", len);
428					}
429#endif
430				} else if (IN_CLASSB(o986->o986_inetaddr)) {
431					len += 4 - IN_CLASSB_NSHIFT / 8;
432#ifdef ARGO_DEBUG
433					if (argo_debug[D_ROUTE]) {
434						printf("iso_netof: class B net len is now %d\n", len);
435					}
436#endif
437				} else {
438					len += 4 - IN_CLASSC_NSHIFT / 8;
439#ifdef ARGO_DEBUG
440					if (argo_debug[D_ROUTE]) {
441						printf("iso_netof: class C net len is now %d\n", len);
442					}
443#endif
444				}
445			} else
446				len = 0;
447		} break;
448
449	default:
450		len = 0;
451	}
452
453	memcpy(buf, (void *) isoa, len);
454#ifdef ARGO_DEBUG
455	if (argo_debug[D_ROUTE]) {
456		printf("iso_netof: isoa ");
457		dump_buf(isoa, len);
458		printf("iso_netof: net ");
459		dump_buf(buf, len);
460	}
461#endif
462	return len;
463}
464#endif				/* notdef */
465/*
466 * Generic iso control operations (ioctl's).
467 * Ifp is 0 if not an interface-specific ioctl.
468 */
469/* ARGSUSED */
470int
471iso_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp,
472	struct lwp *l)
473{
474	struct iso_ifreq *ifr = (struct iso_ifreq *) data;
475	struct iso_ifaddr *ia = 0;
476	struct iso_aliasreq *ifra = (struct iso_aliasreq *) data;
477	int             error, hostIsNew, maskIsNew;
478
479	/*
480	 * Find address for this interface, if it exists.
481	 */
482	if (ifp)
483		TAILQ_FOREACH(ia, &iso_ifaddr, ia_list)
484			if (ia->ia_ifp == ifp)
485				break;
486
487	switch (cmd) {
488
489	case SIOCAIFADDR_ISO:
490	case SIOCDIFADDR_ISO:
491		if (ifra->ifra_addr.siso_family == AF_ISO)
492			for (; ia != 0; ia = ia->ia_list.tqe_next) {
493				if (ia->ia_ifp == ifp &&
494				    SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr))
495					break;
496			}
497		if (cmd == SIOCDIFADDR_ISO && ia == 0)
498			return (EADDRNOTAVAIL);
499		/* FALLTHROUGH */
500#if 0
501	case SIOCSIFADDR:
502	case SIOCSIFNETMASK:
503	case SIOCSIFDSTADDR:
504#endif
505		if (l == 0 || kauth_authorize_network(l->l_cred,
506		    KAUTH_NETWORK_INTERFACE,
507		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
508		    NULL))
509			return (EPERM);
510
511		if (ifp == 0)
512			panic("iso_control");
513		if (ia == 0) {
514			ia = malloc(sizeof(*ia),
515			       M_IFADDR, M_WAITOK|M_ZERO);
516			if (ia == 0)
517				return (ENOBUFS);
518			TAILQ_INSERT_TAIL(&iso_ifaddr, ia, ia_list);
519			IFAREF(&ia->ia_ifa);
520			ifa_insert(ifp, &ia->ia_ifa);
521			ia->ia_ifa.ifa_addr = sisotosa(&ia->ia_addr);
522			ia->ia_ifa.ifa_dstaddr = sisotosa(&ia->ia_dstaddr);
523			ia->ia_ifa.ifa_netmask = sisotosa(&ia->ia_sockmask);
524			ia->ia_ifp = ifp;
525			if ((ifp->if_flags & IFF_LOOPBACK) == 0)
526				iso_interfaces++;
527		}
528		break;
529
530	case SIOCGIFADDR_ISO:
531	case SIOCGIFNETMASK_ISO:
532	case SIOCGIFDSTADDR_ISO:
533		if (ia == 0)
534			return (EADDRNOTAVAIL);
535		break;
536	}
537	switch (cmd) {
538
539	case SIOCGIFADDR_ISO:
540		ifr->ifr_Addr = ia->ia_addr;
541		break;
542
543	case SIOCGIFDSTADDR_ISO:
544		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
545			return (EINVAL);
546		ifr->ifr_Addr = ia->ia_dstaddr;
547		break;
548
549	case SIOCGIFNETMASK_ISO:
550		ifr->ifr_Addr = ia->ia_sockmask;
551		break;
552
553	case SIOCAIFADDR_ISO:
554		maskIsNew = 0;
555		hostIsNew = 1;
556		error = 0;
557		if (ia->ia_addr.siso_family == AF_ISO) {
558			if (ifra->ifra_addr.siso_len == 0) {
559				ifra->ifra_addr = ia->ia_addr;
560				hostIsNew = 0;
561			} else if (SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr))
562				hostIsNew = 0;
563		}
564		if (ifra->ifra_mask.siso_len) {
565			iso_ifscrub(ifp, ia);
566			ia->ia_sockmask = ifra->ifra_mask;
567			maskIsNew = 1;
568		}
569		if ((ifp->if_flags & IFF_POINTOPOINT) &&
570		    (ifra->ifra_dstaddr.siso_family == AF_ISO)) {
571			iso_ifscrub(ifp, ia);
572			ia->ia_dstaddr = ifra->ifra_dstaddr;
573			maskIsNew = 1;	/* We lie; but the effect's the same */
574		}
575		if (ifra->ifra_addr.siso_family == AF_ISO &&
576		    (hostIsNew || maskIsNew))
577			error = iso_ifinit(ifp, ia, &ifra->ifra_addr, 0);
578		if (ifra->ifra_snpaoffset)
579			ia->ia_snpaoffset = ifra->ifra_snpaoffset;
580		return (error);
581
582	case SIOCDIFADDR_ISO:
583		iso_purgeaddr(&ia->ia_ifa);
584		break;
585
586#define cmdbyte(x)	(((x) >> 8) & 0xff)
587	default:
588		if (cmdbyte(cmd) == 'a')
589			return (snpac_ioctl(so, cmd, data, l));
590		return ENOTTY;
591	}
592	return (0);
593}
594
595void
596iso_purgeaddr(struct ifaddr *ifa)
597{
598	struct ifnet *ifp = ifa->ifa_ifp;
599	struct iso_ifaddr *ia = (void *) ifa;
600
601	iso_ifscrub(ifp, ia);
602	ifa_remove(ifp, &ia->ia_ifa);
603	TAILQ_REMOVE(&iso_ifaddr, ia, ia_list);
604	IFAFREE(&ia->ia_ifa);
605}
606
607void
608iso_purgeif(struct ifnet *ifp)
609{
610	if_purgeaddrs(ifp, AF_ISO, iso_purgeaddr);
611}
612
613/*
614 * Delete any existing route for an interface.
615 */
616void
617iso_ifscrub(struct ifnet *ifp, struct iso_ifaddr *ia)
618{
619	int             nsellength = ia->ia_addr.siso_tlen;
620	if ((ia->ia_flags & IFA_ROUTE) == 0)
621		return;
622	ia->ia_addr.siso_tlen = 0;
623	if (ifp->if_flags & IFF_LOOPBACK)
624		rtinit(&(ia->ia_ifa), (int) RTM_DELETE, RTF_HOST);
625	else if (ifp->if_flags & IFF_POINTOPOINT)
626		rtinit(&(ia->ia_ifa), (int) RTM_DELETE, RTF_HOST);
627	else {
628		rtinit(&(ia->ia_ifa), (int) RTM_DELETE, 0);
629	}
630	ia->ia_addr.siso_tlen = nsellength;
631	ia->ia_flags &= ~IFA_ROUTE;
632}
633
634/*
635 * Initialize an interface's internet address
636 * and routing table entry.
637 */
638int
639iso_ifinit(struct ifnet *ifp, struct iso_ifaddr *ia, struct sockaddr_iso *siso,
640	int scrub)
641{
642	struct sockaddr_iso oldaddr;
643	int             s = splnet(), error, nsellength;
644
645	oldaddr = ia->ia_addr;
646	ia->ia_addr = *siso;
647	/*
648	 * Give the interface a chance to initialize
649	 * if this is its first address,
650	 * and to validate the address if necessary.
651	 */
652	if ((error = if_addr_init(ifp, &ia->ia_ifa, true)) != 0) {
653		splx(s);
654		ia->ia_addr = oldaddr;
655		return (error);
656	}
657	if (scrub) {
658		ia->ia_ifa.ifa_addr = sisotosa(&oldaddr);
659		iso_ifscrub(ifp, ia);
660		ia->ia_ifa.ifa_addr = sisotosa(&ia->ia_addr);
661	}
662	/*
663	 * XXX -- The following is here temporarily out of laziness in not
664	 * changing every ethernet driver's if_ioctl routine
665	 *
666	 * XXX extract llc_ifinit() and call from ether_ioctl(),
667	 * XXX fddi_ioctl().  --dyoung
668	 *
669	 */
670	if (ifp->if_type == IFT_ETHER || ifp->if_type == IFT_FDDI) {
671		ia->ia_ifa.ifa_rtrequest = llc_rtrequest;
672		ia->ia_ifa.ifa_flags |= RTF_CLONING;
673	}
674	/*
675	 * Add route for the network.
676	 */
677	nsellength = ia->ia_addr.siso_tlen;
678	ia->ia_addr.siso_tlen = 0;
679	if (ifp->if_flags & IFF_LOOPBACK) {
680		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
681		error = rtinit(&(ia->ia_ifa), (int) RTM_ADD, RTF_HOST | RTF_UP);
682	} else if (ifp->if_flags & IFF_POINTOPOINT &&
683		   ia->ia_dstaddr.siso_family == AF_ISO)
684		error = rtinit(&(ia->ia_ifa), (int) RTM_ADD, RTF_HOST | RTF_UP);
685	else {
686		rt_maskedcopy(ia->ia_ifa.ifa_addr, ia->ia_ifa.ifa_dstaddr,
687			      ia->ia_ifa.ifa_netmask);
688		ia->ia_dstaddr.siso_nlen =
689			min(ia->ia_addr.siso_nlen, (ia->ia_sockmask.siso_len - 6));
690		error = rtinit(&(ia->ia_ifa), (int) RTM_ADD, RTF_UP);
691	}
692	ia->ia_addr.siso_tlen = nsellength;
693	ia->ia_flags |= IFA_ROUTE;
694	splx(s);
695	return (error);
696}
697#ifdef notdef
698
699struct ifaddr  *
700iso_ifwithidi(struct sockaddr *addr)
701{
702	struct ifnet *ifp;
703	struct ifaddr *ifa;
704	u_int  af = addr->sa_family;
705
706	if (af != AF_ISO)
707		return (0);
708#ifdef ARGO_DEBUG
709	if (argo_debug[D_ROUTE]) {
710		printf(">>> iso_ifwithidi addr\n");
711		dump_isoaddr(satosiso(addr));
712		printf("\n");
713	}
714#endif
715	TAILQ_FOREACH(ifp, &ifnet, if_list) {
716#ifdef ARGO_DEBUG
717		if (argo_debug[D_ROUTE]) {
718			printf("iso_ifwithidi ifnet %s\n", ifp->if_name);
719		}
720#endif
721		IFADDR_FOREACH(ifa, ifp) {
722#ifdef ARGO_DEBUG
723			if (argo_debug[D_ROUTE]) {
724				printf("iso_ifwithidi address ");
725				dump_isoaddr(satosiso(ifa->ifa_addr));
726			}
727#endif
728			if (ifa->ifa_addr->sa_family != addr->sa_family)
729				continue;
730
731#ifdef ARGO_DEBUG
732			if (argo_debug[D_ROUTE]) {
733				printf(" af same, args to iso_eqtype:\n");
734				printf("0x%x ", satosiso(ifa->ifa_addr)->siso_addr);
735				printf(" 0x%x\n",
736				    &satosiso(addr)->siso_addr);
737			}
738#endif
739
740			if (iso_eqtype(&satosiso(ifa->ifa_addr)->siso_addr,
741				       &satosiso(addr)->siso_addr)) {
742#ifdef ARGO_DEBUG
743				if (argo_debug[D_ROUTE]) {
744					printf("ifa_ifwithidi: ifa found\n");
745				}
746#endif
747				return (ifa);
748			}
749#ifdef ARGO_DEBUG
750			if (argo_debug[D_ROUTE]) {
751				printf(" iso_eqtype failed\n");
752			}
753#endif
754		}
755	}
756	return ((struct ifaddr *) 0);
757}
758
759#endif				/* notdef */
760/*
761 * FUNCTION:		iso_ck_addr
762 *
763 * PURPOSE:		return true if the iso_addr passed is
764 *			within the legal size limit for an iso address.
765 *
766 * RETURNS:		true or false
767 *
768 * SIDE EFFECTS:
769 *
770 */
771int
772iso_ck_addr(struct iso_addr *isoa)
773{
774	return (isoa->isoa_len <= 20);
775
776}
777
778#ifdef notdef
779/*
780 * FUNCTION:		iso_eqtype
781 *
782 * PURPOSE:		Determine if two iso addresses are of the same type.
783 *			This is flaky.  Really we should consider all type
784 *			47 addrs to be the same - but there do exist different
785 *			structures for 47 addrs. Gosip adds a 3rd.
786 *
787 * RETURNS:		true if the addresses are the same type
788 *
789 * SIDE EFFECTS:
790 *
791 * NOTES:		By type, I mean rfc986, t37, or osinet
792 *
793 *			This will first compare afis. If they match, then
794 *			if the addr is not t37, the idis must be compared.
795 */
796int
797iso_eqtype(
798	struct iso_addr *isoaa,	/* first addr to check */
799	struct iso_addr *isoab)	/* other addr to check */
800{
801	if (isoaa->isoa_afi == isoab->isoa_afi) {
802		if (isoaa->isoa_afi == AFI_37)
803			return (1);
804		else
805			return (!memcmp(&isoaa->isoa_u, &isoab->isoa_u, 2));
806	}
807	return (0);
808}
809#endif /* notdef */
810/*
811 * FUNCTION:		iso_localifa()
812 *
813 * PURPOSE:		Find an interface addresss having a given destination
814 *			or at least matching the net.
815 *
816 * RETURNS:		ptr to an interface address
817 *
818 * SIDE EFFECTS:
819 *
820 * NOTES:
821 */
822struct iso_ifaddr *
823iso_localifa(const struct sockaddr_iso *siso)
824{
825	struct iso_ifaddr *ia;
826	const char *cp1, *cp2, *cp3;
827	struct ifnet *ifp;
828	struct iso_ifaddr *ia_maybe = 0;
829	/*
830	 * We make one pass looking for both net matches and an exact
831	 * dst addr.
832	 */
833	TAILQ_FOREACH(ia, &iso_ifaddr, ia_list) {
834		if ((ifp = ia->ia_ifp) == 0 || ((ifp->if_flags & IFF_UP) == 0))
835			continue;
836		if (ifp->if_flags & IFF_POINTOPOINT) {
837			if ((ia->ia_dstaddr.siso_family == AF_ISO) &&
838			    SAME_ISOADDR(&ia->ia_dstaddr, siso))
839				return (ia);
840			else if (SAME_ISOADDR(&ia->ia_addr, siso))
841				ia_maybe = ia;
842			continue;
843		}
844		if (ia->ia_sockmask.siso_len) {
845			char *cplim = ia->ia_sockmask.siso_len +
846				      (char *) &ia->ia_sockmask;
847			cp1 = ia->ia_sockmask.siso_data;
848			cp2 = siso->siso_data;
849			cp3 = ia->ia_addr.siso_data;
850			while (cp1 < cplim)
851				if (*cp1++ & (*cp2++ ^ *cp3++))
852					goto next;
853			ia_maybe = ia;
854		}
855		if (SAME_ISOADDR(&ia->ia_addr, siso))
856			return ia;
857next:		;
858	}
859	return ia_maybe;
860}
861
862/*
863 * FUNCTION:		iso_nlctloutput
864 *
865 * PURPOSE:		Set options at the network level
866 *
867 * RETURNS:		E*
868 *
869 * SIDE EFFECTS:
870 *
871 * NOTES:		This could embody some of the functions of
872 *				rclnp_ctloutput and cons_ctloutput.
873 */
874int
875iso_nlctloutput(
876	int             cmd,		/* command:set or get */
877	int             optname,	/* option of interest */
878	void *        pcb,		/* nl pcb */
879	struct mbuf    *m)		/* data for set, buffer for get */
880{
881	int             error = 0;	/* return value */
882	void *        data;	/* data for option */
883	int             data_len;	/* data's length */
884
885#ifdef ARGO_DEBUG
886	if (argo_debug[D_ISO]) {
887		printf("iso_nlctloutput: cmd %x, opt %x, pcb %p, m %p\n",
888		    cmd, optname, pcb, m);
889	}
890#endif
891
892	if ((cmd != PRCO_GETOPT) && (cmd != PRCO_SETOPT))
893		return (EOPNOTSUPP);
894
895	data = mtod(m, void *);
896	data_len = (m)->m_len;
897
898#ifdef ARGO_DEBUG
899	if (argo_debug[D_ISO]) {
900		printf("iso_nlctloutput: data is:\n");
901		dump_buf(data, data_len);
902	}
903#endif
904
905	switch (optname) {
906	default:
907		error = EOPNOTSUPP;
908	}
909	if (cmd == PRCO_SETOPT)
910		m_freem(m);
911	return error;
912}
913#endif /* ISO */
914
915#ifdef ARGO_DEBUG
916
917/*
918 * FUNCTION:		dump_isoaddr
919 *
920 * PURPOSE:		debugging
921 *
922 * RETURNS:		nada
923 *
924 */
925void
926dump_isoaddr(const struct sockaddr_iso *s)
927{
928	if (s->siso_family == AF_ISO) {
929		printf("ISO address: suffixlen %d, %s\n",
930		       s->siso_tlen, clnp_saddr_isop(s));
931	} else if (s->siso_family == AF_INET) {
932		/* hack */
933		const struct sockaddr_in *sin = satocsin(s);
934
935		printf("%d.%d.%d.%d: %d",
936		       (sin->sin_addr.s_addr >> 24) & 0xff,
937		       (sin->sin_addr.s_addr >> 16) & 0xff,
938		       (sin->sin_addr.s_addr >> 8) & 0xff,
939		       (sin->sin_addr.s_addr) & 0xff,
940		       sin->sin_port);
941	}
942}
943
944#endif /* ARGO_DEBUG */
945
946struct queue {
947	struct queue *q_next, *q_prev;
948};
949
950/*
951 * FUNCTION:		iso_insque
952 *
953 * PURPOSE:		insert an element into a queue
954 *
955 * RETURNS:
956 */
957void
958iso_insque(void *v1, void *v2)
959{
960	struct queue *elem = v1, *head = v2;
961	struct queue *next;
962
963	next = head->q_next;
964	elem->q_next = next;
965	head->q_next = elem;
966	elem->q_prev = head;
967	next->q_prev = elem;
968}
969
970/*
971 * FUNCTION:		iso_remque
972 *
973 * PURPOSE:		remove an element from a queue
974 *
975 * RETURNS:
976 */
977void
978iso_remque(void *v)
979{
980	struct queue *elem = v;
981	struct queue *next, *prev;
982
983	next = elem->q_next;
984	prev = elem->q_prev;
985	next->q_prev = prev;
986	prev->q_next = next;
987	elem->q_prev = NULL;
988}
989