if_fddisubr.c revision 148887
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 148887 2005-08-09 10:20:02Z rwatson $
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 const 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	senderr(e)	do { error = (e); goto bad; } while (0)
102
103/*
104 * FDDI output routine.
105 * Encapsulate a packet of type family for the local net.
106 * Use trailer local net encapsulation if enough data in first
107 * packet leaves a multiple of 512 bytes of data in remainder.
108 * Assumes that ifp is actually pointer to arpcom structure.
109 */
110static int
111fddi_output(ifp, m, dst, rt0)
112	struct ifnet *ifp;
113	struct mbuf *m;
114	struct sockaddr *dst;
115	struct rtentry *rt0;
116{
117	u_int16_t type;
118	int loop_copy = 0, error = 0, hdrcmplt = 0;
119 	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
120	struct fddi_header *fh;
121
122#ifdef MAC
123	error = mac_check_ifnet_transmit(ifp, m);
124	if (error)
125		senderr(error);
126#endif
127
128	if (ifp->if_flags & IFF_MONITOR)
129		senderr(ENETDOWN);
130	if (!((ifp->if_flags & IFF_UP) &&
131	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
132		senderr(ENETDOWN);
133	getmicrotime(&ifp->if_lastchange);
134
135	switch (dst->sa_family) {
136#ifdef INET
137	case AF_INET: {
138		error = arpresolve(ifp, rt0, m, dst, edst);
139		if (error)
140			return (error == EWOULDBLOCK ? 0 : error);
141		type = htons(ETHERTYPE_IP);
142		break;
143	}
144	case AF_ARP:
145	{
146		struct arphdr *ah;
147		ah = mtod(m, struct arphdr *);
148		ah->ar_hrd = htons(ARPHRD_ETHER);
149
150		loop_copy = -1; /* if this is for us, don't do it */
151
152		switch (ntohs(ah->ar_op)) {
153		case ARPOP_REVREQUEST:
154		case ARPOP_REVREPLY:
155			type = htons(ETHERTYPE_REVARP);
156			break;
157		case ARPOP_REQUEST:
158		case ARPOP_REPLY:
159		default:
160			type = htons(ETHERTYPE_ARP);
161			break;
162		}
163
164		if (m->m_flags & M_BCAST)
165			bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN);
166                else
167			bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN);
168
169	}
170	break;
171#endif /* INET */
172#ifdef INET6
173	case AF_INET6:
174		error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst);
175		if (error)
176			return (error); /* Something bad happened */
177		type = htons(ETHERTYPE_IPV6);
178		break;
179#endif /* INET6 */
180#ifdef IPX
181	case AF_IPX:
182		type = htons(ETHERTYPE_IPX);
183 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
184		    (caddr_t)edst, FDDI_ADDR_LEN);
185		break;
186#endif /* IPX */
187#ifdef NETATALK
188	case AF_APPLETALK: {
189	    struct at_ifaddr *aa;
190            if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst))
191                return (0);
192	    /*
193	     * ifaddr is the first thing in at_ifaddr
194	     */
195	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
196		goto bad;
197
198	    /*
199	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
200	     * Since we must preserve the value of m, which is passed to us by
201	     * value, we m_copy() the first mbuf, and use it for our llc header.
202	     */
203	    if (aa->aa_flags & AFA_PHASE2) {
204		struct llc llc;
205
206		M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT);
207		if (m == 0)
208			senderr(ENOBUFS);
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(IFP2ENADDR(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	IFQ_HANDOFF(ifp, m, error);
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_create_mbuf_from_ifnet(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(IFP2ENADDR(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 (ip_fastforward(m))
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, bpf)
560	struct ifnet *ifp;
561	int bpf;
562{
563	struct ifaddr *ifa;
564	struct sockaddr_dl *sdl;
565
566	ifp->if_type = IFT_FDDI;
567	ifp->if_addrlen = FDDI_ADDR_LEN;
568	ifp->if_hdrlen = 21;
569
570	if_attach(ifp);         /* Must be called before additional assignments */
571
572	ifp->if_mtu = FDDIMTU;
573	ifp->if_output = fddi_output;
574	ifp->if_input = fddi_input;
575	ifp->if_resolvemulti = fddi_resolvemulti;
576	ifp->if_broadcastaddr = fddibroadcastaddr;
577	ifp->if_baudrate = 100000000;
578#ifdef IFF_NOTRAILERS
579	ifp->if_flags |= IFF_NOTRAILERS;
580#endif
581	ifa = ifaddr_byindex(ifp->if_index);
582	if (ifa == NULL) {
583		if_printf(ifp, "%s() no lladdr!\n", __func__);
584		return;
585	}
586
587	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
588	sdl->sdl_type = IFT_FDDI;
589	sdl->sdl_alen = ifp->if_addrlen;
590	bcopy(IFP2ENADDR(ifp), 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							IFP2ENADDR(ifp);
649				} else {
650					bcopy((caddr_t) ina->x_host.c_host,
651					      (caddr_t) IFP2ENADDR(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(IFP2ENADDR(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	struct sockaddr_in *sin;
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		MALLOC(sdl, struct sockaddr_dl *, 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		MALLOC(sdl, struct sockaddr_dl *, 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