if_fddisubr.c revision 93084
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 93084 2002-03-24 09:34:04Z bde $
377055Sdg */
387055Sdg
3932356Seivind#include "opt_atalk.h"
4032350Seivind#include "opt_inet.h"
4154263Sshin#include "opt_inet6.h"
4231742Seivind#include "opt_ipx.h"
4331742Seivind
447055Sdg#include <sys/param.h>
457055Sdg#include <sys/systm.h>
467055Sdg#include <sys/mbuf.h>
477055Sdg#include <sys/socket.h>
4868315Sume#include <sys/malloc.h>
497055Sdg
507055Sdg#include <net/if.h>
517055Sdg#include <net/netisr.h>
527055Sdg#include <net/route.h>
537055Sdg#include <net/if_llc.h>
547055Sdg#include <net/if_dl.h>
557055Sdg#include <net/if_types.h>
567055Sdg
5754263Sshin#if defined(INET) || defined(INET6)
587055Sdg#include <netinet/in.h>
597055Sdg#include <netinet/in_var.h>
6032350Seivind#include <netinet/if_ether.h>
617055Sdg#endif
6254263Sshin#ifdef INET6
6354263Sshin#include <netinet6/nd6.h>
6454263Sshin#endif
6521830Sjoerg#if defined(__FreeBSD__)
667055Sdg#include <netinet/if_fddi.h>
6721830Sjoerg#else
6821830Sjoerg#include <net/if_fddi.h>
6921830Sjoerg#endif
707055Sdg
7111819Sjulian#ifdef IPX
7221830Sjoerg#include <netipx/ipx.h>
7311819Sjulian#include <netipx/ipx_if.h>
7411819Sjulian#endif
7511819Sjulian
767055Sdg#ifdef NS
777055Sdg#include <netns/ns.h>
787055Sdg#include <netns/ns_if.h>
797055Sdg#endif
807055Sdg
817055Sdg#ifdef DECNET
827055Sdg#include <netdnet/dn.h>
837055Sdg#endif
847055Sdg
8521830Sjoerg#ifdef NETATALK
8621830Sjoerg#include <netatalk/at.h>
8721830Sjoerg#include <netatalk/at_var.h>
8821830Sjoerg#include <netatalk/at_extern.h>
8921830Sjoerg
9021830Sjoerg#define llc_snap_org_code llc_un.type_snap.org_code
9121830Sjoerg#define llc_snap_ether_type llc_un.type_snap.ether_type
9221830Sjoerg
9321830Sjoergextern u_char	at_org_code[ 3 ];
9421830Sjoergextern u_char	aarp_org_code[ 3 ];
9521830Sjoerg#endif /* NETATALK */
9621830Sjoerg
9792725Salfredstatic	int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
9893084Sbde			      struct sockaddr *);
9968180Sume
1007055Sdg#define senderr(e) { error = (e); goto bad;}
1017055Sdg
1027055Sdg/*
1037055Sdg * This really should be defined in if_llc.h but in case it isn't.
1047055Sdg */
1057055Sdg#ifndef llc_snap
1067055Sdg#define	llc_snap	llc_un.type_snap
1077055Sdg#endif
1087055Sdg
10921830Sjoerg#if defined(__bsdi__) || defined(__NetBSD__)
11021830Sjoerg#define	RTALLOC1(a, b)			rtalloc1(a, b)
1117055Sdg#define	ARPRESOLVE(a, b, c, d, e, f)	arpresolve(a, b, c, d, e)
11221830Sjoerg#elif defined(__FreeBSD__)
11321830Sjoerg#define	RTALLOC1(a, b)			rtalloc1(a, b, 0UL)
1147055Sdg#define	ARPRESOLVE(a, b, c, d, e, f)	arpresolve(a, b, c, d, e, f)
1157055Sdg#endif
1167055Sdg/*
1177055Sdg * FDDI output routine.
1187055Sdg * Encapsulate a packet of type family for the local net.
1197055Sdg * Use trailer local net encapsulation if enough data in first
1207055Sdg * packet leaves a multiple of 512 bytes of data in remainder.
1217055Sdg * Assumes that ifp is actually pointer to arpcom structure.
1227055Sdg */
1237055Sdgint
12454799Sgreenfddi_output(ifp, m, dst, rt0)
1257055Sdg	register struct ifnet *ifp;
12654799Sgreen	struct mbuf *m;
1277055Sdg	struct sockaddr *dst;
1287055Sdg	struct rtentry *rt0;
1297055Sdg{
13021830Sjoerg	u_int16_t type;
13169152Sjlemon	int loop_copy = 0, error = 0, hdrcmplt = 0;
13252248Smsmith 	u_char esrc[6], edst[6];
1337055Sdg	register struct rtentry *rt;
13421830Sjoerg	register struct fddi_header *fh;
1357055Sdg	struct arpcom *ac = (struct arpcom *)ifp;
1367055Sdg
1377055Sdg	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
1387055Sdg		senderr(ENETDOWN);
13934961Sphk	getmicrotime(&ifp->if_lastchange);
14021830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401
14143305Sdillon	if ((rt = rt0) != NULL) {
1427055Sdg		if ((rt->rt_flags & RTF_UP) == 0) {
14343305Sdillon			if ((rt0 = rt = RTALLOC1(dst, 1)) != NULL)
1447055Sdg				rt->rt_refcnt--;
14521830Sjoerg			else
1467055Sdg				senderr(EHOSTUNREACH);
1477055Sdg		}
1487055Sdg		if (rt->rt_flags & RTF_GATEWAY) {
1497055Sdg			if (rt->rt_gwroute == 0)
1507055Sdg				goto lookup;
1517055Sdg			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
1527055Sdg				rtfree(rt); rt = rt0;
1537055Sdg			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1);
1547055Sdg				if ((rt = rt->rt_gwroute) == 0)
1557055Sdg					senderr(EHOSTUNREACH);
1567055Sdg			}
1577055Sdg		}
1587055Sdg		if (rt->rt_flags & RTF_REJECT)
1597055Sdg			if (rt->rt_rmx.rmx_expire == 0 ||
16034961Sphk			    time_second < rt->rt_rmx.rmx_expire)
1617055Sdg				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
1627055Sdg	}
16321830Sjoerg#endif
1647055Sdg	switch (dst->sa_family) {
1657055Sdg
1667055Sdg#ifdef INET
16721830Sjoerg	case AF_INET: {
16821830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401
16984931Sfjoe		if (!ARPRESOLVE(ifp, rt, m, dst, edst, rt0))
1707055Sdg			return (0);	/* if not yet resolved */
17121830Sjoerg#else
17221830Sjoerg		int usetrailers;
17321830Sjoerg		if (!arpresolve(ac, m, &((struct sockaddr_in *)dst)->sin_addr, edst, &usetrailers))
17421830Sjoerg			return (0);	/* if not yet resolved */
17521830Sjoerg#endif
17621830Sjoerg		type = htons(ETHERTYPE_IP);
1777055Sdg		break;
17821830Sjoerg	}
1797055Sdg#endif
18054263Sshin#ifdef INET6
18154263Sshin	case AF_INET6:
18254263Sshin		if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
18374093Sbmilekic			/* Something bad happened */
18454263Sshin			return(0);
18554263Sshin		}
18654263Sshin		type = htons(ETHERTYPE_IPV6);
18754263Sshin		break;
18854263Sshin#endif
18911819Sjulian#ifdef IPX
19011819Sjulian	case AF_IPX:
19121830Sjoerg		type = htons(ETHERTYPE_IPX);
19211819Sjulian 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
19311819Sjulian		    (caddr_t)edst, sizeof (edst));
19411819Sjulian		break;
19511819Sjulian#endif
19621830Sjoerg#ifdef NETATALK
19721830Sjoerg	case AF_APPLETALK: {
19821830Sjoerg	    struct at_ifaddr *aa;
19936908Sjulian            if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst))
20021830Sjoerg                return (0);
20121830Sjoerg	    /*
20221830Sjoerg	     * ifaddr is the first thing in at_ifaddr
20321830Sjoerg	     */
20430834Sjulian	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
20521830Sjoerg		goto bad;
20621830Sjoerg
20721830Sjoerg	    /*
20821830Sjoerg	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
20921830Sjoerg	     * Since we must preserve the value of m, which is passed to us by
21021830Sjoerg	     * value, we m_copy() the first mbuf, and use it for our llc header.
21121830Sjoerg	     */
21221830Sjoerg	    if (aa->aa_flags & AFA_PHASE2) {
21321830Sjoerg		struct llc llc;
21421830Sjoerg
21570254Sbmilekic		M_PREPEND(m, sizeof(struct llc), M_TRYWAIT);
21621830Sjoerg		if (m == 0)
21721830Sjoerg			senderr(ENOBUFS);
21821830Sjoerg		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
21921830Sjoerg		llc.llc_control = LLC_UI;
22021830Sjoerg		bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code));
22121830Sjoerg		llc.llc_snap_ether_type = htons(ETHERTYPE_AT);
22221830Sjoerg		bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc));
22321830Sjoerg		type = 0;
22421830Sjoerg	    } else {
22521830Sjoerg		type = htons(ETHERTYPE_AT);
22621830Sjoerg	    }
22721830Sjoerg	    break;
22821830Sjoerg	}
22921830Sjoerg#endif /* NETATALK */
2307055Sdg#ifdef NS
2317055Sdg	case AF_NS:
23221830Sjoerg		type = htons(ETHERTYPE_NS);
2337055Sdg 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
2347055Sdg		    (caddr_t)edst, sizeof (edst));
2357055Sdg		break;
2367055Sdg#endif
2377055Sdg
23852248Smsmith	case pseudo_AF_HDRCMPLT:
23952248Smsmith	{
24052248Smsmith		struct ether_header *eh;
24152248Smsmith		hdrcmplt = 1;
24252248Smsmith		eh = (struct ether_header *)dst->sa_data;
24352248Smsmith 		(void)memcpy((caddr_t)esrc, (caddr_t)eh->ether_shost, sizeof (esrc));
24452248Smsmith		/* FALLTHROUGH */
24552248Smsmith	}
24652248Smsmith
2477055Sdg	case AF_UNSPEC:
2487055Sdg	{
2497055Sdg		struct ether_header *eh;
25036992Sjulian		loop_copy = -1;
2517055Sdg		eh = (struct ether_header *)dst->sa_data;
2528384Sdg 		(void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
2537055Sdg		if (*edst & 1)
2547055Sdg			m->m_flags |= (M_BCAST|M_MCAST);
2557055Sdg		type = eh->ether_type;
2567055Sdg		break;
2577055Sdg	}
2587055Sdg
2597055Sdg	case AF_IMPLINK:
2607055Sdg	{
2617055Sdg		fh = mtod(m, struct fddi_header *);
2627055Sdg		error = EPROTONOSUPPORT;
2637055Sdg		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
2647055Sdg			case FDDIFC_LLC_ASYNC: {
2657055Sdg				/* legal priorities are 0 through 7 */
2667055Sdg				if ((fh->fddi_fc & FDDIFC_Z) > 7)
2677055Sdg			        	goto bad;
2687055Sdg				break;
2697055Sdg			}
2707055Sdg			case FDDIFC_LLC_SYNC: {
2717055Sdg				/* FDDIFC_Z bits reserved, must be zero */
2727055Sdg				if (fh->fddi_fc & FDDIFC_Z)
2737055Sdg					goto bad;
2747055Sdg				break;
2757055Sdg			}
2767055Sdg			case FDDIFC_SMT: {
2777055Sdg				/* FDDIFC_Z bits must be non zero */
2787055Sdg				if ((fh->fddi_fc & FDDIFC_Z) == 0)
2797055Sdg					goto bad;
2807055Sdg				break;
2817055Sdg			}
2827055Sdg			default: {
2837055Sdg				/* anything else is too dangerous */
2847055Sdg               	 		goto bad;
2857055Sdg			}
2867055Sdg		}
2877055Sdg		error = 0;
2887055Sdg		if (fh->fddi_dhost[0] & 1)
2897055Sdg			m->m_flags |= (M_BCAST|M_MCAST);
2907055Sdg		goto queue_it;
2917055Sdg	}
2927055Sdg	default:
2937055Sdg		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
2947055Sdg			dst->sa_family);
2957055Sdg		senderr(EAFNOSUPPORT);
2967055Sdg	}
2977055Sdg
2987055Sdg	if (type != 0) {
2997055Sdg		register struct llc *l;
3007055Sdg		M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
3017055Sdg		if (m == 0)
3027055Sdg			senderr(ENOBUFS);
3037055Sdg		l = mtod(m, struct llc *);
3047055Sdg		l->llc_control = LLC_UI;
3057055Sdg		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
3067055Sdg		l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0;
3078384Sdg		(void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type,
30821830Sjoerg			sizeof(u_int16_t));
3097055Sdg	}
31036908Sjulian
3117055Sdg	/*
3127055Sdg	 * Add local net header.  If no space in first mbuf,
3137055Sdg	 * allocate another.
3147055Sdg	 */
3157055Sdg	M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT);
3167055Sdg	if (m == 0)
3177055Sdg		senderr(ENOBUFS);
3187055Sdg	fh = mtod(m, struct fddi_header *);
3197055Sdg	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
3208384Sdg 	(void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst));
3217055Sdg  queue_it:
32252248Smsmith	if (hdrcmplt)
32352248Smsmith		(void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)esrc,
32452248Smsmith			sizeof(fh->fddi_shost));
32552248Smsmith	else
32652248Smsmith		(void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr,
32752248Smsmith			sizeof(fh->fddi_shost));
32836908Sjulian	/*
32936908Sjulian	 * If a simplex interface, and the packet is being sent to our
33036908Sjulian	 * Ethernet address or a broadcast address, loopback a copy.
33136908Sjulian	 * XXX To make a simplex device behave exactly like a duplex
33236908Sjulian	 * device, we should copy in the case of sending to our own
33336908Sjulian	 * ethernet address (thus letting the original actually appear
33436908Sjulian	 * on the wire). However, we don't do that here for security
33536908Sjulian	 * reasons and compatibility with the original behavior.
33636908Sjulian	 */
33736992Sjulian	if ((ifp->if_flags & IFF_SIMPLEX) &&
33836992Sjulian	   (loop_copy != -1)) {
33936908Sjulian		if ((m->m_flags & M_BCAST) || loop_copy) {
34036908Sjulian			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
34136908Sjulian
34236908Sjulian			(void) if_simloop(ifp,
34360889Sarchie				n, dst->sa_family, sizeof(struct fddi_header));
34436908Sjulian	     	} else if (bcmp(fh->fddi_dhost,
34536908Sjulian		    fh->fddi_shost, sizeof(fh->fddi_shost)) == 0) {
34636908Sjulian			(void) if_simloop(ifp,
34760889Sarchie				m, dst->sa_family, sizeof(struct fddi_header));
34836908Sjulian			return(0);	/* XXX */
34936908Sjulian		}
35036908Sjulian	}
35136908Sjulian
35269152Sjlemon	if (! IF_HANDOFF(&ifp->if_snd, m, ifp))
3537055Sdg		senderr(ENOBUFS);
3547055Sdg	return (error);
3557055Sdg
3567055Sdgbad:
3577055Sdg	if (m)
3587055Sdg		m_freem(m);
3597055Sdg	return (error);
3607055Sdg}
3617055Sdg
3627055Sdg/*
3637055Sdg * Process a received FDDI packet;
3647055Sdg * the packet is in the mbuf chain m without
3657055Sdg * the fddi header, which is provided separately.
3667055Sdg */
3677055Sdgvoid
3687055Sdgfddi_input(ifp, fh, m)
3697055Sdg	struct ifnet *ifp;
3707055Sdg	register struct fddi_header *fh;
3717055Sdg	struct mbuf *m;
3727055Sdg{
3737055Sdg	register struct ifqueue *inq;
3747055Sdg	register struct llc *l;
3757055Sdg
3767055Sdg	if ((ifp->if_flags & IFF_UP) == 0) {
3777055Sdg		m_freem(m);
3787055Sdg		return;
3797055Sdg	}
38034961Sphk	getmicrotime(&ifp->if_lastchange);
3817055Sdg	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh);
38221830Sjoerg	if (fh->fddi_dhost[0] & 1) {
38321830Sjoerg		if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost,
38421830Sjoerg		    sizeof(fddibroadcastaddr)) == 0)
38521830Sjoerg			m->m_flags |= M_BCAST;
38621830Sjoerg		else
38721830Sjoerg			m->m_flags |= M_MCAST;
3887055Sdg		ifp->if_imcasts++;
38923910Sjoerg	} else if ((ifp->if_flags & IFF_PROMISC)
39023910Sjoerg	    && bcmp(((struct arpcom *)ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost,
39123910Sjoerg		    sizeof(fh->fddi_dhost)) != 0) {
39223910Sjoerg		m_freem(m);
39323910Sjoerg		return;
39421830Sjoerg	}
3957055Sdg
39621830Sjoerg#ifdef M_LINK0
39721830Sjoerg	/*
39821830Sjoerg	 * If this has a LLC priority of 0, then mark it so upper
39921830Sjoerg	 * layers have a hint that it really came via a FDDI/Ethernet
40021830Sjoerg	 * bridge.
40121830Sjoerg	 */
40221830Sjoerg	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
40321830Sjoerg		m->m_flags |= M_LINK0;
40421830Sjoerg#endif
40521830Sjoerg
4067055Sdg	l = mtod(m, struct llc *);
4077055Sdg	switch (l->llc_dsap) {
40854263Sshin#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK)
4097055Sdg	case LLC_SNAP_LSAP:
4107055Sdg	{
41121830Sjoerg		u_int16_t type;
4127055Sdg		if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP)
4137055Sdg			goto dropanyway;
41421830Sjoerg#ifdef NETATALK
41521830Sjoerg		if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code,
41621830Sjoerg			 sizeof(at_org_code)) == 0 &&
41721830Sjoerg		 	ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) {
41821830Sjoerg		    inq = &atintrq2;
41921830Sjoerg		    m_adj( m, sizeof( struct llc ));
42021830Sjoerg		    schednetisr(NETISR_ATALK);
42121830Sjoerg		    break;
42221830Sjoerg		}
42321830Sjoerg
42421830Sjoerg		if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code,
42521830Sjoerg			 sizeof(aarp_org_code)) == 0 &&
42621830Sjoerg			ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) {
42721830Sjoerg		    m_adj( m, sizeof( struct llc ));
42821830Sjoerg		    aarpinput((struct arpcom *)ifp, m); /* XXX */
42921830Sjoerg		    return;
43021830Sjoerg		}
43121830Sjoerg#endif /* NETATALK */
4327055Sdg		if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0)
4337055Sdg			goto dropanyway;
43421830Sjoerg		type = ntohs(l->llc_snap.ether_type);
4357055Sdg		m_adj(m, 8);
43621830Sjoerg		switch (type) {
4377055Sdg#ifdef INET
4387055Sdg		case ETHERTYPE_IP:
43936265Sdg			if (ipflow_fastforward(m))
44036192Sdg				return;
4417055Sdg			schednetisr(NETISR_IP);
4427055Sdg			inq = &ipintrq;
4437055Sdg			break;
4447055Sdg
4457055Sdg		case ETHERTYPE_ARP:
44678295Sjlemon			if (ifp->if_flags & IFF_NOARP)
44778295Sjlemon				goto dropanyway;
4487055Sdg			schednetisr(NETISR_ARP);
4497055Sdg			inq = &arpintrq;
4507055Sdg			break;
4517055Sdg#endif
45254263Sshin#ifdef INET6
45354263Sshin		case ETHERTYPE_IPV6:
45454263Sshin			schednetisr(NETISR_IPV6);
45554263Sshin			inq = &ip6intrq;
45654263Sshin			break;
45754263Sshin#endif
45821830Sjoerg#ifdef IPX
45921830Sjoerg		case ETHERTYPE_IPX:
46021830Sjoerg			schednetisr(NETISR_IPX);
46121830Sjoerg			inq = &ipxintrq;
46221830Sjoerg			break;
46321830Sjoerg#endif
4647055Sdg#ifdef NS
4657055Sdg		case ETHERTYPE_NS:
4667055Sdg			schednetisr(NETISR_NS);
4677055Sdg			inq = &nsintrq;
4687055Sdg			break;
4697055Sdg#endif
4707055Sdg#ifdef DECNET
47121830Sjoerg		case ETHERTYPE_DECNET:
4727055Sdg			schednetisr(NETISR_DECNET);
4737055Sdg			inq = &decnetintrq;
4747055Sdg			break;
4757055Sdg#endif
47621830Sjoerg#ifdef NETATALK
47721830Sjoerg		case ETHERTYPE_AT:
47821830Sjoerg	                schednetisr(NETISR_ATALK);
47921830Sjoerg			inq = &atintrq1;
48021830Sjoerg			break;
48121830Sjoerg	        case ETHERTYPE_AARP:
48221830Sjoerg			/* probably this should be done with a NETISR as well */
48321830Sjoerg			aarpinput((struct arpcom *)ifp, m); /* XXX */
48421830Sjoerg			return;
48521830Sjoerg#endif /* NETATALK */
4867055Sdg		default:
48721830Sjoerg			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
4887055Sdg			ifp->if_noproto++;
4897055Sdg			goto dropanyway;
4907055Sdg		}
4917055Sdg		break;
4927055Sdg	}
4937055Sdg#endif /* INET || NS */
49421830Sjoerg
4957055Sdg	default:
49621830Sjoerg		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
4977055Sdg		ifp->if_noproto++;
4987055Sdg	dropanyway:
4997055Sdg		m_freem(m);
5007055Sdg		return;
5017055Sdg	}
5027055Sdg
50369152Sjlemon	(void) IF_HANDOFF(inq, m, NULL);
5047055Sdg}
5057055Sdg/*
5067055Sdg * Perform common duties while attaching to interface list
5077055Sdg */
50821830Sjoerg#ifdef __NetBSD__
50921830Sjoerg#define	ifa_next	ifa_list.tqe_next
51021830Sjoerg#endif
51121830Sjoerg
5127055Sdgvoid
5137055Sdgfddi_ifattach(ifp)
5147055Sdg	register struct ifnet *ifp;
5157055Sdg{
5167055Sdg	register struct ifaddr *ifa;
5177055Sdg	register struct sockaddr_dl *sdl;
5187055Sdg
5197055Sdg	ifp->if_type = IFT_FDDI;
5207055Sdg	ifp->if_addrlen = 6;
5217055Sdg	ifp->if_hdrlen = 21;
5227055Sdg	ifp->if_mtu = FDDIMTU;
52368180Sume	ifp->if_resolvemulti = fddi_resolvemulti;
52416063Sgpalmer	ifp->if_baudrate = 100000000;
52521830Sjoerg#ifdef IFF_NOTRAILERS
52621830Sjoerg	ifp->if_flags |= IFF_NOTRAILERS;
52721830Sjoerg#endif
52884931Sfjoe	ifp->if_broadcastaddr = fddibroadcastaddr;
52921831Sjoerg#if defined(__FreeBSD__)
53083130Sjlemon	ifa = ifaddr_byindex(ifp->if_index);
53121831Sjoerg	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
53221831Sjoerg	sdl->sdl_type = IFT_FDDI;
53321831Sjoerg	sdl->sdl_alen = ifp->if_addrlen;
53421831Sjoerg	bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
53521831Sjoerg#elif defined(__NetBSD__)
53621830Sjoerg	LIST_INIT(&((struct arpcom *)ifp)->ac_multiaddrs);
53771999Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
53821830Sjoerg#else
53921830Sjoerg	for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next)
54021830Sjoerg#endif
54121831Sjoerg#if !defined(__FreeBSD__)
54221830Sjoerg		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
54321830Sjoerg		    sdl->sdl_family == AF_LINK) {
54421830Sjoerg			sdl->sdl_type = IFT_FDDI;
54521830Sjoerg			sdl->sdl_alen = ifp->if_addrlen;
54621830Sjoerg			bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
54721830Sjoerg			      LLADDR(sdl), ifp->if_addrlen);
54821830Sjoerg			break;
54921830Sjoerg		}
55021831Sjoerg#endif
5517055Sdg}
55268180Sume
55368180Sumestatic int
55468180Sumefddi_resolvemulti(ifp, llsa, sa)
55568180Sume	struct ifnet *ifp;
55668180Sume	struct sockaddr **llsa;
55768180Sume	struct sockaddr *sa;
55868180Sume{
55968180Sume	struct sockaddr_dl *sdl;
56068180Sume	struct sockaddr_in *sin;
56168180Sume#ifdef INET6
56268180Sume	struct sockaddr_in6 *sin6;
56368180Sume#endif
56468180Sume	u_char *e_addr;
56568180Sume
56668180Sume	switch(sa->sa_family) {
56768180Sume	case AF_LINK:
56868180Sume		/*
56968180Sume		 * No mapping needed. Just check that it's a valid MC address.
57068180Sume		 */
57168180Sume		sdl = (struct sockaddr_dl *)sa;
57268180Sume		e_addr = LLADDR(sdl);
57368180Sume		if ((e_addr[0] & 1) != 1)
57468180Sume			return EADDRNOTAVAIL;
57568180Sume		*llsa = 0;
57668180Sume		return 0;
57768180Sume
57868180Sume#ifdef INET
57968180Sume	case AF_INET:
58068180Sume		sin = (struct sockaddr_in *)sa;
58168180Sume		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
58268180Sume			return EADDRNOTAVAIL;
58368180Sume		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
58468180Sume		       M_WAITOK);
58568180Sume		sdl->sdl_len = sizeof *sdl;
58668180Sume		sdl->sdl_family = AF_LINK;
58768180Sume		sdl->sdl_index = ifp->if_index;
58868180Sume		sdl->sdl_type = IFT_FDDI;
58968180Sume		sdl->sdl_nlen = 0;
59068180Sume		sdl->sdl_alen = ETHER_ADDR_LEN;	/* XXX */
59168180Sume		sdl->sdl_slen = 0;
59268180Sume		e_addr = LLADDR(sdl);
59368180Sume		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
59468180Sume		*llsa = (struct sockaddr *)sdl;
59568180Sume		return 0;
59668180Sume#endif
59768180Sume#ifdef INET6
59868180Sume	case AF_INET6:
59968180Sume		sin6 = (struct sockaddr_in6 *)sa;
60068180Sume		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
60168180Sume			/*
60268180Sume			 * An IP6 address of 0 means listen to all
60368180Sume			 * of the Ethernet multicast address used for IP6.
60468180Sume			 * (This is used for multicast routers.)
60568180Sume			 */
60668180Sume			ifp->if_flags |= IFF_ALLMULTI;
60768180Sume			*llsa = 0;
60868180Sume			return 0;
60968180Sume		}
61068180Sume		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
61168180Sume			return EADDRNOTAVAIL;
61268180Sume		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
61368180Sume		       M_WAITOK);
61468180Sume		sdl->sdl_len = sizeof *sdl;
61568180Sume		sdl->sdl_family = AF_LINK;
61668180Sume		sdl->sdl_index = ifp->if_index;
61768180Sume		sdl->sdl_type = IFT_FDDI;
61868180Sume		sdl->sdl_nlen = 0;
61968180Sume		sdl->sdl_alen = ETHER_ADDR_LEN;	/* XXX */
62068180Sume		sdl->sdl_slen = 0;
62168180Sume		e_addr = LLADDR(sdl);
62268180Sume		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
62368180Sume		*llsa = (struct sockaddr *)sdl;
62468180Sume		return 0;
62568180Sume#endif
62668180Sume
62768180Sume	default:
62868180Sume		/*
62968180Sume		 * Well, the text isn't quite right, but it's the name
63068180Sume		 * that counts...
63168180Sume		 */
63268180Sume		return EAFNOSUPPORT;
63368180Sume	}
63468180Sume}
635