if_fddisubr.c revision 111767
17055Sdg/*
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 111767 2003-03-02 21:34:37Z mdodd $
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>
48105577Srwatson#include <sys/mac.h>
4993375Smdodd#include <sys/malloc.h>
507055Sdg#include <sys/mbuf.h>
5193375Smdodd#include <sys/module.h>
527055Sdg#include <sys/socket.h>
5393375Smdodd#include <sys/sockio.h>
547055Sdg
557055Sdg#include <net/if.h>
567055Sdg#include <net/if_llc.h>
577055Sdg#include <net/if_dl.h>
587055Sdg#include <net/if_types.h>
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 NS
797055Sdg#include <netns/ns.h>
807055Sdg#include <netns/ns_if.h>
817055Sdg#endif
827055Sdg
837055Sdg#ifdef DECNET
847055Sdg#include <netdnet/dn.h>
857055Sdg#endif
867055Sdg
8721830Sjoerg#ifdef NETATALK
8821830Sjoerg#include <netatalk/at.h>
8921830Sjoerg#include <netatalk/at_var.h>
9021830Sjoerg#include <netatalk/at_extern.h>
9121830Sjoerg
9221830Sjoergextern u_char	at_org_code[ 3 ];
9321830Sjoergextern u_char	aarp_org_code[ 3 ];
9421830Sjoerg#endif /* NETATALK */
9521830Sjoerg
9693382Smdoddstatic u_char fddibroadcastaddr[FDDI_ADDR_LEN] =
9793382Smdodd			{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
9893382Smdodd
9993383Smdoddstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
10093084Sbde			      struct sockaddr *);
10193383Smdoddstatic int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *,
10293383Smdodd		       struct rtentry *);
103106939Ssamstatic void fddi_input(struct ifnet *ifp, struct mbuf *m);
10468180Sume
10593383Smdodd
10693369Smdodd#define	IFP2AC(IFP)	((struct arpcom *)IFP)
10793369Smdodd#define	senderr(e)	{ error = (e); goto bad; }
10893369Smdodd
1097055Sdg/*
1107055Sdg * FDDI output routine.
1117055Sdg * Encapsulate a packet of type family for the local net.
1127055Sdg * Use trailer local net encapsulation if enough data in first
1137055Sdg * packet leaves a multiple of 512 bytes of data in remainder.
1147055Sdg * Assumes that ifp is actually pointer to arpcom structure.
1157055Sdg */
11693383Smdoddstatic int
11754799Sgreenfddi_output(ifp, m, dst, rt0)
11893367Smdodd	struct ifnet *ifp;
11954799Sgreen	struct mbuf *m;
1207055Sdg	struct sockaddr *dst;
1217055Sdg	struct rtentry *rt0;
1227055Sdg{
12321830Sjoerg	u_int16_t type;
12469152Sjlemon	int loop_copy = 0, error = 0, hdrcmplt = 0;
12593373Smdodd 	u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
12693367Smdodd	struct rtentry *rt;
12793367Smdodd	struct fddi_header *fh;
12893369Smdodd	struct arpcom *ac = IFP2AC(ifp);
1297055Sdg
130105577Srwatson#ifdef MAC
131105577Srwatson	error = mac_check_ifnet_transmit(ifp, m);
132105577Srwatson	if (error)
133105577Srwatson		senderr(error);
134105577Srwatson#endif
135105577Srwatson
1367055Sdg	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
1377055Sdg		senderr(ENETDOWN);
13834961Sphk	getmicrotime(&ifp->if_lastchange);
139111767Smdodd
140111767Smdodd	error = rt_check(&rt, &rt0, dst);
141111767Smdodd	if (error)
142111767Smdodd		goto bad;
143111767Smdodd
1447055Sdg	switch (dst->sa_family) {
1457055Sdg
1467055Sdg#ifdef INET
14721830Sjoerg	case AF_INET: {
14893369Smdodd		if (!arpresolve(ifp, rt, m, dst, edst, rt0))
1497055Sdg			return (0);	/* if not yet resolved */
15021830Sjoerg		type = htons(ETHERTYPE_IP);
1517055Sdg		break;
15221830Sjoerg	}
1537055Sdg#endif
15454263Sshin#ifdef INET6
15554263Sshin	case AF_INET6:
15693375Smdodd		if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) {
15774093Sbmilekic			/* Something bad happened */
15893369Smdodd			return (0);
15954263Sshin		}
16054263Sshin		type = htons(ETHERTYPE_IPV6);
16154263Sshin		break;
16254263Sshin#endif
16311819Sjulian#ifdef IPX
16411819Sjulian	case AF_IPX:
16521830Sjoerg		type = htons(ETHERTYPE_IPX);
16611819Sjulian 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
16793373Smdodd		    (caddr_t)edst, FDDI_ADDR_LEN);
16811819Sjulian		break;
16911819Sjulian#endif
17021830Sjoerg#ifdef NETATALK
17121830Sjoerg	case AF_APPLETALK: {
17221830Sjoerg	    struct at_ifaddr *aa;
17336908Sjulian            if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst))
17421830Sjoerg                return (0);
17521830Sjoerg	    /*
17621830Sjoerg	     * ifaddr is the first thing in at_ifaddr
17721830Sjoerg	     */
17830834Sjulian	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
17921830Sjoerg		goto bad;
18021830Sjoerg
18121830Sjoerg	    /*
18221830Sjoerg	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
18321830Sjoerg	     * Since we must preserve the value of m, which is passed to us by
18421830Sjoerg	     * value, we m_copy() the first mbuf, and use it for our llc header.
18521830Sjoerg	     */
18621830Sjoerg	    if (aa->aa_flags & AFA_PHASE2) {
18721830Sjoerg		struct llc llc;
18821830Sjoerg
189111119Simp		M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT);
19021830Sjoerg		if (m == 0)
19121830Sjoerg			senderr(ENOBUFS);
19221830Sjoerg		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
19321830Sjoerg		llc.llc_control = LLC_UI;
19493371Smdodd		bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code));
19593371Smdodd		llc.llc_snap.ether_type = htons(ETHERTYPE_AT);
19693373Smdodd		bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN);
19721830Sjoerg		type = 0;
19821830Sjoerg	    } else {
19921830Sjoerg		type = htons(ETHERTYPE_AT);
20021830Sjoerg	    }
20121830Sjoerg	    break;
20221830Sjoerg	}
20321830Sjoerg#endif /* NETATALK */
2047055Sdg#ifdef NS
2057055Sdg	case AF_NS:
20621830Sjoerg		type = htons(ETHERTYPE_NS);
2077055Sdg 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
20893373Smdodd		    (caddr_t)edst, FDDI_ADDR_LEN);
2097055Sdg		break;
2107055Sdg#endif
2117055Sdg
21252248Smsmith	case pseudo_AF_HDRCMPLT:
21352248Smsmith	{
21493376Smdodd		struct ether_header *eh;
21552248Smsmith		hdrcmplt = 1;
21693376Smdodd		eh = (struct ether_header *)dst->sa_data;
21793376Smdodd		bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN);
21852248Smsmith		/* FALLTHROUGH */
21952248Smsmith	}
22052248Smsmith
2217055Sdg	case AF_UNSPEC:
2227055Sdg	{
2237055Sdg		struct ether_header *eh;
22436992Sjulian		loop_copy = -1;
2257055Sdg		eh = (struct ether_header *)dst->sa_data;
22693375Smdodd		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN);
2277055Sdg		if (*edst & 1)
2287055Sdg			m->m_flags |= (M_BCAST|M_MCAST);
2297055Sdg		type = eh->ether_type;
2307055Sdg		break;
2317055Sdg	}
2327055Sdg
2337055Sdg	case AF_IMPLINK:
2347055Sdg	{
2357055Sdg		fh = mtod(m, struct fddi_header *);
2367055Sdg		error = EPROTONOSUPPORT;
2377055Sdg		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
2387055Sdg			case FDDIFC_LLC_ASYNC: {
2397055Sdg				/* legal priorities are 0 through 7 */
2407055Sdg				if ((fh->fddi_fc & FDDIFC_Z) > 7)
2417055Sdg			        	goto bad;
2427055Sdg				break;
2437055Sdg			}
2447055Sdg			case FDDIFC_LLC_SYNC: {
2457055Sdg				/* FDDIFC_Z bits reserved, must be zero */
2467055Sdg				if (fh->fddi_fc & FDDIFC_Z)
2477055Sdg					goto bad;
2487055Sdg				break;
2497055Sdg			}
2507055Sdg			case FDDIFC_SMT: {
2517055Sdg				/* FDDIFC_Z bits must be non zero */
2527055Sdg				if ((fh->fddi_fc & FDDIFC_Z) == 0)
2537055Sdg					goto bad;
2547055Sdg				break;
2557055Sdg			}
2567055Sdg			default: {
2577055Sdg				/* anything else is too dangerous */
2587055Sdg               	 		goto bad;
2597055Sdg			}
2607055Sdg		}
2617055Sdg		error = 0;
2627055Sdg		if (fh->fddi_dhost[0] & 1)
2637055Sdg			m->m_flags |= (M_BCAST|M_MCAST);
2647055Sdg		goto queue_it;
2657055Sdg	}
2667055Sdg	default:
267105598Sbrooks		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
2687055Sdg		senderr(EAFNOSUPPORT);
2697055Sdg	}
2707055Sdg
27193380Smdodd	/*
27293380Smdodd	 * Add LLC header.
27393380Smdodd	 */
2747055Sdg	if (type != 0) {
27593367Smdodd		struct llc *l;
276111119Simp		M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
2777055Sdg		if (m == 0)
2787055Sdg			senderr(ENOBUFS);
2797055Sdg		l = mtod(m, struct llc *);
2807055Sdg		l->llc_control = LLC_UI;
2817055Sdg		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
2827055Sdg		l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0;
28393375Smdodd		bcopy((caddr_t)&type, (caddr_t)&l->llc_snap.ether_type,
28421830Sjoerg			sizeof(u_int16_t));
2857055Sdg	}
28636908Sjulian
2877055Sdg	/*
2887055Sdg	 * Add local net header.  If no space in first mbuf,
2897055Sdg	 * allocate another.
2907055Sdg	 */
291111119Simp	M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT);
2927055Sdg	if (m == 0)
2937055Sdg		senderr(ENOBUFS);
2947055Sdg	fh = mtod(m, struct fddi_header *);
2957055Sdg	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
29693375Smdodd	bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN);
2977055Sdg  queue_it:
29852248Smsmith	if (hdrcmplt)
29993375Smdodd		bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN);
30052248Smsmith	else
30193375Smdodd		bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost,
30293373Smdodd			FDDI_ADDR_LEN);
30393377Smdodd
30436908Sjulian	/*
30536908Sjulian	 * If a simplex interface, and the packet is being sent to our
30636908Sjulian	 * Ethernet address or a broadcast address, loopback a copy.
30736908Sjulian	 * XXX To make a simplex device behave exactly like a duplex
30836908Sjulian	 * device, we should copy in the case of sending to our own
30936908Sjulian	 * ethernet address (thus letting the original actually appear
31036908Sjulian	 * on the wire). However, we don't do that here for security
31136908Sjulian	 * reasons and compatibility with the original behavior.
31236908Sjulian	 */
31393377Smdodd	if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
31436908Sjulian		if ((m->m_flags & M_BCAST) || loop_copy) {
31536908Sjulian			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
31636908Sjulian
31736908Sjulian			(void) if_simloop(ifp,
31893373Smdodd				n, dst->sa_family, FDDI_HDR_LEN);
31936908Sjulian	     	} else if (bcmp(fh->fddi_dhost,
32093373Smdodd		    fh->fddi_shost, FDDI_ADDR_LEN) == 0) {
32136908Sjulian			(void) if_simloop(ifp,
32293373Smdodd				m, dst->sa_family, FDDI_HDR_LEN);
32393369Smdodd			return (0);	/* XXX */
32436908Sjulian		}
32536908Sjulian	}
32636908Sjulian
32769152Sjlemon	if (! IF_HANDOFF(&ifp->if_snd, m, ifp))
3287055Sdg		senderr(ENOBUFS);
3297055Sdg	return (error);
3307055Sdg
3317055Sdgbad:
33293379Smdodd	ifp->if_oerrors++;
3337055Sdg	if (m)
3347055Sdg		m_freem(m);
3357055Sdg	return (error);
3367055Sdg}
3377055Sdg
3387055Sdg/*
3397055Sdg * Process a received FDDI packet;
3407055Sdg * the packet is in the mbuf chain m without
3417055Sdg * the fddi header, which is provided separately.
3427055Sdg */
343106939Ssamstatic void
344106939Ssamfddi_input(ifp, m)
3457055Sdg	struct ifnet *ifp;
3467055Sdg	struct mbuf *m;
3477055Sdg{
34893367Smdodd	struct ifqueue *inq;
34993367Smdodd	struct llc *l;
350106939Ssam	struct fddi_header *fh;
3517055Sdg
352106939Ssam	fh = mtod(m, struct fddi_header *);
353106939Ssam
35493379Smdodd	/*
355106939Ssam	 * Update interface statistics.
356106939Ssam	 */
357106939Ssam	ifp->if_ibytes += m->m_pkthdr.len;
358106939Ssam	getmicrotime(&ifp->if_lastchange);
359106939Ssam
360106939Ssam	/*
36193379Smdodd	 * Discard packet if interface is not up.
36293379Smdodd	 */
36393379Smdodd	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
36493379Smdodd		goto dropanyway;
36593379Smdodd
366105577Srwatson#ifdef MAC
367105577Srwatson	mac_create_mbuf_from_ifnet(ifp, m);
368105577Srwatson#endif
369105577Srwatson
37093379Smdodd	/*
37193379Smdodd	 * Discard non local unicast packets when interface
37293379Smdodd	 * is in promiscuous mode.
37393379Smdodd	 */
37493379Smdodd	if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) &&
37593379Smdodd	    (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost,
37693379Smdodd	     FDDI_ADDR_LEN) != 0))
37793379Smdodd		goto dropanyway;
37893379Smdodd
37993379Smdodd	/*
38093379Smdodd	 * Set mbuf flags for bcast/mcast.
38193379Smdodd	 */
38221830Sjoerg	if (fh->fddi_dhost[0] & 1) {
38393381Smdodd		if (bcmp((caddr_t)ifp->if_broadcastaddr,
38493381Smdodd			 (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN) == 0)
38521830Sjoerg			m->m_flags |= M_BCAST;
38621830Sjoerg		else
38721830Sjoerg			m->m_flags |= M_MCAST;
3887055Sdg		ifp->if_imcasts++;
38921830Sjoerg	}
3907055Sdg
39121830Sjoerg#ifdef M_LINK0
39221830Sjoerg	/*
39321830Sjoerg	 * If this has a LLC priority of 0, then mark it so upper
39421830Sjoerg	 * layers have a hint that it really came via a FDDI/Ethernet
39521830Sjoerg	 * bridge.
39621830Sjoerg	 */
39721830Sjoerg	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
39821830Sjoerg		m->m_flags |= M_LINK0;
39921830Sjoerg#endif
40021830Sjoerg
401106939Ssam	/* Strip off FDDI header. */
402106939Ssam	m_adj(m, sizeof(struct fddi_header));
403106939Ssam
40493379Smdodd	m = m_pullup(m, sizeof(struct llc));
40593379Smdodd	if (m == 0) {
40693379Smdodd		ifp->if_ierrors++;
40793379Smdodd		goto dropanyway;
40893379Smdodd	}
4097055Sdg	l = mtod(m, struct llc *);
41093377Smdodd
4117055Sdg	switch (l->llc_dsap) {
4127055Sdg	case LLC_SNAP_LSAP:
4137055Sdg	{
41421830Sjoerg		u_int16_t type;
41593379Smdodd		if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) {
41693379Smdodd			ifp->if_noproto++;
4177055Sdg			goto dropanyway;
41893379Smdodd		}
41921830Sjoerg#ifdef NETATALK
42093371Smdodd		if (Bcmp(&(l->llc_snap.org_code)[0], at_org_code,
42121830Sjoerg			 sizeof(at_org_code)) == 0 &&
42293371Smdodd		 	ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) {
42321830Sjoerg		    inq = &atintrq2;
42493373Smdodd		    m_adj(m, LLC_SNAPFRAMELEN);
42521830Sjoerg		    schednetisr(NETISR_ATALK);
42621830Sjoerg		    break;
42721830Sjoerg		}
42821830Sjoerg
42993371Smdodd		if (Bcmp(&(l->llc_snap.org_code)[0], aarp_org_code,
43021830Sjoerg			 sizeof(aarp_org_code)) == 0 &&
43193371Smdodd			ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) {
43293373Smdodd		    m_adj(m, LLC_SNAPFRAMELEN);
43393369Smdodd		    aarpinput(IFP2AC(ifp), m); /* XXX */
43421830Sjoerg		    return;
43521830Sjoerg		}
43621830Sjoerg#endif /* NETATALK */
43793377Smdodd		if (l->llc_snap.org_code[0] != 0 ||
43893377Smdodd		    l->llc_snap.org_code[1] != 0 ||
43993379Smdodd		    l->llc_snap.org_code[2] != 0) {
44093379Smdodd			ifp->if_noproto++;
4417055Sdg			goto dropanyway;
44293379Smdodd		}
44393377Smdodd
44421830Sjoerg		type = ntohs(l->llc_snap.ether_type);
44593377Smdodd		m_adj(m, LLC_SNAPFRAMELEN);
44693377Smdodd
44721830Sjoerg		switch (type) {
4487055Sdg#ifdef INET
4497055Sdg		case ETHERTYPE_IP:
45036265Sdg			if (ipflow_fastforward(m))
45136192Sdg				return;
4527055Sdg			schednetisr(NETISR_IP);
4537055Sdg			inq = &ipintrq;
4547055Sdg			break;
4557055Sdg
4567055Sdg		case ETHERTYPE_ARP:
45778295Sjlemon			if (ifp->if_flags & IFF_NOARP)
45878295Sjlemon				goto dropanyway;
4597055Sdg			schednetisr(NETISR_ARP);
4607055Sdg			inq = &arpintrq;
4617055Sdg			break;
4627055Sdg#endif
46354263Sshin#ifdef INET6
46454263Sshin		case ETHERTYPE_IPV6:
46554263Sshin			schednetisr(NETISR_IPV6);
46654263Sshin			inq = &ip6intrq;
46754263Sshin			break;
46854263Sshin#endif
46921830Sjoerg#ifdef IPX
47021830Sjoerg		case ETHERTYPE_IPX:
47121830Sjoerg			schednetisr(NETISR_IPX);
47221830Sjoerg			inq = &ipxintrq;
47321830Sjoerg			break;
47421830Sjoerg#endif
4757055Sdg#ifdef NS
4767055Sdg		case ETHERTYPE_NS:
4777055Sdg			schednetisr(NETISR_NS);
4787055Sdg			inq = &nsintrq;
4797055Sdg			break;
4807055Sdg#endif
4817055Sdg#ifdef DECNET
48221830Sjoerg		case ETHERTYPE_DECNET:
4837055Sdg			schednetisr(NETISR_DECNET);
4847055Sdg			inq = &decnetintrq;
4857055Sdg			break;
4867055Sdg#endif
48721830Sjoerg#ifdef NETATALK
48821830Sjoerg		case ETHERTYPE_AT:
48921830Sjoerg	                schednetisr(NETISR_ATALK);
49021830Sjoerg			inq = &atintrq1;
49121830Sjoerg			break;
49221830Sjoerg	        case ETHERTYPE_AARP:
49321830Sjoerg			/* probably this should be done with a NETISR as well */
49493369Smdodd			aarpinput(IFP2AC(ifp), m); /* XXX */
49521830Sjoerg			return;
49621830Sjoerg#endif /* NETATALK */
4977055Sdg		default:
49821830Sjoerg			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
4997055Sdg			ifp->if_noproto++;
5007055Sdg			goto dropanyway;
5017055Sdg		}
5027055Sdg		break;
5037055Sdg	}
50421830Sjoerg
5057055Sdg	default:
50621830Sjoerg		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
5077055Sdg		ifp->if_noproto++;
50893377Smdodd		goto dropanyway;
5097055Sdg	}
5107055Sdg
51169152Sjlemon	(void) IF_HANDOFF(inq, m, NULL);
51293377Smdodd	return;
51393377Smdodd
51493377Smdodddropanyway:
51593377Smdodd	ifp->if_iqdrops++;
51693377Smdodd	if (m)
51793377Smdodd		m_freem(m);
51893377Smdodd	return;
5197055Sdg}
52093380Smdodd
5217055Sdg/*
5227055Sdg * Perform common duties while attaching to interface list
5237055Sdg */
5247055Sdgvoid
52593383Smdoddfddi_ifattach(ifp, bpf)
52693367Smdodd	struct ifnet *ifp;
52793383Smdodd	int bpf;
5287055Sdg{
52993367Smdodd	struct ifaddr *ifa;
53093367Smdodd	struct sockaddr_dl *sdl;
5317055Sdg
5327055Sdg	ifp->if_type = IFT_FDDI;
53393373Smdodd	ifp->if_addrlen = FDDI_ADDR_LEN;
5347055Sdg	ifp->if_hdrlen = 21;
53593379Smdodd
53693379Smdodd	if_attach(ifp);         /* Must be called before additional assignments */
53793379Smdodd
5387055Sdg	ifp->if_mtu = FDDIMTU;
53993379Smdodd	ifp->if_output = fddi_output;
540106939Ssam	ifp->if_input = fddi_input;
54168180Sume	ifp->if_resolvemulti = fddi_resolvemulti;
54293379Smdodd	ifp->if_broadcastaddr = fddibroadcastaddr;
54316063Sgpalmer	ifp->if_baudrate = 100000000;
54421830Sjoerg#ifdef IFF_NOTRAILERS
54521830Sjoerg	ifp->if_flags |= IFF_NOTRAILERS;
54621830Sjoerg#endif
54783130Sjlemon	ifa = ifaddr_byindex(ifp->if_index);
54893379Smdodd	if (ifa == NULL) {
54993379Smdodd		printf("%s(): no lladdr for %s%d!\n", __FUNCTION__,
55093379Smdodd		       ifp->if_name, ifp->if_unit);
55193379Smdodd		return;
55293379Smdodd	}
55393379Smdodd
55421831Sjoerg	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
55521831Sjoerg	sdl->sdl_type = IFT_FDDI;
55621831Sjoerg	sdl->sdl_alen = ifp->if_addrlen;
55793369Smdodd	bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
55893379Smdodd
55993383Smdodd	if (bpf)
56093383Smdodd		bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN);
56193383Smdodd
56293379Smdodd	return;
5637055Sdg}
56468180Sume
56593382Smdoddvoid
56693382Smdoddfddi_ifdetach(ifp, bpf)
56793382Smdodd	struct ifnet *ifp;
56893382Smdodd	int bpf;
56993382Smdodd{
57093382Smdodd
57193382Smdodd	if (bpf)
57293382Smdodd		bpfdetach(ifp);
57393382Smdodd
57493382Smdodd	if_detach(ifp);
57593382Smdodd
57693382Smdodd	return;
57793382Smdodd}
57893382Smdodd
57993382Smdoddint
58093382Smdoddfddi_ioctl (ifp, command, data)
58193382Smdodd	struct ifnet *ifp;
58293382Smdodd	int command;
58393382Smdodd	caddr_t data;
58493382Smdodd{
58593382Smdodd	struct ifaddr *ifa;
58693382Smdodd	struct ifreq *ifr;
58793382Smdodd	int error;
58893382Smdodd
58993382Smdodd	ifa = (struct ifaddr *) data;
59093382Smdodd	ifr = (struct ifreq *) data;
59193382Smdodd	error = 0;
59293382Smdodd
59393382Smdodd	switch (command) {
59493382Smdodd	case SIOCSIFADDR:
59593382Smdodd		ifp->if_flags |= IFF_UP;
59693382Smdodd
59793382Smdodd		switch (ifa->ifa_addr->sa_family) {
59893382Smdodd#ifdef INET
59993382Smdodd		case AF_INET:	/* before arpwhohas */
60093382Smdodd			ifp->if_init(ifp->if_softc);
60193382Smdodd			arp_ifinit(ifp, ifa);
60293382Smdodd			break;
60393382Smdodd#endif
60493382Smdodd#ifdef IPX
60593382Smdodd		/*
60693382Smdodd		 * XXX - This code is probably wrong
60793382Smdodd		 */
60893382Smdodd		case AF_IPX: {
60993382Smdodd				struct ipx_addr *ina;
61093382Smdodd				struct arpcom *ac;
61193382Smdodd
61293382Smdodd				ina = &(IA_SIPX(ifa)->sipx_addr);
61393382Smdodd				ac = IFP2AC(ifp);
61493382Smdodd
61593382Smdodd				if (ipx_nullhost(*ina)) {
61693382Smdodd					ina->x_host = *(union ipx_host *)
61793382Smdodd							ac->ac_enaddr;
61893382Smdodd				} else {
61993382Smdodd					bcopy((caddr_t) ina->x_host.c_host,
62093382Smdodd					      (caddr_t) ac->ac_enaddr,
62193382Smdodd					      sizeof(ac->ac_enaddr));
62293382Smdodd				}
62393382Smdodd
62493382Smdodd				/*
62593382Smdodd				 * Set new address
62693382Smdodd				 */
62793382Smdodd				ifp->if_init(ifp->if_softc);
62893382Smdodd			}
62993382Smdodd			break;
63093382Smdodd#endif
63193382Smdodd		default:
63293382Smdodd			ifp->if_init(ifp->if_softc);
63393382Smdodd			break;
634104302Sphk		}
63593382Smdodd	case SIOCGIFADDR: {
63693382Smdodd			struct sockaddr *sa;
63793382Smdodd
63893382Smdodd			sa = (struct sockaddr *) & ifr->ifr_data;
63993382Smdodd			bcopy(IFP2AC(ifp)->ac_enaddr,
64093382Smdodd			      (caddr_t) sa->sa_data, FDDI_ADDR_LEN);
64193382Smdodd
64293382Smdodd		}
64393382Smdodd		break;
64493382Smdodd	case SIOCSIFMTU:
64593382Smdodd		/*
64693382Smdodd		 * Set the interface MTU.
64793382Smdodd		 */
64893382Smdodd		if (ifr->ifr_mtu > FDDIMTU) {
64993382Smdodd			error = EINVAL;
65093382Smdodd		} else {
65193382Smdodd			ifp->if_mtu = ifr->ifr_mtu;
65293382Smdodd		}
65393382Smdodd		break;
65493382Smdodd	default:
65593382Smdodd		break;
65693382Smdodd	}
65793382Smdodd
65893382Smdodd	return (error);
65993382Smdodd}
66093382Smdodd
66168180Sumestatic int
66268180Sumefddi_resolvemulti(ifp, llsa, sa)
66368180Sume	struct ifnet *ifp;
66468180Sume	struct sockaddr **llsa;
66568180Sume	struct sockaddr *sa;
66668180Sume{
66768180Sume	struct sockaddr_dl *sdl;
66868180Sume	struct sockaddr_in *sin;
66968180Sume#ifdef INET6
67068180Sume	struct sockaddr_in6 *sin6;
67168180Sume#endif
67268180Sume	u_char *e_addr;
67368180Sume
67468180Sume	switch(sa->sa_family) {
67568180Sume	case AF_LINK:
67668180Sume		/*
67768180Sume		 * No mapping needed. Just check that it's a valid MC address.
67868180Sume		 */
67968180Sume		sdl = (struct sockaddr_dl *)sa;
68068180Sume		e_addr = LLADDR(sdl);
68168180Sume		if ((e_addr[0] & 1) != 1)
68293369Smdodd			return (EADDRNOTAVAIL);
68368180Sume		*llsa = 0;
68493369Smdodd		return (0);
68568180Sume
68668180Sume#ifdef INET
68768180Sume	case AF_INET:
68868180Sume		sin = (struct sockaddr_in *)sa;
68968180Sume		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
69093369Smdodd			return (EADDRNOTAVAIL);
69168180Sume		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
692111119Simp		       M_WAITOK);
69368180Sume		sdl->sdl_len = sizeof *sdl;
69468180Sume		sdl->sdl_family = AF_LINK;
69568180Sume		sdl->sdl_index = ifp->if_index;
69668180Sume		sdl->sdl_type = IFT_FDDI;
69768180Sume		sdl->sdl_nlen = 0;
69893375Smdodd		sdl->sdl_alen = FDDI_ADDR_LEN;
69968180Sume		sdl->sdl_slen = 0;
70068180Sume		e_addr = LLADDR(sdl);
70168180Sume		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
70268180Sume		*llsa = (struct sockaddr *)sdl;
70393369Smdodd		return (0);
70468180Sume#endif
70568180Sume#ifdef INET6
70668180Sume	case AF_INET6:
70768180Sume		sin6 = (struct sockaddr_in6 *)sa;
70868180Sume		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
70968180Sume			/*
71068180Sume			 * An IP6 address of 0 means listen to all
71168180Sume			 * of the Ethernet multicast address used for IP6.
71268180Sume			 * (This is used for multicast routers.)
71368180Sume			 */
71468180Sume			ifp->if_flags |= IFF_ALLMULTI;
71568180Sume			*llsa = 0;
71693369Smdodd			return (0);
71768180Sume		}
71868180Sume		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
71993369Smdodd			return (EADDRNOTAVAIL);
72068180Sume		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
721111119Simp		       M_WAITOK);
72268180Sume		sdl->sdl_len = sizeof *sdl;
72368180Sume		sdl->sdl_family = AF_LINK;
72468180Sume		sdl->sdl_index = ifp->if_index;
72568180Sume		sdl->sdl_type = IFT_FDDI;
72668180Sume		sdl->sdl_nlen = 0;
72793375Smdodd		sdl->sdl_alen = FDDI_ADDR_LEN;
72868180Sume		sdl->sdl_slen = 0;
72968180Sume		e_addr = LLADDR(sdl);
73068180Sume		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
73168180Sume		*llsa = (struct sockaddr *)sdl;
73293369Smdodd		return (0);
73368180Sume#endif
73468180Sume
73568180Sume	default:
73668180Sume		/*
73768180Sume		 * Well, the text isn't quite right, but it's the name
73868180Sume		 * that counts...
73968180Sume		 */
74093369Smdodd		return (EAFNOSUPPORT);
74168180Sume	}
74293375Smdodd
74393375Smdodd	return (0);
74468180Sume}
74593375Smdodd
74693375Smdoddstatic moduledata_t fddi_mod = {
74793375Smdodd	"fddi",	/* module name */
74893375Smdodd	NULL,	/* event handler */
74993375Smdodd	0	/* extra data */
75093375Smdodd};
75193375Smdodd
75293375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
75393375SmdoddMODULE_VERSION(fddi, 1);
754