if_fddisubr.c revision 177599
1139823Simp/*-
221830Sjoerg * Copyright (c) 1995, 1996
321830Sjoerg *	Matt Thomas <matt@3am-software.com>.  All rights reserved.
47055Sdg * Copyright (c) 1982, 1989, 1993
57055Sdg *	The Regents of the University of California.  All rights reserved.
67055Sdg *
77055Sdg * Redistribution and use in source and binary forms, with or without
87055Sdg * modification, are permitted provided that the following conditions
97055Sdg * are met:
107055Sdg * 1. Redistributions of source code must retain the above copyright
117055Sdg *    notice, this list of conditions and the following disclaimer.
127055Sdg * 2. Redistributions in binary form must reproduce the above copyright
137055Sdg *    notice, this list of conditions and the following disclaimer in the
147055Sdg *    documentation and/or other materials provided with the distribution.
157055Sdg * 3. All advertising materials mentioning features or use of this software
167055Sdg *    must display the following acknowledgement:
177055Sdg *	This product includes software developed by the University of
187055Sdg *	California, Berkeley and its contributors.
197055Sdg * 4. Neither the name of the University nor the names of its contributors
207055Sdg *    may be used to endorse or promote products derived from this software
217055Sdg *    without specific prior written permission.
227055Sdg *
237055Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
247055Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
257055Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
267055Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
277055Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
287055Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
297055Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
307055Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
317055Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
327055Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
337055Sdg * SUCH DAMAGE.
347055Sdg *
357061Sdg *	from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
3650477Speter * $FreeBSD: head/sys/net/if_fddisubr.c 177599 2008-03-25 09:39:02Z ru $
377055Sdg */
387055Sdg
3932356Seivind#include "opt_atalk.h"
4032350Seivind#include "opt_inet.h"
4154263Sshin#include "opt_inet6.h"
4231742Seivind#include "opt_ipx.h"
43105577Srwatson#include "opt_mac.h"
4431742Seivind
457055Sdg#include <sys/param.h>
467055Sdg#include <sys/systm.h>
4793375Smdodd#include <sys/kernel.h>
4893375Smdodd#include <sys/malloc.h>
497055Sdg#include <sys/mbuf.h>
5093375Smdodd#include <sys/module.h>
517055Sdg#include <sys/socket.h>
5293375Smdodd#include <sys/sockio.h>
537055Sdg
547055Sdg#include <net/if.h>
55112271Smdodd#include <net/if_dl.h>
567055Sdg#include <net/if_llc.h>
577055Sdg#include <net/if_types.h>
58112271Smdodd
5993375Smdodd#include <net/netisr.h>
6093375Smdodd#include <net/route.h>
6193375Smdodd#include <net/bpf.h>
6293373Smdodd#include <net/fddi.h>
637055Sdg
6454263Sshin#if defined(INET) || defined(INET6)
657055Sdg#include <netinet/in.h>
667055Sdg#include <netinet/in_var.h>
6732350Seivind#include <netinet/if_ether.h>
687055Sdg#endif
6954263Sshin#ifdef INET6
7054263Sshin#include <netinet6/nd6.h>
7154263Sshin#endif
727055Sdg
7311819Sjulian#ifdef IPX
7421830Sjoerg#include <netipx/ipx.h>
7511819Sjulian#include <netipx/ipx_if.h>
7611819Sjulian#endif
7711819Sjulian
787055Sdg#ifdef DECNET
797055Sdg#include <netdnet/dn.h>
807055Sdg#endif
817055Sdg
8221830Sjoerg#ifdef NETATALK
8321830Sjoerg#include <netatalk/at.h>
8421830Sjoerg#include <netatalk/at_var.h>
8521830Sjoerg#include <netatalk/at_extern.h>
8621830Sjoerg
8721830Sjoergextern u_char	at_org_code[ 3 ];
8821830Sjoergextern u_char	aarp_org_code[ 3 ];
8921830Sjoerg#endif /* NETATALK */
9021830Sjoerg
91163606Srwatson#include <security/mac/mac_framework.h>
92163606Srwatson
93126788Srwatsonstatic const u_char fddibroadcastaddr[FDDI_ADDR_LEN] =
9493382Smdodd			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
9593382Smdodd
9693383Smdoddstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
9793084Sbde			      struct sockaddr *);
9893383Smdoddstatic int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *,
9993383Smdodd		       struct rtentry *);
100106939Ssamstatic void fddi_input(struct ifnet *ifp, struct mbuf *m);
10168180Sume
102112276Smdodd#define	senderr(e)	do { error = (e); goto bad; } while (0)
10393369Smdodd
1047055Sdg/*
1057055Sdg * FDDI output routine.
1067055Sdg * Encapsulate a packet of type family for the local net.
1077055Sdg * Use trailer local net encapsulation if enough data in first
1087055Sdg * packet leaves a multiple of 512 bytes of data in remainder.
1097055Sdg * Assumes that ifp is actually pointer to arpcom structure.
1107055Sdg */
11193383Smdoddstatic int
11254799Sgreenfddi_output(ifp, m, dst, rt0)
11393367Smdodd	struct ifnet *ifp;
11454799Sgreen	struct mbuf *m;
1157055Sdg	struct sockaddr *dst;
1167055Sdg	struct rtentry *rt0;
1177055Sdg{
11821830Sjoerg	u_int16_t type;
11969152Sjlemon	int loop_copy = 0, error = 0, hdrcmplt = 0;
12093373Smdodd 	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
12193367Smdodd	struct fddi_header *fh;
1227055Sdg
123105577Srwatson#ifdef MAC
124172930Srwatson	error = mac_ifnet_check_transmit(ifp, m);
125105577Srwatson	if (error)
126105577Srwatson		senderr(error);
127105577Srwatson#endif
128105577Srwatson
129112308Smdodd	if (ifp->if_flags & IFF_MONITOR)
130112308Smdodd		senderr(ENETDOWN);
131148887Srwatson	if (!((ifp->if_flags & IFF_UP) &&
132148887Srwatson	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
1337055Sdg		senderr(ENETDOWN);
13434961Sphk	getmicrotime(&ifp->if_lastchange);
135111767Smdodd
1367055Sdg	switch (dst->sa_family) {
1377055Sdg#ifdef INET
13821830Sjoerg	case AF_INET: {
139128636Sluigi		error = arpresolve(ifp, rt0, m, dst, edst);
140128636Sluigi		if (error)
141128636Sluigi			return (error == EWOULDBLOCK ? 0 : error);
14221830Sjoerg		type = htons(ETHERTYPE_IP);
1437055Sdg		break;
14421830Sjoerg	}
145126951Smdodd	case AF_ARP:
146126951Smdodd	{
147126951Smdodd		struct arphdr *ah;
148126951Smdodd		ah = mtod(m, struct arphdr *);
149126951Smdodd		ah->ar_hrd = htons(ARPHRD_ETHER);
150126951Smdodd
151126951Smdodd		loop_copy = -1; /* if this is for us, don't do it */
152126951Smdodd
153126951Smdodd		switch (ntohs(ah->ar_op)) {
154126951Smdodd		case ARPOP_REVREQUEST:
155126951Smdodd		case ARPOP_REVREPLY:
156126951Smdodd			type = htons(ETHERTYPE_REVARP);
157126951Smdodd			break;
158126951Smdodd		case ARPOP_REQUEST:
159126951Smdodd		case ARPOP_REPLY:
160126951Smdodd		default:
161126951Smdodd			type = htons(ETHERTYPE_ARP);
162126951Smdodd			break;
163126951Smdodd		}
164126951Smdodd
165126951Smdodd		if (m->m_flags & M_BCAST)
166126951Smdodd			bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN);
167126951Smdodd                else
168126951Smdodd			bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN);
169126951Smdodd
170126951Smdodd	}
171126951Smdodd	break;
172112266Smdodd#endif /* INET */
17354263Sshin#ifdef INET6
17454263Sshin	case AF_INET6:
175128636Sluigi		error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst);
176128636Sluigi		if (error)
177128636Sluigi			return (error); /* Something bad happened */
17854263Sshin		type = htons(ETHERTYPE_IPV6);
17954263Sshin		break;
180112266Smdodd#endif /* INET6 */
18111819Sjulian#ifdef IPX
18211819Sjulian	case AF_IPX:
18321830Sjoerg		type = htons(ETHERTYPE_IPX);
18411819Sjulian 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
18593373Smdodd		    (caddr_t)edst, FDDI_ADDR_LEN);
18611819Sjulian		break;
187112266Smdodd#endif /* IPX */
18821830Sjoerg#ifdef NETATALK
18921830Sjoerg	case AF_APPLETALK: {
19021830Sjoerg	    struct at_ifaddr *aa;
191128636Sluigi            if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst))
19221830Sjoerg                return (0);
19321830Sjoerg	    /*
19421830Sjoerg	     * ifaddr is the first thing in at_ifaddr
19521830Sjoerg	     */
19630834Sjulian	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
19721830Sjoerg		goto bad;
19821830Sjoerg
19921830Sjoerg	    /*
20021830Sjoerg	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
20121830Sjoerg	     * Since we must preserve the value of m, which is passed to us by
20221830Sjoerg	     * value, we m_copy() the first mbuf, and use it for our llc header.
20321830Sjoerg	     */
20421830Sjoerg	    if (aa->aa_flags & AFA_PHASE2) {
20521830Sjoerg		struct llc llc;
20621830Sjoerg
207177599Sru		M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAIT);
20821830Sjoerg		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
20921830Sjoerg		llc.llc_control = LLC_UI;
21093371Smdodd		bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code));
21193371Smdodd		llc.llc_snap.ether_type = htons(ETHERTYPE_AT);
21293373Smdodd		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
21321830Sjoerg		type = 0;
21421830Sjoerg	    } else {
21521830Sjoerg		type = htons(ETHERTYPE_AT);
21621830Sjoerg	    }
21721830Sjoerg	    break;
21821830Sjoerg	}
21921830Sjoerg#endif /* NETATALK */
2207055Sdg
22152248Smsmith	case pseudo_AF_HDRCMPLT:
22252248Smsmith	{
22393376Smdodd		struct ether_header *eh;
22452248Smsmith		hdrcmplt = 1;
22593376Smdodd		eh = (struct ether_header *)dst->sa_data;
22693376Smdodd		bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN);
22752248Smsmith		/* FALLTHROUGH */
22852248Smsmith	}
22952248Smsmith
2307055Sdg	case AF_UNSPEC:
2317055Sdg	{
2327055Sdg		struct ether_header *eh;
23336992Sjulian		loop_copy = -1;
2347055Sdg		eh = (struct ether_header *)dst->sa_data;
23593375Smdodd		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN);
2367055Sdg		if (*edst & 1)
2377055Sdg			m->m_flags |= (M_BCAST|M_MCAST);
2387055Sdg		type = eh->ether_type;
2397055Sdg		break;
2407055Sdg	}
2417055Sdg
2427055Sdg	case AF_IMPLINK:
2437055Sdg	{
2447055Sdg		fh = mtod(m, struct fddi_header *);
2457055Sdg		error = EPROTONOSUPPORT;
2467055Sdg		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
2477055Sdg			case FDDIFC_LLC_ASYNC: {
2487055Sdg				/* legal priorities are 0 through 7 */
2497055Sdg				if ((fh->fddi_fc & FDDIFC_Z) > 7)
2507055Sdg			        	goto bad;
2517055Sdg				break;
2527055Sdg			}
2537055Sdg			case FDDIFC_LLC_SYNC: {
2547055Sdg				/* FDDIFC_Z bits reserved, must be zero */
2557055Sdg				if (fh->fddi_fc & FDDIFC_Z)
2567055Sdg					goto bad;
2577055Sdg				break;
2587055Sdg			}
2597055Sdg			case FDDIFC_SMT: {
2607055Sdg				/* FDDIFC_Z bits must be non zero */
2617055Sdg				if ((fh->fddi_fc & FDDIFC_Z) == 0)
2627055Sdg					goto bad;
2637055Sdg				break;
2647055Sdg			}
2657055Sdg			default: {
2667055Sdg				/* anything else is too dangerous */
2677055Sdg               	 		goto bad;
2687055Sdg			}
2697055Sdg		}
2707055Sdg		error = 0;
2717055Sdg		if (fh->fddi_dhost[0] & 1)
2727055Sdg			m->m_flags |= (M_BCAST|M_MCAST);
2737055Sdg		goto queue_it;
2747055Sdg	}
2757055Sdg	default:
276105598Sbrooks		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
2777055Sdg		senderr(EAFNOSUPPORT);
2787055Sdg	}
2797055Sdg
28093380Smdodd	/*
28193380Smdodd	 * Add LLC header.
28293380Smdodd	 */
2837055Sdg	if (type != 0) {
28493367Smdodd		struct llc *l;
285111119Simp		M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
2867055Sdg		if (m == 0)
2877055Sdg			senderr(ENOBUFS);
2887055Sdg		l = mtod(m, struct llc *);
2897055Sdg		l->llc_control = LLC_UI;
2907055Sdg		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
291112266Smdodd		l->llc_snap.org_code[0] =
292112266Smdodd			l->llc_snap.org_code[1] =
293112266Smdodd			l->llc_snap.org_code[2] = 0;
294112266Smdodd		l->llc_snap.ether_type = htons(type);
2957055Sdg	}
29636908Sjulian
2977055Sdg	/*
2987055Sdg	 * Add local net header.  If no space in first mbuf,
2997055Sdg	 * allocate another.
3007055Sdg	 */
301111119Simp	M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT);
3027055Sdg	if (m == 0)
3037055Sdg		senderr(ENOBUFS);
3047055Sdg	fh = mtod(m, struct fddi_header *);
3057055Sdg	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
30693375Smdodd	bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN);
3077055Sdg  queue_it:
30852248Smsmith	if (hdrcmplt)
30993375Smdodd		bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN);
31052248Smsmith	else
311152315Sru		bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost,
31293373Smdodd			FDDI_ADDR_LEN);
31393377Smdodd
31436908Sjulian	/*
31536908Sjulian	 * If a simplex interface, and the packet is being sent to our
31636908Sjulian	 * Ethernet address or a broadcast address, loopback a copy.
31736908Sjulian	 * XXX To make a simplex device behave exactly like a duplex
31836908Sjulian	 * device, we should copy in the case of sending to our own
31936908Sjulian	 * ethernet address (thus letting the original actually appear
32036908Sjulian	 * on the wire). However, we don't do that here for security
32136908Sjulian	 * reasons and compatibility with the original behavior.
32236908Sjulian	 */
32393377Smdodd	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
324112279Smdodd		if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
325112279Smdodd			struct mbuf *n;
326112279Smdodd			n = m_copy(m, 0, (int)M_COPYALL);
327112279Smdodd			(void) if_simloop(ifp, n, dst->sa_family,
328112279Smdodd					  FDDI_HDR_LEN);
329112279Smdodd	     	} else if (bcmp(fh->fddi_dhost, fh->fddi_shost,
330112279Smdodd				FDDI_ADDR_LEN) == 0) {
331112279Smdodd			(void) if_simloop(ifp, m, dst->sa_family,
332112279Smdodd					  FDDI_HDR_LEN);
33393369Smdodd			return (0);	/* XXX */
33436908Sjulian		}
33536908Sjulian	}
33636908Sjulian
337130549Smlaier	IFQ_HANDOFF(ifp, m, error);
338130549Smlaier	if (error)
339130549Smlaier		ifp->if_oerrors++;
340130549Smlaier
3417055Sdg	return (error);
3427055Sdg
3437055Sdgbad:
34493379Smdodd	ifp->if_oerrors++;
3457055Sdg	if (m)
3467055Sdg		m_freem(m);
3477055Sdg	return (error);
3487055Sdg}
3497055Sdg
3507055Sdg/*
351112308Smdodd * Process a received FDDI packet.
3527055Sdg */
353106939Ssamstatic void
354106939Ssamfddi_input(ifp, m)
3557055Sdg	struct ifnet *ifp;
3567055Sdg	struct mbuf *m;
3577055Sdg{
358111888Sjlemon	int isr;
35993367Smdodd	struct llc *l;
360106939Ssam	struct fddi_header *fh;
3617055Sdg
362112308Smdodd	/*
363112308Smdodd	 * Do consistency checks to verify assumptions
364112308Smdodd	 * made by code past this point.
365112308Smdodd	 */
366112308Smdodd	if ((m->m_flags & M_PKTHDR) == 0) {
367112308Smdodd		if_printf(ifp, "discard frame w/o packet header\n");
368112308Smdodd		ifp->if_ierrors++;
369112308Smdodd		m_freem(m);
370112308Smdodd		return;
371112308Smdodd	}
372112308Smdodd	if (m->m_pkthdr.rcvif == NULL) {
373112308Smdodd		if_printf(ifp, "discard frame w/o interface pointer\n");
374112308Smdodd		ifp->if_ierrors++;
375112308Smdodd		m_freem(m);
376112308Smdodd		return;
377112308Smdodd        }
378112308Smdodd
379112308Smdodd	m = m_pullup(m, FDDI_HDR_LEN);
380112308Smdodd	if (m == NULL) {
381112308Smdodd		ifp->if_ierrors++;
382112308Smdodd		goto dropanyway;
383112308Smdodd	}
384106939Ssam	fh = mtod(m, struct fddi_header *);
385112308Smdodd	m->m_pkthdr.header = (void *)fh;
386106939Ssam
38793379Smdodd	/*
38893379Smdodd	 * Discard packet if interface is not up.
38993379Smdodd	 */
390148887Srwatson	if (!((ifp->if_flags & IFF_UP) &&
391148887Srwatson	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
39293379Smdodd		goto dropanyway;
39393379Smdodd
394112308Smdodd	/*
395112308Smdodd	 * Give bpf a chance at the packet.
396112308Smdodd	 */
397112308Smdodd	BPF_MTAP(ifp, m);
398112308Smdodd
399112308Smdodd	/*
400112308Smdodd	 * Interface marked for monitoring; discard packet.
401112308Smdodd	 */
402112308Smdodd	if (ifp->if_flags & IFF_MONITOR) {
403112308Smdodd		m_freem(m);
404112308Smdodd		return;
405112308Smdodd	}
406112308Smdodd
407105577Srwatson#ifdef MAC
408172930Srwatson	mac_ifnet_create_mbuf(ifp, m);
409105577Srwatson#endif
410105577Srwatson
41193379Smdodd	/*
412112287Smdodd	 * Update interface statistics.
413112287Smdodd	 */
414112287Smdodd	ifp->if_ibytes += m->m_pkthdr.len;
415112287Smdodd	getmicrotime(&ifp->if_lastchange);
416112287Smdodd
417112287Smdodd	/*
41893379Smdodd	 * Discard non local unicast packets when interface
41993379Smdodd	 * is in promiscuous mode.
42093379Smdodd	 */
42193379Smdodd	if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) &&
422152315Sru	    (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost,
42393379Smdodd	     FDDI_ADDR_LEN) != 0))
42493379Smdodd		goto dropanyway;
42593379Smdodd
42693379Smdodd	/*
42793379Smdodd	 * Set mbuf flags for bcast/mcast.
42893379Smdodd	 */
42921830Sjoerg	if (fh->fddi_dhost[0] & 1) {
430121436Simp		if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost,
431121436Simp		    FDDI_ADDR_LEN) == 0)
43221830Sjoerg			m->m_flags |= M_BCAST;
43321830Sjoerg		else
43421830Sjoerg			m->m_flags |= M_MCAST;
4357055Sdg		ifp->if_imcasts++;
43621830Sjoerg	}
4377055Sdg
43821830Sjoerg#ifdef M_LINK0
43921830Sjoerg	/*
44021830Sjoerg	 * If this has a LLC priority of 0, then mark it so upper
44121830Sjoerg	 * layers have a hint that it really came via a FDDI/Ethernet
44221830Sjoerg	 * bridge.
44321830Sjoerg	 */
44421830Sjoerg	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
44521830Sjoerg		m->m_flags |= M_LINK0;
44621830Sjoerg#endif
44721830Sjoerg
448106939Ssam	/* Strip off FDDI header. */
449111790Smdodd	m_adj(m, FDDI_HDR_LEN);
450106939Ssam
451111790Smdodd	m = m_pullup(m, LLC_SNAPFRAMELEN);
45293379Smdodd	if (m == 0) {
45393379Smdodd		ifp->if_ierrors++;
45493379Smdodd		goto dropanyway;
45593379Smdodd	}
4567055Sdg	l = mtod(m, struct llc *);
45793377Smdodd
4587055Sdg	switch (l->llc_dsap) {
4597055Sdg	case LLC_SNAP_LSAP:
4607055Sdg	{
46121830Sjoerg		u_int16_t type;
462112266Smdodd		if ((l->llc_control != LLC_UI) ||
463112266Smdodd		    (l->llc_ssap != LLC_SNAP_LSAP)) {
46493379Smdodd			ifp->if_noproto++;
4657055Sdg			goto dropanyway;
46693379Smdodd		}
46721830Sjoerg#ifdef NETATALK
468128396Sluigi		if (bcmp(&(l->llc_snap.org_code)[0], at_org_code,
469111888Sjlemon		    sizeof(at_org_code)) == 0 &&
470111888Sjlemon		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) {
471111888Sjlemon			isr = NETISR_ATALK2;
472111888Sjlemon			m_adj(m, LLC_SNAPFRAMELEN);
473111888Sjlemon			break;
47421830Sjoerg		}
47521830Sjoerg
476128396Sluigi		if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code,
477111888Sjlemon		    sizeof(aarp_org_code)) == 0 &&
478111888Sjlemon		    ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) {
479111888Sjlemon			m_adj(m, LLC_SNAPFRAMELEN);
480111888Sjlemon			isr = NETISR_AARP;
481111888Sjlemon			break;
48221830Sjoerg		}
48321830Sjoerg#endif /* NETATALK */
48493377Smdodd		if (l->llc_snap.org_code[0] != 0 ||
48593377Smdodd		    l->llc_snap.org_code[1] != 0 ||
48693379Smdodd		    l->llc_snap.org_code[2] != 0) {
48793379Smdodd			ifp->if_noproto++;
4887055Sdg			goto dropanyway;
48993379Smdodd		}
49093377Smdodd
49121830Sjoerg		type = ntohs(l->llc_snap.ether_type);
49293377Smdodd		m_adj(m, LLC_SNAPFRAMELEN);
49393377Smdodd
49421830Sjoerg		switch (type) {
4957055Sdg#ifdef INET
4967055Sdg		case ETHERTYPE_IP:
497154518Sandre			if ((m = ip_fastforward(m)) == NULL)
49836192Sdg				return;
499111888Sjlemon			isr = NETISR_IP;
5007055Sdg			break;
5017055Sdg
5027055Sdg		case ETHERTYPE_ARP:
50378295Sjlemon			if (ifp->if_flags & IFF_NOARP)
50478295Sjlemon				goto dropanyway;
505111888Sjlemon			isr = NETISR_ARP;
5067055Sdg			break;
5077055Sdg#endif
50854263Sshin#ifdef INET6
50954263Sshin		case ETHERTYPE_IPV6:
510111888Sjlemon			isr = NETISR_IPV6;
51154263Sshin			break;
51254263Sshin#endif
51321830Sjoerg#ifdef IPX
51421830Sjoerg		case ETHERTYPE_IPX:
515111888Sjlemon			isr = NETISR_IPX;
51621830Sjoerg			break;
51721830Sjoerg#endif
5187055Sdg#ifdef DECNET
51921830Sjoerg		case ETHERTYPE_DECNET:
520111888Sjlemon			isr = NETISR_DECNET;
5217055Sdg			break;
5227055Sdg#endif
52321830Sjoerg#ifdef NETATALK
52421830Sjoerg		case ETHERTYPE_AT:
525111888Sjlemon	                isr = NETISR_ATALK1;
52621830Sjoerg			break;
52721830Sjoerg	        case ETHERTYPE_AARP:
528111888Sjlemon			isr = NETISR_AARP;
529111888Sjlemon			break;
53021830Sjoerg#endif /* NETATALK */
5317055Sdg		default:
53221830Sjoerg			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
5337055Sdg			ifp->if_noproto++;
5347055Sdg			goto dropanyway;
5357055Sdg		}
5367055Sdg		break;
5377055Sdg	}
53821830Sjoerg
5397055Sdg	default:
54021830Sjoerg		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
5417055Sdg		ifp->if_noproto++;
54293377Smdodd		goto dropanyway;
5437055Sdg	}
544111888Sjlemon	netisr_dispatch(isr, m);
54593377Smdodd	return;
54693377Smdodd
54793377Smdodddropanyway:
54893377Smdodd	ifp->if_iqdrops++;
54993377Smdodd	if (m)
55093377Smdodd		m_freem(m);
55193377Smdodd	return;
5527055Sdg}
55393380Smdodd
5547055Sdg/*
5557055Sdg * Perform common duties while attaching to interface list
5567055Sdg */
5577055Sdgvoid
558152296Srufddi_ifattach(ifp, lla, bpf)
55993367Smdodd	struct ifnet *ifp;
560152296Sru	const u_int8_t *lla;
56193383Smdodd	int bpf;
5627055Sdg{
56393367Smdodd	struct ifaddr *ifa;
56493367Smdodd	struct sockaddr_dl *sdl;
5657055Sdg
5667055Sdg	ifp->if_type = IFT_FDDI;
56793373Smdodd	ifp->if_addrlen = FDDI_ADDR_LEN;
5687055Sdg	ifp->if_hdrlen = 21;
56993379Smdodd
57093379Smdodd	if_attach(ifp);         /* Must be called before additional assignments */
57193379Smdodd
5727055Sdg	ifp->if_mtu = FDDIMTU;
57393379Smdodd	ifp->if_output = fddi_output;
574106939Ssam	ifp->if_input = fddi_input;
57568180Sume	ifp->if_resolvemulti = fddi_resolvemulti;
57693379Smdodd	ifp->if_broadcastaddr = fddibroadcastaddr;
57716063Sgpalmer	ifp->if_baudrate = 100000000;
57821830Sjoerg#ifdef IFF_NOTRAILERS
57921830Sjoerg	ifp->if_flags |= IFF_NOTRAILERS;
58021830Sjoerg#endif
581152315Sru	ifa = ifp->if_addr;
582152315Sru	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
58393379Smdodd
58421831Sjoerg	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
58521831Sjoerg	sdl->sdl_type = IFT_FDDI;
58621831Sjoerg	sdl->sdl_alen = ifp->if_addrlen;
587152296Sru	bcopy(lla, LLADDR(sdl), ifp->if_addrlen);
58893379Smdodd
58993383Smdodd	if (bpf)
59093383Smdodd		bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN);
59193383Smdodd
59293379Smdodd	return;
5937055Sdg}
59468180Sume
59593382Smdoddvoid
59693382Smdoddfddi_ifdetach(ifp, bpf)
59793382Smdodd	struct ifnet *ifp;
59893382Smdodd	int bpf;
59993382Smdodd{
60093382Smdodd
60193382Smdodd	if (bpf)
60293382Smdodd		bpfdetach(ifp);
60393382Smdodd
60493382Smdodd	if_detach(ifp);
60593382Smdodd
60693382Smdodd	return;
60793382Smdodd}
60893382Smdodd
60993382Smdoddint
61093382Smdoddfddi_ioctl (ifp, command, data)
61193382Smdodd	struct ifnet *ifp;
61293382Smdodd	int command;
61393382Smdodd	caddr_t data;
61493382Smdodd{
61593382Smdodd	struct ifaddr *ifa;
61693382Smdodd	struct ifreq *ifr;
61793382Smdodd	int error;
61893382Smdodd
61993382Smdodd	ifa = (struct ifaddr *) data;
62093382Smdodd	ifr = (struct ifreq *) data;
62193382Smdodd	error = 0;
62293382Smdodd
62393382Smdodd	switch (command) {
62493382Smdodd	case SIOCSIFADDR:
62593382Smdodd		ifp->if_flags |= IFF_UP;
62693382Smdodd
62793382Smdodd		switch (ifa->ifa_addr->sa_family) {
62893382Smdodd#ifdef INET
62993382Smdodd		case AF_INET:	/* before arpwhohas */
63093382Smdodd			ifp->if_init(ifp->if_softc);
63193382Smdodd			arp_ifinit(ifp, ifa);
63293382Smdodd			break;
63393382Smdodd#endif
63493382Smdodd#ifdef IPX
63593382Smdodd		/*
63693382Smdodd		 * XXX - This code is probably wrong
63793382Smdodd		 */
63893382Smdodd		case AF_IPX: {
63993382Smdodd				struct ipx_addr *ina;
64093382Smdodd
64193382Smdodd				ina = &(IA_SIPX(ifa)->sipx_addr);
64293382Smdodd
64393382Smdodd				if (ipx_nullhost(*ina)) {
64493382Smdodd					ina->x_host = *(union ipx_host *)
645152315Sru							IF_LLADDR(ifp);
64693382Smdodd				} else {
64793382Smdodd					bcopy((caddr_t) ina->x_host.c_host,
648152315Sru					      (caddr_t) IF_LLADDR(ifp),
649147256Sbrooks					      ETHER_ADDR_LEN);
65093382Smdodd				}
65193382Smdodd
65293382Smdodd				/*
65393382Smdodd				 * Set new address
65493382Smdodd				 */
65593382Smdodd				ifp->if_init(ifp->if_softc);
65693382Smdodd			}
65793382Smdodd			break;
65893382Smdodd#endif
65993382Smdodd		default:
66093382Smdodd			ifp->if_init(ifp->if_softc);
66193382Smdodd			break;
662104302Sphk		}
663144045Smdodd		break;
66493382Smdodd	case SIOCGIFADDR: {
66593382Smdodd			struct sockaddr *sa;
66693382Smdodd
66793382Smdodd			sa = (struct sockaddr *) & ifr->ifr_data;
668152315Sru			bcopy(IF_LLADDR(ifp),
66993382Smdodd			      (caddr_t) sa->sa_data, FDDI_ADDR_LEN);
67093382Smdodd
67193382Smdodd		}
67293382Smdodd		break;
67393382Smdodd	case SIOCSIFMTU:
67493382Smdodd		/*
67593382Smdodd		 * Set the interface MTU.
67693382Smdodd		 */
67793382Smdodd		if (ifr->ifr_mtu > FDDIMTU) {
67893382Smdodd			error = EINVAL;
67993382Smdodd		} else {
68093382Smdodd			ifp->if_mtu = ifr->ifr_mtu;
68193382Smdodd		}
68293382Smdodd		break;
68393382Smdodd	default:
684144045Smdodd		error = EINVAL;
68593382Smdodd		break;
68693382Smdodd	}
68793382Smdodd
68893382Smdodd	return (error);
68993382Smdodd}
69093382Smdodd
69168180Sumestatic int
69268180Sumefddi_resolvemulti(ifp, llsa, sa)
69368180Sume	struct ifnet *ifp;
69468180Sume	struct sockaddr **llsa;
69568180Sume	struct sockaddr *sa;
69668180Sume{
69768180Sume	struct sockaddr_dl *sdl;
69868180Sume	struct sockaddr_in *sin;
69968180Sume#ifdef INET6
70068180Sume	struct sockaddr_in6 *sin6;
70168180Sume#endif
70268180Sume	u_char *e_addr;
70368180Sume
70468180Sume	switch(sa->sa_family) {
70568180Sume	case AF_LINK:
70668180Sume		/*
70768180Sume		 * No mapping needed. Just check that it's a valid MC address.
70868180Sume		 */
70968180Sume		sdl = (struct sockaddr_dl *)sa;
71068180Sume		e_addr = LLADDR(sdl);
71168180Sume		if ((e_addr[0] & 1) != 1)
71293369Smdodd			return (EADDRNOTAVAIL);
71368180Sume		*llsa = 0;
71493369Smdodd		return (0);
71568180Sume
71668180Sume#ifdef INET
71768180Sume	case AF_INET:
71868180Sume		sin = (struct sockaddr_in *)sa;
71968180Sume		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
72093369Smdodd			return (EADDRNOTAVAIL);
72168180Sume		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
722148641Srwatson		       M_NOWAIT | M_ZERO);
723148641Srwatson		if (sdl == NULL)
724148641Srwatson			return (ENOMEM);
72568180Sume		sdl->sdl_len = sizeof *sdl;
72668180Sume		sdl->sdl_family = AF_LINK;
72768180Sume		sdl->sdl_index = ifp->if_index;
72868180Sume		sdl->sdl_type = IFT_FDDI;
72968180Sume		sdl->sdl_nlen = 0;
73093375Smdodd		sdl->sdl_alen = FDDI_ADDR_LEN;
73168180Sume		sdl->sdl_slen = 0;
73268180Sume		e_addr = LLADDR(sdl);
73368180Sume		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
73468180Sume		*llsa = (struct sockaddr *)sdl;
73593369Smdodd		return (0);
73668180Sume#endif
73768180Sume#ifdef INET6
73868180Sume	case AF_INET6:
73968180Sume		sin6 = (struct sockaddr_in6 *)sa;
74068180Sume		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
74168180Sume			/*
74268180Sume			 * An IP6 address of 0 means listen to all
74368180Sume			 * of the Ethernet multicast address used for IP6.
74468180Sume			 * (This is used for multicast routers.)
74568180Sume			 */
74668180Sume			ifp->if_flags |= IFF_ALLMULTI;
74768180Sume			*llsa = 0;
74893369Smdodd			return (0);
74968180Sume		}
75068180Sume		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
75193369Smdodd			return (EADDRNOTAVAIL);
75268180Sume		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
753148641Srwatson		       M_NOWAIT | M_ZERO);
754148641Srwatson		if (sdl == NULL)
755148641Srwatson			return (ENOMEM);
75668180Sume		sdl->sdl_len = sizeof *sdl;
75768180Sume		sdl->sdl_family = AF_LINK;
75868180Sume		sdl->sdl_index = ifp->if_index;
75968180Sume		sdl->sdl_type = IFT_FDDI;
76068180Sume		sdl->sdl_nlen = 0;
76193375Smdodd		sdl->sdl_alen = FDDI_ADDR_LEN;
76268180Sume		sdl->sdl_slen = 0;
76368180Sume		e_addr = LLADDR(sdl);
76468180Sume		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
76568180Sume		*llsa = (struct sockaddr *)sdl;
76693369Smdodd		return (0);
76768180Sume#endif
76868180Sume
76968180Sume	default:
77068180Sume		/*
77168180Sume		 * Well, the text isn't quite right, but it's the name
77268180Sume		 * that counts...
77368180Sume		 */
77493369Smdodd		return (EAFNOSUPPORT);
77568180Sume	}
77693375Smdodd
77793375Smdodd	return (0);
77868180Sume}
77993375Smdodd
78093375Smdoddstatic moduledata_t fddi_mod = {
78193375Smdodd	"fddi",	/* module name */
78293375Smdodd	NULL,	/* event handler */
78393375Smdodd	0	/* extra data */
78493375Smdodd};
78593375Smdodd
78693375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
78793375SmdoddMODULE_VERSION(fddi, 1);
788