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