if_fddisubr.c revision 121436
1/*
2 * Copyright (c) 1995, 1996
3 *	Matt Thomas <matt@3am-software.com>.  All rights reserved.
4 * Copyright (c) 1982, 1989, 1993
5 *	The Regents of the University of California.  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 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
36 * $FreeBSD: head/sys/net/if_fddisubr.c 121436 2003-10-23 17:47:55Z imp $
37 */
38
39#include "opt_atalk.h"
40#include "opt_inet.h"
41#include "opt_inet6.h"
42#include "opt_ipx.h"
43#include "opt_mac.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/mac.h>
49#include <sys/malloc.h>
50#include <sys/mbuf.h>
51#include <sys/module.h>
52#include <sys/socket.h>
53#include <sys/sockio.h>
54
55#include <net/if.h>
56#include <net/if_dl.h>
57#include <net/if_llc.h>
58#include <net/if_types.h>
59
60#include <net/netisr.h>
61#include <net/route.h>
62#include <net/bpf.h>
63#include <net/fddi.h>
64
65#if defined(INET) || defined(INET6)
66#include <netinet/in.h>
67#include <netinet/in_var.h>
68#include <netinet/if_ether.h>
69#endif
70#ifdef INET6
71#include <netinet6/nd6.h>
72#endif
73
74#ifdef IPX
75#include <netipx/ipx.h>
76#include <netipx/ipx_if.h>
77#endif
78
79#ifdef DECNET
80#include <netdnet/dn.h>
81#endif
82
83#ifdef NETATALK
84#include <netatalk/at.h>
85#include <netatalk/at_var.h>
86#include <netatalk/at_extern.h>
87
88extern u_char	at_org_code[ 3 ];
89extern u_char	aarp_org_code[ 3 ];
90#endif /* NETATALK */
91
92static u_char fddibroadcastaddr[FDDI_ADDR_LEN] =
93			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
94
95static int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
96			      struct sockaddr *);
97static int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *,
98		       struct rtentry *);
99static void fddi_input(struct ifnet *ifp, struct mbuf *m);
100
101#define	IFP2AC(IFP)	((struct arpcom *)IFP)
102#define	senderr(e)	do { error = (e); goto bad; } while (0)
103
104/*
105 * FDDI output routine.
106 * Encapsulate a packet of type family for the local net.
107 * Use trailer local net encapsulation if enough data in first
108 * packet leaves a multiple of 512 bytes of data in remainder.
109 * Assumes that ifp is actually pointer to arpcom structure.
110 */
111static int
112fddi_output(ifp, m, dst, rt0)
113	struct ifnet *ifp;
114	struct mbuf *m;
115	struct sockaddr *dst;
116	struct rtentry *rt0;
117{
118	u_int16_t type;
119	int loop_copy = 0, error = 0, hdrcmplt = 0;
120 	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
121	struct rtentry *rt;
122	struct fddi_header *fh;
123	struct arpcom *ac = IFP2AC(ifp);
124
125#ifdef MAC
126	error = mac_check_ifnet_transmit(ifp, m);
127	if (error)
128		senderr(error);
129#endif
130
131	if (ifp->if_flags & IFF_MONITOR)
132		senderr(ENETDOWN);
133	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
134		senderr(ENETDOWN);
135	getmicrotime(&ifp->if_lastchange);
136
137	error = rt_check(&rt, &rt0, dst);
138	if (error)
139		goto bad;
140
141	switch (dst->sa_family) {
142#ifdef INET
143	case AF_INET: {
144		if (!arpresolve(ifp, rt, m, dst, edst, rt0))
145			return (0);	/* if not yet resolved */
146		type = htons(ETHERTYPE_IP);
147		break;
148	}
149#endif /* INET */
150#ifdef INET6
151	case AF_INET6:
152		if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) {
153			/* Something bad happened */
154			return (0);
155		}
156		type = htons(ETHERTYPE_IPV6);
157		break;
158#endif /* INET6 */
159#ifdef IPX
160	case AF_IPX:
161		type = htons(ETHERTYPE_IPX);
162 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
163		    (caddr_t)edst, FDDI_ADDR_LEN);
164		break;
165#endif /* IPX */
166#ifdef NETATALK
167	case AF_APPLETALK: {
168	    struct at_ifaddr *aa;
169            if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst))
170                return (0);
171	    /*
172	     * ifaddr is the first thing in at_ifaddr
173	     */
174	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
175		goto bad;
176
177	    /*
178	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
179	     * Since we must preserve the value of m, which is passed to us by
180	     * value, we m_copy() the first mbuf, and use it for our llc header.
181	     */
182	    if (aa->aa_flags & AFA_PHASE2) {
183		struct llc llc;
184
185		M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT);
186		if (m == 0)
187			senderr(ENOBUFS);
188		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
189		llc.llc_control = LLC_UI;
190		bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code));
191		llc.llc_snap.ether_type = htons(ETHERTYPE_AT);
192		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
193		type = 0;
194	    } else {
195		type = htons(ETHERTYPE_AT);
196	    }
197	    break;
198	}
199#endif /* NETATALK */
200
201	case pseudo_AF_HDRCMPLT:
202	{
203		struct ether_header *eh;
204		hdrcmplt = 1;
205		eh = (struct ether_header *)dst->sa_data;
206		bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN);
207		/* FALLTHROUGH */
208	}
209
210	case AF_UNSPEC:
211	{
212		struct ether_header *eh;
213		loop_copy = -1;
214		eh = (struct ether_header *)dst->sa_data;
215		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN);
216		if (*edst & 1)
217			m->m_flags |= (M_BCAST|M_MCAST);
218		type = eh->ether_type;
219		break;
220	}
221
222	case AF_IMPLINK:
223	{
224		fh = mtod(m, struct fddi_header *);
225		error = EPROTONOSUPPORT;
226		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
227			case FDDIFC_LLC_ASYNC: {
228				/* legal priorities are 0 through 7 */
229				if ((fh->fddi_fc & FDDIFC_Z) > 7)
230			        	goto bad;
231				break;
232			}
233			case FDDIFC_LLC_SYNC: {
234				/* FDDIFC_Z bits reserved, must be zero */
235				if (fh->fddi_fc & FDDIFC_Z)
236					goto bad;
237				break;
238			}
239			case FDDIFC_SMT: {
240				/* FDDIFC_Z bits must be non zero */
241				if ((fh->fddi_fc & FDDIFC_Z) == 0)
242					goto bad;
243				break;
244			}
245			default: {
246				/* anything else is too dangerous */
247               	 		goto bad;
248			}
249		}
250		error = 0;
251		if (fh->fddi_dhost[0] & 1)
252			m->m_flags |= (M_BCAST|M_MCAST);
253		goto queue_it;
254	}
255	default:
256		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
257		senderr(EAFNOSUPPORT);
258	}
259
260	/*
261	 * Add LLC header.
262	 */
263	if (type != 0) {
264		struct llc *l;
265		M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
266		if (m == 0)
267			senderr(ENOBUFS);
268		l = mtod(m, struct llc *);
269		l->llc_control = LLC_UI;
270		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
271		l->llc_snap.org_code[0] =
272			l->llc_snap.org_code[1] =
273			l->llc_snap.org_code[2] = 0;
274		l->llc_snap.ether_type = htons(type);
275	}
276
277	/*
278	 * Add local net header.  If no space in first mbuf,
279	 * allocate another.
280	 */
281	M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT);
282	if (m == 0)
283		senderr(ENOBUFS);
284	fh = mtod(m, struct fddi_header *);
285	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
286	bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN);
287  queue_it:
288	if (hdrcmplt)
289		bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN);
290	else
291		bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost,
292			FDDI_ADDR_LEN);
293
294	/*
295	 * If a simplex interface, and the packet is being sent to our
296	 * Ethernet address or a broadcast address, loopback a copy.
297	 * XXX To make a simplex device behave exactly like a duplex
298	 * device, we should copy in the case of sending to our own
299	 * ethernet address (thus letting the original actually appear
300	 * on the wire). However, we don't do that here for security
301	 * reasons and compatibility with the original behavior.
302	 */
303	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
304		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
305			struct mbuf *n;
306			n = m_copy(m, 0, (int)M_COPYALL);
307			(void) if_simloop(ifp, n, dst->sa_family,
308					  FDDI_HDR_LEN);
309	     	} else if (bcmp(fh->fddi_dhost, fh->fddi_shost,
310				FDDI_ADDR_LEN) == 0) {
311			(void) if_simloop(ifp, m, dst->sa_family,
312					  FDDI_HDR_LEN);
313			return (0);	/* XXX */
314		}
315	}
316
317	if (! IF_HANDOFF(&ifp->if_snd, m, ifp))
318		senderr(ENOBUFS);
319	return (error);
320
321bad:
322	ifp->if_oerrors++;
323	if (m)
324		m_freem(m);
325	return (error);
326}
327
328/*
329 * Process a received FDDI packet.
330 */
331static void
332fddi_input(ifp, m)
333	struct ifnet *ifp;
334	struct mbuf *m;
335{
336	int isr;
337	struct llc *l;
338	struct fddi_header *fh;
339
340	/*
341	 * Do consistency checks to verify assumptions
342	 * made by code past this point.
343	 */
344	if ((m->m_flags & M_PKTHDR) == 0) {
345		if_printf(ifp, "discard frame w/o packet header\n");
346		ifp->if_ierrors++;
347		m_freem(m);
348		return;
349	}
350	if (m->m_pkthdr.rcvif == NULL) {
351		if_printf(ifp, "discard frame w/o interface pointer\n");
352		ifp->if_ierrors++;
353		m_freem(m);
354		return;
355        }
356
357	m = m_pullup(m, FDDI_HDR_LEN);
358	if (m == NULL) {
359		ifp->if_ierrors++;
360		goto dropanyway;
361	}
362	fh = mtod(m, struct fddi_header *);
363	m->m_pkthdr.header = (void *)fh;
364
365	/*
366	 * Discard packet if interface is not up.
367	 */
368	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
369		goto dropanyway;
370
371	/*
372	 * Give bpf a chance at the packet.
373	 */
374	BPF_MTAP(ifp, m);
375
376	/*
377	 * Interface marked for monitoring; discard packet.
378	 */
379	if (ifp->if_flags & IFF_MONITOR) {
380		m_freem(m);
381		return;
382	}
383
384#ifdef MAC
385	mac_create_mbuf_from_ifnet(ifp, m);
386#endif
387
388	/*
389	 * Update interface statistics.
390	 */
391	ifp->if_ibytes += m->m_pkthdr.len;
392	getmicrotime(&ifp->if_lastchange);
393
394	/*
395	 * Discard non local unicast packets when interface
396	 * is in promiscuous mode.
397	 */
398	if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) &&
399	    (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost,
400	     FDDI_ADDR_LEN) != 0))
401		goto dropanyway;
402
403	/*
404	 * Set mbuf flags for bcast/mcast.
405	 */
406	if (fh->fddi_dhost[0] & 1) {
407		if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost,
408		    FDDI_ADDR_LEN) == 0)
409			m->m_flags |= M_BCAST;
410		else
411			m->m_flags |= M_MCAST;
412		ifp->if_imcasts++;
413	}
414
415#ifdef M_LINK0
416	/*
417	 * If this has a LLC priority of 0, then mark it so upper
418	 * layers have a hint that it really came via a FDDI/Ethernet
419	 * bridge.
420	 */
421	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
422		m->m_flags |= M_LINK0;
423#endif
424
425	/* Strip off FDDI header. */
426	m_adj(m, FDDI_HDR_LEN);
427
428	m = m_pullup(m, LLC_SNAPFRAMELEN);
429	if (m == 0) {
430		ifp->if_ierrors++;
431		goto dropanyway;
432	}
433	l = mtod(m, struct llc *);
434
435	switch (l->llc_dsap) {
436	case LLC_SNAP_LSAP:
437	{
438		u_int16_t type;
439		if ((l->llc_control != LLC_UI) ||
440		    (l->llc_ssap != LLC_SNAP_LSAP)) {
441			ifp->if_noproto++;
442			goto dropanyway;
443		}
444#ifdef NETATALK
445		if (Bcmp(&(l->llc_snap.org_code)[0], at_org_code,
446		    sizeof(at_org_code)) == 0 &&
447		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) {
448			isr = NETISR_ATALK2;
449			m_adj(m, LLC_SNAPFRAMELEN);
450			break;
451		}
452
453		if (Bcmp(&(l->llc_snap.org_code)[0], aarp_org_code,
454		    sizeof(aarp_org_code)) == 0 &&
455		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) {
456			m_adj(m, LLC_SNAPFRAMELEN);
457			isr = NETISR_AARP;
458			break;
459		}
460#endif /* NETATALK */
461		if (l->llc_snap.org_code[0] != 0 ||
462		    l->llc_snap.org_code[1] != 0 ||
463		    l->llc_snap.org_code[2] != 0) {
464			ifp->if_noproto++;
465			goto dropanyway;
466		}
467
468		type = ntohs(l->llc_snap.ether_type);
469		m_adj(m, LLC_SNAPFRAMELEN);
470
471		switch (type) {
472#ifdef INET
473		case ETHERTYPE_IP:
474			if (ipflow_fastforward(m))
475				return;
476			isr = NETISR_IP;
477			break;
478
479		case ETHERTYPE_ARP:
480			if (ifp->if_flags & IFF_NOARP)
481				goto dropanyway;
482			isr = NETISR_ARP;
483			break;
484#endif
485#ifdef INET6
486		case ETHERTYPE_IPV6:
487			isr = NETISR_IPV6;
488			break;
489#endif
490#ifdef IPX
491		case ETHERTYPE_IPX:
492			isr = NETISR_IPX;
493			break;
494#endif
495#ifdef DECNET
496		case ETHERTYPE_DECNET:
497			isr = NETISR_DECNET;
498			break;
499#endif
500#ifdef NETATALK
501		case ETHERTYPE_AT:
502	                isr = NETISR_ATALK1;
503			break;
504	        case ETHERTYPE_AARP:
505			isr = NETISR_AARP;
506			break;
507#endif /* NETATALK */
508		default:
509			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
510			ifp->if_noproto++;
511			goto dropanyway;
512		}
513		break;
514	}
515
516	default:
517		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
518		ifp->if_noproto++;
519		goto dropanyway;
520	}
521	netisr_dispatch(isr, m);
522	return;
523
524dropanyway:
525	ifp->if_iqdrops++;
526	if (m)
527		m_freem(m);
528	return;
529}
530
531/*
532 * Perform common duties while attaching to interface list
533 */
534void
535fddi_ifattach(ifp, bpf)
536	struct ifnet *ifp;
537	int bpf;
538{
539	struct ifaddr *ifa;
540	struct sockaddr_dl *sdl;
541
542	ifp->if_type = IFT_FDDI;
543	ifp->if_addrlen = FDDI_ADDR_LEN;
544	ifp->if_hdrlen = 21;
545
546	if_attach(ifp);         /* Must be called before additional assignments */
547
548	ifp->if_mtu = FDDIMTU;
549	ifp->if_output = fddi_output;
550	ifp->if_input = fddi_input;
551	ifp->if_resolvemulti = fddi_resolvemulti;
552	ifp->if_broadcastaddr = fddibroadcastaddr;
553	ifp->if_baudrate = 100000000;
554#ifdef IFF_NOTRAILERS
555	ifp->if_flags |= IFF_NOTRAILERS;
556#endif
557	ifa = ifaddr_byindex(ifp->if_index);
558	if (ifa == NULL) {
559		if_printf(ifp, "%s() no lladdr!\n", __func__);
560		return;
561	}
562
563	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
564	sdl->sdl_type = IFT_FDDI;
565	sdl->sdl_alen = ifp->if_addrlen;
566	bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
567
568	if (bpf)
569		bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN);
570
571	return;
572}
573
574void
575fddi_ifdetach(ifp, bpf)
576	struct ifnet *ifp;
577	int bpf;
578{
579
580	if (bpf)
581		bpfdetach(ifp);
582
583	if_detach(ifp);
584
585	return;
586}
587
588int
589fddi_ioctl (ifp, command, data)
590	struct ifnet *ifp;
591	int command;
592	caddr_t data;
593{
594	struct ifaddr *ifa;
595	struct ifreq *ifr;
596	int error;
597
598	ifa = (struct ifaddr *) data;
599	ifr = (struct ifreq *) data;
600	error = 0;
601
602	switch (command) {
603	case SIOCSIFADDR:
604		ifp->if_flags |= IFF_UP;
605
606		switch (ifa->ifa_addr->sa_family) {
607#ifdef INET
608		case AF_INET:	/* before arpwhohas */
609			ifp->if_init(ifp->if_softc);
610			arp_ifinit(ifp, ifa);
611			break;
612#endif
613#ifdef IPX
614		/*
615		 * XXX - This code is probably wrong
616		 */
617		case AF_IPX: {
618				struct ipx_addr *ina;
619				struct arpcom *ac;
620
621				ina = &(IA_SIPX(ifa)->sipx_addr);
622				ac = IFP2AC(ifp);
623
624				if (ipx_nullhost(*ina)) {
625					ina->x_host = *(union ipx_host *)
626							ac->ac_enaddr;
627				} else {
628					bcopy((caddr_t) ina->x_host.c_host,
629					      (caddr_t) ac->ac_enaddr,
630					      sizeof(ac->ac_enaddr));
631				}
632
633				/*
634				 * Set new address
635				 */
636				ifp->if_init(ifp->if_softc);
637			}
638			break;
639#endif
640		default:
641			ifp->if_init(ifp->if_softc);
642			break;
643		}
644	case SIOCGIFADDR: {
645			struct sockaddr *sa;
646
647			sa = (struct sockaddr *) & ifr->ifr_data;
648			bcopy(IFP2AC(ifp)->ac_enaddr,
649			      (caddr_t) sa->sa_data, FDDI_ADDR_LEN);
650
651		}
652		break;
653	case SIOCSIFMTU:
654		/*
655		 * Set the interface MTU.
656		 */
657		if (ifr->ifr_mtu > FDDIMTU) {
658			error = EINVAL;
659		} else {
660			ifp->if_mtu = ifr->ifr_mtu;
661		}
662		break;
663	default:
664		break;
665	}
666
667	return (error);
668}
669
670static int
671fddi_resolvemulti(ifp, llsa, sa)
672	struct ifnet *ifp;
673	struct sockaddr **llsa;
674	struct sockaddr *sa;
675{
676	struct sockaddr_dl *sdl;
677	struct sockaddr_in *sin;
678#ifdef INET6
679	struct sockaddr_in6 *sin6;
680#endif
681	u_char *e_addr;
682
683	switch(sa->sa_family) {
684	case AF_LINK:
685		/*
686		 * No mapping needed. Just check that it's a valid MC address.
687		 */
688		sdl = (struct sockaddr_dl *)sa;
689		e_addr = LLADDR(sdl);
690		if ((e_addr[0] & 1) != 1)
691			return (EADDRNOTAVAIL);
692		*llsa = 0;
693		return (0);
694
695#ifdef INET
696	case AF_INET:
697		sin = (struct sockaddr_in *)sa;
698		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
699			return (EADDRNOTAVAIL);
700		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
701		       M_WAITOK);
702		sdl->sdl_len = sizeof *sdl;
703		sdl->sdl_family = AF_LINK;
704		sdl->sdl_index = ifp->if_index;
705		sdl->sdl_type = IFT_FDDI;
706		sdl->sdl_nlen = 0;
707		sdl->sdl_alen = FDDI_ADDR_LEN;
708		sdl->sdl_slen = 0;
709		e_addr = LLADDR(sdl);
710		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
711		*llsa = (struct sockaddr *)sdl;
712		return (0);
713#endif
714#ifdef INET6
715	case AF_INET6:
716		sin6 = (struct sockaddr_in6 *)sa;
717		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
718			/*
719			 * An IP6 address of 0 means listen to all
720			 * of the Ethernet multicast address used for IP6.
721			 * (This is used for multicast routers.)
722			 */
723			ifp->if_flags |= IFF_ALLMULTI;
724			*llsa = 0;
725			return (0);
726		}
727		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
728			return (EADDRNOTAVAIL);
729		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
730		       M_WAITOK);
731		sdl->sdl_len = sizeof *sdl;
732		sdl->sdl_family = AF_LINK;
733		sdl->sdl_index = ifp->if_index;
734		sdl->sdl_type = IFT_FDDI;
735		sdl->sdl_nlen = 0;
736		sdl->sdl_alen = FDDI_ADDR_LEN;
737		sdl->sdl_slen = 0;
738		e_addr = LLADDR(sdl);
739		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
740		*llsa = (struct sockaddr *)sdl;
741		return (0);
742#endif
743
744	default:
745		/*
746		 * Well, the text isn't quite right, but it's the name
747		 * that counts...
748		 */
749		return (EAFNOSUPPORT);
750	}
751
752	return (0);
753}
754
755static moduledata_t fddi_mod = {
756	"fddi",	/* module name */
757	NULL,	/* event handler */
758	0	/* extra data */
759};
760
761DECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
762MODULE_VERSION(fddi, 1);
763