if_fddisubr.c revision 185164
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 185164 2008-11-22 07:35:45Z kmacy $
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/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/module.h>
51#include <sys/socket.h>
52#include <sys/sockio.h>
53
54#include <net/if.h>
55#include <net/if_dl.h>
56#include <net/if_llc.h>
57#include <net/if_types.h>
58
59#include <net/ethernet.h>
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
92#include <security/mac/mac_framework.h>
93
94static const u_char fddibroadcastaddr[FDDI_ADDR_LEN] =
95			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
96
97static int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
98			      struct sockaddr *);
99static int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *,
100		       struct rtentry *);
101static void fddi_input(struct ifnet *ifp, struct mbuf *m);
102
103#define	senderr(e)	do { error = (e); goto bad; } while (0)
104
105/*
106 * FDDI output routine.
107 * Encapsulate a packet of type family for the local net.
108 * Use trailer local net encapsulation if enough data in first
109 * packet leaves a multiple of 512 bytes of data in remainder.
110 * Assumes that ifp is actually pointer to arpcom structure.
111 */
112static int
113fddi_output(ifp, m, dst, rt0)
114	struct ifnet *ifp;
115	struct mbuf *m;
116	struct sockaddr *dst;
117	struct rtentry *rt0;
118{
119	u_int16_t type;
120	int loop_copy = 0, error = 0, hdrcmplt = 0;
121 	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
122	struct fddi_header *fh;
123
124#ifdef MAC
125	error = mac_ifnet_check_transmit(ifp, m);
126	if (error)
127		senderr(error);
128#endif
129
130	if (ifp->if_flags & IFF_MONITOR)
131		senderr(ENETDOWN);
132	if (!((ifp->if_flags & IFF_UP) &&
133	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
134		senderr(ENETDOWN);
135	getmicrotime(&ifp->if_lastchange);
136
137	switch (dst->sa_family) {
138#ifdef INET
139	case AF_INET: {
140		error = arpresolve(ifp, rt0, m, dst, edst);
141		if (error)
142			return (error == EWOULDBLOCK ? 0 : error);
143		type = htons(ETHERTYPE_IP);
144		break;
145	}
146	case AF_ARP:
147	{
148		struct arphdr *ah;
149		ah = mtod(m, struct arphdr *);
150		ah->ar_hrd = htons(ARPHRD_ETHER);
151
152		loop_copy = -1; /* if this is for us, don't do it */
153
154		switch (ntohs(ah->ar_op)) {
155		case ARPOP_REVREQUEST:
156		case ARPOP_REVREPLY:
157			type = htons(ETHERTYPE_REVARP);
158			break;
159		case ARPOP_REQUEST:
160		case ARPOP_REPLY:
161		default:
162			type = htons(ETHERTYPE_ARP);
163			break;
164		}
165
166		if (m->m_flags & M_BCAST)
167			bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN);
168                else
169			bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN);
170
171	}
172	break;
173#endif /* INET */
174#ifdef INET6
175	case AF_INET6:
176		error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst);
177		if (error)
178			return (error); /* Something bad happened */
179		type = htons(ETHERTYPE_IPV6);
180		break;
181#endif /* INET6 */
182#ifdef IPX
183	case AF_IPX:
184		type = htons(ETHERTYPE_IPX);
185 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
186		    (caddr_t)edst, FDDI_ADDR_LEN);
187		break;
188#endif /* IPX */
189#ifdef NETATALK
190	case AF_APPLETALK: {
191	    struct at_ifaddr *aa;
192            if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst))
193                return (0);
194	    /*
195	     * ifaddr is the first thing in at_ifaddr
196	     */
197	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
198		goto bad;
199
200	    /*
201	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
202	     * Since we must preserve the value of m, which is passed to us by
203	     * value, we m_copy() the first mbuf, and use it for our llc header.
204	     */
205	    if (aa->aa_flags & AFA_PHASE2) {
206		struct llc llc;
207
208		M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAIT);
209		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
210		llc.llc_control = LLC_UI;
211		bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code));
212		llc.llc_snap.ether_type = htons(ETHERTYPE_AT);
213		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
214		type = 0;
215	    } else {
216		type = htons(ETHERTYPE_AT);
217	    }
218	    break;
219	}
220#endif /* NETATALK */
221
222	case pseudo_AF_HDRCMPLT:
223	{
224		struct ether_header *eh;
225		hdrcmplt = 1;
226		eh = (struct ether_header *)dst->sa_data;
227		bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN);
228		/* FALLTHROUGH */
229	}
230
231	case AF_UNSPEC:
232	{
233		struct ether_header *eh;
234		loop_copy = -1;
235		eh = (struct ether_header *)dst->sa_data;
236		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN);
237		if (*edst & 1)
238			m->m_flags |= (M_BCAST|M_MCAST);
239		type = eh->ether_type;
240		break;
241	}
242
243	case AF_IMPLINK:
244	{
245		fh = mtod(m, struct fddi_header *);
246		error = EPROTONOSUPPORT;
247		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
248			case FDDIFC_LLC_ASYNC: {
249				/* legal priorities are 0 through 7 */
250				if ((fh->fddi_fc & FDDIFC_Z) > 7)
251			        	goto bad;
252				break;
253			}
254			case FDDIFC_LLC_SYNC: {
255				/* FDDIFC_Z bits reserved, must be zero */
256				if (fh->fddi_fc & FDDIFC_Z)
257					goto bad;
258				break;
259			}
260			case FDDIFC_SMT: {
261				/* FDDIFC_Z bits must be non zero */
262				if ((fh->fddi_fc & FDDIFC_Z) == 0)
263					goto bad;
264				break;
265			}
266			default: {
267				/* anything else is too dangerous */
268               	 		goto bad;
269			}
270		}
271		error = 0;
272		if (fh->fddi_dhost[0] & 1)
273			m->m_flags |= (M_BCAST|M_MCAST);
274		goto queue_it;
275	}
276	default:
277		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
278		senderr(EAFNOSUPPORT);
279	}
280
281	/*
282	 * Add LLC header.
283	 */
284	if (type != 0) {
285		struct llc *l;
286		M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
287		if (m == 0)
288			senderr(ENOBUFS);
289		l = mtod(m, struct llc *);
290		l->llc_control = LLC_UI;
291		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
292		l->llc_snap.org_code[0] =
293			l->llc_snap.org_code[1] =
294			l->llc_snap.org_code[2] = 0;
295		l->llc_snap.ether_type = htons(type);
296	}
297
298	/*
299	 * Add local net header.  If no space in first mbuf,
300	 * allocate another.
301	 */
302	M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT);
303	if (m == 0)
304		senderr(ENOBUFS);
305	fh = mtod(m, struct fddi_header *);
306	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
307	bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN);
308  queue_it:
309	if (hdrcmplt)
310		bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN);
311	else
312		bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost,
313			FDDI_ADDR_LEN);
314
315	/*
316	 * If a simplex interface, and the packet is being sent to our
317	 * Ethernet address or a broadcast address, loopback a copy.
318	 * XXX To make a simplex device behave exactly like a duplex
319	 * device, we should copy in the case of sending to our own
320	 * ethernet address (thus letting the original actually appear
321	 * on the wire). However, we don't do that here for security
322	 * reasons and compatibility with the original behavior.
323	 */
324	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
325		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
326			struct mbuf *n;
327			n = m_copy(m, 0, (int)M_COPYALL);
328			(void) if_simloop(ifp, n, dst->sa_family,
329					  FDDI_HDR_LEN);
330	     	} else if (bcmp(fh->fddi_dhost, fh->fddi_shost,
331				FDDI_ADDR_LEN) == 0) {
332			(void) if_simloop(ifp, m, dst->sa_family,
333					  FDDI_HDR_LEN);
334			return (0);	/* XXX */
335		}
336	}
337
338	error = (ifp->if_transmit)(ifp, m);
339	if (error)
340		ifp->if_oerrors++;
341
342	return (error);
343
344bad:
345	ifp->if_oerrors++;
346	if (m)
347		m_freem(m);
348	return (error);
349}
350
351/*
352 * Process a received FDDI packet.
353 */
354static void
355fddi_input(ifp, m)
356	struct ifnet *ifp;
357	struct mbuf *m;
358{
359	int isr;
360	struct llc *l;
361	struct fddi_header *fh;
362
363	/*
364	 * Do consistency checks to verify assumptions
365	 * made by code past this point.
366	 */
367	if ((m->m_flags & M_PKTHDR) == 0) {
368		if_printf(ifp, "discard frame w/o packet header\n");
369		ifp->if_ierrors++;
370		m_freem(m);
371		return;
372	}
373	if (m->m_pkthdr.rcvif == NULL) {
374		if_printf(ifp, "discard frame w/o interface pointer\n");
375		ifp->if_ierrors++;
376		m_freem(m);
377		return;
378        }
379
380	m = m_pullup(m, FDDI_HDR_LEN);
381	if (m == NULL) {
382		ifp->if_ierrors++;
383		goto dropanyway;
384	}
385	fh = mtod(m, struct fddi_header *);
386	m->m_pkthdr.header = (void *)fh;
387
388	/*
389	 * Discard packet if interface is not up.
390	 */
391	if (!((ifp->if_flags & IFF_UP) &&
392	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
393		goto dropanyway;
394
395	/*
396	 * Give bpf a chance at the packet.
397	 */
398	BPF_MTAP(ifp, m);
399
400	/*
401	 * Interface marked for monitoring; discard packet.
402	 */
403	if (ifp->if_flags & IFF_MONITOR) {
404		m_freem(m);
405		return;
406	}
407
408#ifdef MAC
409	mac_ifnet_create_mbuf(ifp, m);
410#endif
411
412	/*
413	 * Update interface statistics.
414	 */
415	ifp->if_ibytes += m->m_pkthdr.len;
416	getmicrotime(&ifp->if_lastchange);
417
418	/*
419	 * Discard non local unicast packets when interface
420	 * is in promiscuous mode.
421	 */
422	if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) &&
423	    (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost,
424	     FDDI_ADDR_LEN) != 0))
425		goto dropanyway;
426
427	/*
428	 * Set mbuf flags for bcast/mcast.
429	 */
430	if (fh->fddi_dhost[0] & 1) {
431		if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost,
432		    FDDI_ADDR_LEN) == 0)
433			m->m_flags |= M_BCAST;
434		else
435			m->m_flags |= M_MCAST;
436		ifp->if_imcasts++;
437	}
438
439#ifdef M_LINK0
440	/*
441	 * If this has a LLC priority of 0, then mark it so upper
442	 * layers have a hint that it really came via a FDDI/Ethernet
443	 * bridge.
444	 */
445	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
446		m->m_flags |= M_LINK0;
447#endif
448
449	/* Strip off FDDI header. */
450	m_adj(m, FDDI_HDR_LEN);
451
452	m = m_pullup(m, LLC_SNAPFRAMELEN);
453	if (m == 0) {
454		ifp->if_ierrors++;
455		goto dropanyway;
456	}
457	l = mtod(m, struct llc *);
458
459	switch (l->llc_dsap) {
460	case LLC_SNAP_LSAP:
461	{
462		u_int16_t type;
463		if ((l->llc_control != LLC_UI) ||
464		    (l->llc_ssap != LLC_SNAP_LSAP)) {
465			ifp->if_noproto++;
466			goto dropanyway;
467		}
468#ifdef NETATALK
469		if (bcmp(&(l->llc_snap.org_code)[0], at_org_code,
470		    sizeof(at_org_code)) == 0 &&
471		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) {
472			isr = NETISR_ATALK2;
473			m_adj(m, LLC_SNAPFRAMELEN);
474			break;
475		}
476
477		if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code,
478		    sizeof(aarp_org_code)) == 0 &&
479		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) {
480			m_adj(m, LLC_SNAPFRAMELEN);
481			isr = NETISR_AARP;
482			break;
483		}
484#endif /* NETATALK */
485		if (l->llc_snap.org_code[0] != 0 ||
486		    l->llc_snap.org_code[1] != 0 ||
487		    l->llc_snap.org_code[2] != 0) {
488			ifp->if_noproto++;
489			goto dropanyway;
490		}
491
492		type = ntohs(l->llc_snap.ether_type);
493		m_adj(m, LLC_SNAPFRAMELEN);
494
495		switch (type) {
496#ifdef INET
497		case ETHERTYPE_IP:
498			if ((m = ip_fastforward(m)) == NULL)
499				return;
500			isr = NETISR_IP;
501			break;
502
503		case ETHERTYPE_ARP:
504			if (ifp->if_flags & IFF_NOARP)
505				goto dropanyway;
506			isr = NETISR_ARP;
507			break;
508#endif
509#ifdef INET6
510		case ETHERTYPE_IPV6:
511			isr = NETISR_IPV6;
512			break;
513#endif
514#ifdef IPX
515		case ETHERTYPE_IPX:
516			isr = NETISR_IPX;
517			break;
518#endif
519#ifdef DECNET
520		case ETHERTYPE_DECNET:
521			isr = NETISR_DECNET;
522			break;
523#endif
524#ifdef NETATALK
525		case ETHERTYPE_AT:
526	                isr = NETISR_ATALK1;
527			break;
528	        case ETHERTYPE_AARP:
529			isr = NETISR_AARP;
530			break;
531#endif /* NETATALK */
532		default:
533			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
534			ifp->if_noproto++;
535			goto dropanyway;
536		}
537		break;
538	}
539
540	default:
541		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
542		ifp->if_noproto++;
543		goto dropanyway;
544	}
545	netisr_dispatch(isr, m);
546	return;
547
548dropanyway:
549	ifp->if_iqdrops++;
550	if (m)
551		m_freem(m);
552	return;
553}
554
555/*
556 * Perform common duties while attaching to interface list
557 */
558void
559fddi_ifattach(ifp, lla, bpf)
560	struct ifnet *ifp;
561	const u_int8_t *lla;
562	int bpf;
563{
564	struct ifaddr *ifa;
565	struct sockaddr_dl *sdl;
566
567	ifp->if_type = IFT_FDDI;
568	ifp->if_addrlen = FDDI_ADDR_LEN;
569	ifp->if_hdrlen = 21;
570
571	if_attach(ifp);         /* Must be called before additional assignments */
572
573	ifp->if_mtu = FDDIMTU;
574	ifp->if_output = fddi_output;
575	ifp->if_input = fddi_input;
576	ifp->if_resolvemulti = fddi_resolvemulti;
577	ifp->if_broadcastaddr = fddibroadcastaddr;
578	ifp->if_baudrate = 100000000;
579#ifdef IFF_NOTRAILERS
580	ifp->if_flags |= IFF_NOTRAILERS;
581#endif
582	ifa = ifp->if_addr;
583	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
584
585	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
586	sdl->sdl_type = IFT_FDDI;
587	sdl->sdl_alen = ifp->if_addrlen;
588	bcopy(lla, LLADDR(sdl), ifp->if_addrlen);
589
590	if (bpf)
591		bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN);
592
593	return;
594}
595
596void
597fddi_ifdetach(ifp, bpf)
598	struct ifnet *ifp;
599	int bpf;
600{
601
602	if (bpf)
603		bpfdetach(ifp);
604
605	if_detach(ifp);
606
607	return;
608}
609
610int
611fddi_ioctl (ifp, command, data)
612	struct ifnet *ifp;
613	int command;
614	caddr_t data;
615{
616	struct ifaddr *ifa;
617	struct ifreq *ifr;
618	int error;
619
620	ifa = (struct ifaddr *) data;
621	ifr = (struct ifreq *) data;
622	error = 0;
623
624	switch (command) {
625	case SIOCSIFADDR:
626		ifp->if_flags |= IFF_UP;
627
628		switch (ifa->ifa_addr->sa_family) {
629#ifdef INET
630		case AF_INET:	/* before arpwhohas */
631			ifp->if_init(ifp->if_softc);
632			arp_ifinit(ifp, ifa);
633			break;
634#endif
635#ifdef IPX
636		/*
637		 * XXX - This code is probably wrong
638		 */
639		case AF_IPX: {
640				struct ipx_addr *ina;
641
642				ina = &(IA_SIPX(ifa)->sipx_addr);
643
644				if (ipx_nullhost(*ina)) {
645					ina->x_host = *(union ipx_host *)
646							IF_LLADDR(ifp);
647				} else {
648					bcopy((caddr_t) ina->x_host.c_host,
649					      (caddr_t) IF_LLADDR(ifp),
650					      ETHER_ADDR_LEN);
651				}
652
653				/*
654				 * Set new address
655				 */
656				ifp->if_init(ifp->if_softc);
657			}
658			break;
659#endif
660		default:
661			ifp->if_init(ifp->if_softc);
662			break;
663		}
664		break;
665	case SIOCGIFADDR: {
666			struct sockaddr *sa;
667
668			sa = (struct sockaddr *) & ifr->ifr_data;
669			bcopy(IF_LLADDR(ifp),
670			      (caddr_t) sa->sa_data, FDDI_ADDR_LEN);
671
672		}
673		break;
674	case SIOCSIFMTU:
675		/*
676		 * Set the interface MTU.
677		 */
678		if (ifr->ifr_mtu > FDDIMTU) {
679			error = EINVAL;
680		} else {
681			ifp->if_mtu = ifr->ifr_mtu;
682		}
683		break;
684	default:
685		error = EINVAL;
686		break;
687	}
688
689	return (error);
690}
691
692static int
693fddi_resolvemulti(ifp, llsa, sa)
694	struct ifnet *ifp;
695	struct sockaddr **llsa;
696	struct sockaddr *sa;
697{
698	struct sockaddr_dl *sdl;
699#ifdef INET
700	struct sockaddr_in *sin;
701#endif
702#ifdef INET6
703	struct sockaddr_in6 *sin6;
704#endif
705	u_char *e_addr;
706
707	switch(sa->sa_family) {
708	case AF_LINK:
709		/*
710		 * No mapping needed. Just check that it's a valid MC address.
711		 */
712		sdl = (struct sockaddr_dl *)sa;
713		e_addr = LLADDR(sdl);
714		if ((e_addr[0] & 1) != 1)
715			return (EADDRNOTAVAIL);
716		*llsa = 0;
717		return (0);
718
719#ifdef INET
720	case AF_INET:
721		sin = (struct sockaddr_in *)sa;
722		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
723			return (EADDRNOTAVAIL);
724		sdl = malloc(sizeof *sdl, M_IFMADDR,
725		       M_NOWAIT | M_ZERO);
726		if (sdl == NULL)
727			return (ENOMEM);
728		sdl->sdl_len = sizeof *sdl;
729		sdl->sdl_family = AF_LINK;
730		sdl->sdl_index = ifp->if_index;
731		sdl->sdl_type = IFT_FDDI;
732		sdl->sdl_nlen = 0;
733		sdl->sdl_alen = FDDI_ADDR_LEN;
734		sdl->sdl_slen = 0;
735		e_addr = LLADDR(sdl);
736		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
737		*llsa = (struct sockaddr *)sdl;
738		return (0);
739#endif
740#ifdef INET6
741	case AF_INET6:
742		sin6 = (struct sockaddr_in6 *)sa;
743		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
744			/*
745			 * An IP6 address of 0 means listen to all
746			 * of the Ethernet multicast address used for IP6.
747			 * (This is used for multicast routers.)
748			 */
749			ifp->if_flags |= IFF_ALLMULTI;
750			*llsa = 0;
751			return (0);
752		}
753		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
754			return (EADDRNOTAVAIL);
755		sdl = malloc(sizeof *sdl, M_IFMADDR,
756		       M_NOWAIT | M_ZERO);
757		if (sdl == NULL)
758			return (ENOMEM);
759		sdl->sdl_len = sizeof *sdl;
760		sdl->sdl_family = AF_LINK;
761		sdl->sdl_index = ifp->if_index;
762		sdl->sdl_type = IFT_FDDI;
763		sdl->sdl_nlen = 0;
764		sdl->sdl_alen = FDDI_ADDR_LEN;
765		sdl->sdl_slen = 0;
766		e_addr = LLADDR(sdl);
767		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
768		*llsa = (struct sockaddr *)sdl;
769		return (0);
770#endif
771
772	default:
773		/*
774		 * Well, the text isn't quite right, but it's the name
775		 * that counts...
776		 */
777		return (EAFNOSUPPORT);
778	}
779
780	return (0);
781}
782
783static moduledata_t fddi_mod = {
784	"fddi",	/* module name */
785	NULL,	/* event handler */
786	0	/* extra data */
787};
788
789DECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
790MODULE_VERSION(fddi, 1);
791