if_iso88025subr.c revision 87914
144165Sjulian/*
244165Sjulian * Copyright (c) 1998, Larry Lile
344165Sjulian * All rights reserved.
444165Sjulian *
544165Sjulian * For latest sources and information on this driver, please
644165Sjulian * go to http://anarchy.stdio.com.
744165Sjulian *
844165Sjulian * Questions, comments or suggestions should be directed to
944165Sjulian * Larry Lile <lile@stdio.com>.
1044165Sjulian *
1144165Sjulian * Redistribution and use in source and binary forms, with or without
1244165Sjulian * modification, are permitted provided that the following conditions
1344165Sjulian * are met:
1444165Sjulian * 1. Redistributions of source code must retain the above copyright
1544165Sjulian *    notice unmodified, this list of conditions, and the following
1644165Sjulian *    disclaimer.
1744165Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1844165Sjulian *    notice, this list of conditions and the following disclaimer in the
1944165Sjulian *    documentation and/or other materials provided with the distribution.
2044165Sjulian *
2144165Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2244165Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2344165Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2444165Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2544165Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2644165Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2744165Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2844165Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2944165Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3044165Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3144165Sjulian * SUCH DAMAGE.
3244165Sjulian *
3350477Speter * $FreeBSD: head/sys/net/if_iso88025subr.c 87914 2001-12-14 19:32:47Z jlemon $
3444165Sjulian *
3544165Sjulian */
3644165Sjulian
3744165Sjulian/*
3844165Sjulian *
3944165Sjulian * General ISO 802.5 (Token Ring) support routines
4044165Sjulian *
4144165Sjulian */
4244165Sjulian
4344165Sjulian#include "opt_inet.h"
4474408Smdodd#include "opt_inet6.h"
4574408Smdodd#include "opt_ipx.h"
4644165Sjulian
4744165Sjulian#include <sys/param.h>
4844165Sjulian#include <sys/systm.h>
4944165Sjulian#include <sys/mbuf.h>
5044165Sjulian#include <sys/socket.h>
5144165Sjulian#include <sys/sockio.h>
5244165Sjulian#include <sys/sysctl.h>
5344165Sjulian
5444165Sjulian#include <net/if.h>
5544165Sjulian#include <net/netisr.h>
5644165Sjulian#include <net/route.h>
5744165Sjulian#include <net/if_llc.h>
5844165Sjulian#include <net/if_dl.h>
5944165Sjulian#include <net/if_types.h>
6044165Sjulian
6144165Sjulian#include <net/if_arp.h>
6244165Sjulian
6344165Sjulian#include <net/iso88025.h>
6444165Sjulian
6574408Smdodd#if defined(INET) || defined(INET6)
6644165Sjulian#include <netinet/in.h>
6744165Sjulian#include <netinet/in_var.h>
6844165Sjulian#include <netinet/if_ether.h>
6944165Sjulian#endif
7074408Smdodd#ifdef INET6
7174408Smdodd#include <netinet6/nd6.h>
7274408Smdodd#endif
7344165Sjulian
7474408Smdodd#ifdef IPX
7574408Smdodd#include <netipx/ipx.h>
7674408Smdodd#include <netipx/ipx_if.h>
7774408Smdodd#endif
7874408Smdodd
7944165Sjulian#include <net/bpf.h>
8044165Sjulian
8144165Sjulian#include <machine/md_var.h>
8244165Sjulian
8344165Sjulian#include <vm/vm.h>
8444165Sjulian#include <vm/vm_param.h>
8544165Sjulian#include <vm/pmap.h>
8644165Sjulian
8744165Sjulian#include <net/iso88025.h>
8844165Sjulian
8974408Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP)
9074408Smdodd
9144165Sjulianvoid
9258313Slileiso88025_ifattach(struct ifnet *ifp)
9344165Sjulian{
9444165Sjulian    register struct ifaddr *ifa = NULL;
9544165Sjulian    register struct sockaddr_dl *sdl;
9644165Sjulian
9744165Sjulian    ifp->if_type = IFT_ISO88025;
9858313Slile    ifp->if_addrlen = ISO88025_ADDR_LEN;
9958313Slile    ifp->if_hdrlen = ISO88025_HDR_LEN;
10044165Sjulian    if (ifp->if_baudrate == 0)
10158313Slile        ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
10244165Sjulian    if (ifp->if_mtu == 0)
10344165Sjulian        ifp->if_mtu = ISO88025_DEFAULT_MTU;
10484931Sfjoe    ifp->if_broadcastaddr = etherbroadcastaddr;
10544165Sjulian
10683130Sjlemon        ifa = ifaddr_byindex(ifp->if_index);
10744165Sjulian        if (ifa == 0) {
10844165Sjulian                printf("iso88025_ifattach: no lladdr!\n");
10944165Sjulian                return;
11044165Sjulian        }
11144165Sjulian        sdl = (struct sockaddr_dl *)ifa->ifa_addr;
11244165Sjulian        sdl->sdl_type = IFT_ISO88025;
11344165Sjulian        sdl->sdl_alen = ifp->if_addrlen;
11444165Sjulian        bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
11544165Sjulian}
11644165Sjulian
11774408Smdodd/*
11874408Smdodd * Perform common duties while detaching a Token Ring interface
11974408Smdodd */
12074408Smdoddvoid
12174408Smdoddiso88025_ifdetach(ifp, bpf)
12274408Smdodd        struct ifnet *ifp;
12374408Smdodd        int bpf;
12474408Smdodd{
12574408Smdodd	if (bpf)
12674408Smdodd                bpfdetach(ifp);
12774408Smdodd	if_detach(ifp);
12874408Smdodd}
12974408Smdodd
13074408Smdodd
13144165Sjulianint
13244165Sjulianiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data)
13344165Sjulian{
13444165Sjulian        struct ifaddr *ifa = (struct ifaddr *) data;
13544165Sjulian        struct ifreq *ifr = (struct ifreq *) data;
13644165Sjulian        int error = 0;
13744165Sjulian
13844165Sjulian        switch (command) {
13944165Sjulian        case SIOCSIFADDR:
14044165Sjulian                ifp->if_flags |= IFF_UP;
14144165Sjulian
14244165Sjulian                switch (ifa->ifa_addr->sa_family) {
14344165Sjulian#ifdef INET
14444165Sjulian                case AF_INET:
14544165Sjulian                        ifp->if_init(ifp->if_softc);    /* before arpwhohas */
14684931Sfjoe                        arp_ifinit(ifp, ifa);
14744165Sjulian                        break;
14874408Smdodd#endif	/* INET */
14974408Smdodd#ifdef IPX
15074408Smdodd                /*
15174408Smdodd                 * XXX - This code is probably wrong
15274408Smdodd                 */
15374408Smdodd                case AF_IPX:
15474408Smdodd                        {
15574408Smdodd                        register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
15674408Smdodd                        struct arpcom *ac = IFP2AC(ifp);
15774408Smdodd
15874408Smdodd                        if (ipx_nullhost(*ina))
15974408Smdodd                                ina->x_host =
16074408Smdodd                                    *(union ipx_host *)
16174408Smdodd                                    ac->ac_enaddr;
16274408Smdodd                        else {
16374408Smdodd                                bcopy((caddr_t) ina->x_host.c_host,
16474408Smdodd                                      (caddr_t) ac->ac_enaddr,
16574408Smdodd                                      sizeof(ac->ac_enaddr));
16674408Smdodd                        }
16774408Smdodd
16874408Smdodd                        /*
16974408Smdodd                         * Set new address
17074408Smdodd                         */
17174408Smdodd                        ifp->if_init(ifp->if_softc);
17274408Smdodd                        break;
17374408Smdodd                        }
17474408Smdodd#endif	/* IPX */
17544165Sjulian                default:
17644165Sjulian                        ifp->if_init(ifp->if_softc);
17744165Sjulian                        break;
17844165Sjulian                }
17944165Sjulian                break;
18044165Sjulian
18144165Sjulian        case SIOCGIFADDR:
18244165Sjulian                {
18344165Sjulian                        struct sockaddr *sa;
18444165Sjulian
18544165Sjulian                        sa = (struct sockaddr *) & ifr->ifr_data;
18644165Sjulian                        bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
18744165Sjulian                              (caddr_t) sa->sa_data, ISO88025_ADDR_LEN);
18844165Sjulian                }
18944165Sjulian                break;
19044165Sjulian
19144165Sjulian        case SIOCSIFMTU:
19244165Sjulian                /*
19344165Sjulian                 * Set the interface MTU.
19444165Sjulian                 */
19558313Slile                if (ifr->ifr_mtu > ISO88025_MAX_MTU) {
19644165Sjulian                        error = EINVAL;
19744165Sjulian                } else {
19844165Sjulian                        ifp->if_mtu = ifr->ifr_mtu;
19944165Sjulian                }
20044165Sjulian                break;
20144165Sjulian        }
20244165Sjulian        return (error);
20344165Sjulian}
20444165Sjulian
20544165Sjulian/*
20644165Sjulian * ISO88025 encapsulation
20744165Sjulian */
20844165Sjulianint
20974408Smdoddiso88025_output(ifp, m, dst, rt0)
21074408Smdodd	struct ifnet *ifp;
21174408Smdodd	struct mbuf *m;
21274408Smdodd	struct sockaddr *dst;
21374408Smdodd	struct rtentry *rt0;
21444165Sjulian{
21574408Smdodd	u_int16_t snap_type = 0;
21687914Sjlemon	int loop_copy = 0, error = 0, rif_len = 0;
21787914Sjlemon	u_char edst[ISO88025_ADDR_LEN];
21874408Smdodd	struct iso88025_header *th;
21944627Sjulian	struct iso88025_header gen_th;
22074408Smdodd	struct sockaddr_dl *sdl = NULL;
22174408Smdodd	struct rtentry *rt;
22244165Sjulian	struct arpcom *ac = (struct arpcom *)ifp;
22344165Sjulian
22444165Sjulian	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
22544165Sjulian		senderr(ENETDOWN);
22674408Smdodd	getmicrotime(&ifp->if_lastchange);
22774408Smdodd
22844165Sjulian	rt = rt0;
22974408Smdodd	if (rt != NULL) {
23044165Sjulian		if ((rt->rt_flags & RTF_UP) == 0) {
23144165Sjulian			rt0 = rt = rtalloc1(dst, 1, 0UL);
23244165Sjulian			if (rt0)
23344165Sjulian				rt->rt_refcnt--;
23444165Sjulian			else
23544165Sjulian				senderr(EHOSTUNREACH);
23644165Sjulian		}
23744165Sjulian		if (rt->rt_flags & RTF_GATEWAY) {
23844165Sjulian			if (rt->rt_gwroute == 0)
23944165Sjulian				goto lookup;
24044165Sjulian			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
24144165Sjulian				rtfree(rt); rt = rt0;
24244165Sjulian			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1,
24344165Sjulian							  0UL);
24444165Sjulian				if ((rt = rt->rt_gwroute) == 0)
24544165Sjulian					senderr(EHOSTUNREACH);
24644165Sjulian			}
24744165Sjulian		}
24844165Sjulian		if (rt->rt_flags & RTF_REJECT)
24944165Sjulian			if (rt->rt_rmx.rmx_expire == 0 ||
25044165Sjulian			    time_second < rt->rt_rmx.rmx_expire)
25144165Sjulian				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
25244165Sjulian	}
25344627Sjulian
25444627Sjulian	/* Calculate routing info length based on arp table entry */
25544627Sjulian	if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
25644627Sjulian		if (sdl->sdl_rcf != NULL)
25758313Slile			rif_len = TR_RCF_RIFLEN(sdl->sdl_rcf);
25844627Sjulian
25944627Sjulian	/* Generate a generic 802.5 header for the packet */
26058313Slile	gen_th.ac = TR_AC;
26158313Slile	gen_th.fc = TR_LLC_FRAME;
26274408Smdodd	(void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr,
26374408Smdodd		sizeof(ac->ac_enaddr));
26444627Sjulian	if (rif_len) {
26558313Slile		gen_th.iso88025_shost[0] |= TR_RII;
26644627Sjulian		if (rif_len > 2) {
26744627Sjulian			gen_th.rcf = sdl->sdl_rcf;
26874408Smdodd			(void)memcpy((caddr_t)gen_th.rd,
26974408Smdodd				(caddr_t)sdl->sdl_route, rif_len - 2);
27044627Sjulian		}
27144627Sjulian	}
27244627Sjulian
27344165Sjulian	switch (dst->sa_family) {
27444165Sjulian#ifdef INET
27544165Sjulian	case AF_INET:
27684931Sfjoe		if (!arpresolve(ifp, rt, m, dst, edst, rt0))
27744165Sjulian			return (0);	/* if not yet resolved */
27874408Smdodd		snap_type = ETHERTYPE_IP;
27974408Smdodd		break;
28074408Smdodd#endif	/* INET */
28174408Smdodd#ifdef NOT_YET
28274408Smdodd#ifdef INET6
28374408Smdodd	case AF_INET6:
28474408Smdodd		if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
28574408Smdodd			/* Something bad happened */
28674408Smdodd			return(0);
28774408Smdodd		}
28874408Smdodd		snap_type = ETHERTYPE_IPV6;
28974408Smdodd		break;
29074408Smdodd#endif	/* INET6 */
29174408Smdodd#endif	/* NOT_YET */
29274408Smdodd#ifdef IPX
29374408Smdodd	case AF_IPX:
29474408Smdodd	{
29574408Smdodd		u_int8_t	*cp;
29674408Smdodd
29774408Smdodd		snap_type = 0;
29874408Smdodd		bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
29974408Smdodd			sizeof (edst));
30074408Smdodd
30174408Smdodd		M_PREPEND(m, 3, M_TRYWAIT);
30244627Sjulian		if (m == 0)
30344627Sjulian			senderr(ENOBUFS);
30474408Smdodd		m = m_pullup(m, 3);
30574408Smdodd		if (m == 0)
30674408Smdodd			senderr(ENOBUFS);
30774408Smdodd		cp = mtod(m, u_int8_t *);
30874408Smdodd		*cp++ = ETHERTYPE_IPX_8022;
30974408Smdodd		*cp++ = ETHERTYPE_IPX_8022;
31074408Smdodd		*cp++ = LLC_UI;
31174408Smdodd	}
31274408Smdodd	break;
31374408Smdodd#endif	/* IPX */
31444165Sjulian	case AF_UNSPEC:
31574408Smdodd	{
31674408Smdodd		struct iso88025_sockaddr_data *sd;
31744627Sjulian		/*
31844627Sjulian		 * For AF_UNSPEC sockaddr.sa_data must contain all of the
31944627Sjulian		 * mac information needed to send the packet.  This allows
32044627Sjulian		 * full mac, llc, and source routing function to be controlled.
32144627Sjulian		 * llc and source routing information must already be in the
32244627Sjulian		 * mbuf provided, ac/fc are set in sa_data.  sockaddr.sa_data
32344627Sjulian		 * should be a iso88025_sockaddr_data structure see iso88025.h
32444627Sjulian		 */
32544165Sjulian                loop_copy = -1;
32644627Sjulian		sd = (struct iso88025_sockaddr_data *)dst->sa_data;
32744627Sjulian		gen_th.ac = sd->ac;
32844627Sjulian		gen_th.fc = sd->fc;
32974408Smdodd		(void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost,
33074408Smdodd			sizeof(sd->ether_dhost));
33174408Smdodd		(void)memcpy((caddr_t)gen_th.iso88025_shost,
33274408Smdodd			(caddr_t)sd->ether_shost, sizeof(sd->ether_shost));
33344627Sjulian		rif_len = 0;
33444165Sjulian		break;
33574408Smdodd	}
33644165Sjulian	default:
33744165Sjulian		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
33844165Sjulian			dst->sa_family);
33944165Sjulian		senderr(EAFNOSUPPORT);
34074408Smdodd		break;
34144165Sjulian	}
34244165Sjulian
34374408Smdodd	if (snap_type != 0) {
34474408Smdodd        	struct llc *l;
34574408Smdodd		M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
34674408Smdodd		if (m == 0)
34774408Smdodd			senderr(ENOBUFS);
34874408Smdodd		l = mtod(m, struct llc *);
34974408Smdodd		l->llc_un.type_snap.ether_type = htons(snap_type);
35074408Smdodd		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
35174408Smdodd		l->llc_un.type_snap.control = LLC_UI;
35274408Smdodd		l->llc_un.type_snap.org_code[0] =
35374408Smdodd			l->llc_un.type_snap.org_code[1] =
35474408Smdodd			l->llc_un.type_snap.org_code[2] = 0;
35574408Smdodd	}
35674408Smdodd
35744165Sjulian	/*
35844165Sjulian	 * Add local net header.  If no space in first mbuf,
35944165Sjulian	 * allocate another.
36044165Sjulian	 */
36144627Sjulian	M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT);
36244165Sjulian	if (m == 0)
36344165Sjulian		senderr(ENOBUFS);
36444627Sjulian
36574408Smdodd	(void)memcpy((caddr_t)&gen_th.iso88025_dhost, (caddr_t)edst,
36674408Smdodd		     sizeof(edst));
36774408Smdodd
36844627Sjulian	/* Copy as much of the generic header as is needed into the mbuf */
36944165Sjulian	th = mtod(m, struct iso88025_header *);
37044627Sjulian	memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
37144627Sjulian
37244165Sjulian        /*
37344165Sjulian         * If a simplex interface, and the packet is being sent to our
37444165Sjulian         * Ethernet address or a broadcast address, loopback a copy.
37544165Sjulian         * XXX To make a simplex device behave exactly like a duplex
37644165Sjulian         * device, we should copy in the case of sending to our own
37744165Sjulian         * ethernet address (thus letting the original actually appear
37844165Sjulian         * on the wire). However, we don't do that here for security
37944165Sjulian         * reasons and compatibility with the original behavior.
38044165Sjulian         */
38174408Smdodd        if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
38244165Sjulian                if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
38374408Smdodd                        struct mbuf *n;
38474408Smdodd			n = m_copy(m, 0, (int)M_COPYALL);
38574408Smdodd                        (void)if_simloop(ifp, n, dst->sa_family,
38674408Smdodd					  ISO88025_HDR_LEN);
38774408Smdodd                } else
38874408Smdodd			if (bcmp(th->iso88025_dhost, th->iso88025_shost,
38974408Smdodd				 ETHER_ADDR_LEN) == 0) {
39074408Smdodd				(void)if_simloop(ifp, m, dst->sa_family,
39174408Smdodd						 ISO88025_HDR_LEN);
39274408Smdodd                        	return(0);      /* XXX */
39374408Smdodd			}
39444165Sjulian        }
39544165Sjulian
39674408Smdodd	if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + (sizeof(struct llc))) ) {
39769152Sjlemon		printf("iso88025_output: packet dropped QFULL.\n");
39844165Sjulian		senderr(ENOBUFS);
39944165Sjulian	}
40044165Sjulian	return (error);
40144165Sjulian
40244165Sjulianbad:
40344165Sjulian	if (m)
40444165Sjulian		m_freem(m);
40544165Sjulian	return (error);
40644165Sjulian}
40744165Sjulian
40844165Sjulian/*
40944165Sjulian * ISO 88025 de-encapsulation
41044165Sjulian */
41144165Sjulianvoid
41274408Smdoddiso88025_input(ifp, th, m)
41374408Smdodd	struct ifnet *ifp;
41474408Smdodd	struct iso88025_header *th;
41574408Smdodd	struct mbuf *m;
41644165Sjulian{
41744165Sjulian	register struct ifqueue *inq;
41874408Smdodd	register struct llc *l;
41944165Sjulian
42058313Slile	if ((ifp->if_flags & IFF_UP) == 0) {
42158313Slile		m_freem(m);
42258313Slile		return;
42358313Slile	}
42444165Sjulian
42574408Smdodd	getmicrotime(&ifp->if_lastchange);
42674408Smdodd	ifp->if_ibytes += m->m_pkthdr.len + sizeof(*th);
42758313Slile
42844165Sjulian	if (th->iso88025_dhost[0] & 1) {
42974408Smdodd		if (bcmp((caddr_t)etherbroadcastaddr,
43074408Smdodd			 (caddr_t)th->iso88025_dhost,
43174408Smdodd			 sizeof(etherbroadcastaddr)) == 0)
43244165Sjulian			m->m_flags |= M_BCAST;
43344165Sjulian		else
43444165Sjulian			m->m_flags |= M_MCAST;
43574408Smdodd		ifp->if_imcasts++;
43644165Sjulian	}
43744165Sjulian
43874408Smdodd	l = mtod(m, struct llc *);
43944165Sjulian
44074408Smdodd	switch (l->llc_dsap) {
44174408Smdodd#ifdef IPX
44274408Smdodd	case ETHERTYPE_IPX_8022:	/* Thanks a bunch Novell */
44374408Smdodd		if ((l->llc_control != LLC_UI) ||
44474408Smdodd		    (l->llc_ssap != ETHERTYPE_IPX_8022))
44574408Smdodd			goto dropanyway;
44674408Smdodd
44774408Smdodd		th->iso88025_shost[0] &= ~(TR_RII);
44874408Smdodd		m_adj(m, 3);
44974408Smdodd		schednetisr(NETISR_IPX);
45074408Smdodd		inq = &ipxintrq;
45174408Smdodd		break;
45274408Smdodd#endif	/* IPX */
45374408Smdodd	case LLC_SNAP_LSAP: {
45474408Smdodd		u_int16_t type;
45574408Smdodd		if ((l->llc_control != LLC_UI) ||
45674408Smdodd		    (l->llc_ssap != LLC_SNAP_LSAP))
45774408Smdodd			goto dropanyway;
45874408Smdodd
45974408Smdodd		if (l->llc_un.type_snap.org_code[0] != 0 ||
46074408Smdodd		    l->llc_un.type_snap.org_code[1] != 0 ||
46174408Smdodd		    l->llc_un.type_snap.org_code[2] != 0)
46274408Smdodd			goto dropanyway;
46374408Smdodd
46474408Smdodd		type = ntohs(l->llc_un.type_snap.ether_type);
46574408Smdodd		m_adj(m, sizeof(struct llc));
46674408Smdodd		switch (type) {
46744165Sjulian#ifdef INET
46874408Smdodd		case ETHERTYPE_IP:
46974408Smdodd			th->iso88025_shost[0] &= ~(TR_RII);
47074408Smdodd			if (ipflow_fastforward(m))
47174408Smdodd				return;
47274408Smdodd			schednetisr(NETISR_IP);
47374408Smdodd			inq = &ipintrq;
47474408Smdodd			break;
47574408Smdodd
47674408Smdodd		case ETHERTYPE_ARP:
47778295Sjlemon			if (ifp->if_flags & IFF_NOARP)
47878295Sjlemon				goto dropanyway;
47974408Smdodd			schednetisr(NETISR_ARP);
48074408Smdodd			inq = &arpintrq;
48174408Smdodd			break;
48274408Smdodd#endif	/* INET */
48374408Smdodd#ifdef IPX_SNAP	/* XXX: Not supported! */
48474408Smdodd		case ETHERTYPE_IPX:
48574408Smdodd			th->iso88025_shost[0] &= ~(TR_RII);
48674408Smdodd			schednetisr(NETISR_IPX);
48774408Smdodd			inq = &ipxintrq;
48874408Smdodd			break;
48974408Smdodd#endif	/* IPX_SNAP */
49074408Smdodd#ifdef NOT_YET
49174408Smdodd#ifdef INET6
49274408Smdodd		case ETHERTYPE_IPV6:
49374408Smdodd			th->iso88025_shost[0] &= ~(TR_RII);
49474408Smdodd			schednetisr(NETISR_IPV6);
49574408Smdodd			inq = &ip6intrq;
49674408Smdodd			break;
49774408Smdodd#endif	/* INET6 */
49874408Smdodd#endif	/* NOT_YET */
49974408Smdodd		default:
50074408Smdodd			printf("iso88025_input: unexpected llc_snap ether_type  0x%02x\n", type);
50174408Smdodd			m_freem(m);
50244165Sjulian			return;
50374408Smdodd		}
50444165Sjulian		break;
50574408Smdodd	}
50674408Smdodd	case LLC_ISO_LSAP:
50774408Smdodd		switch (l->llc_control) {
50874408Smdodd		case LLC_UI:
50974408Smdodd			goto dropanyway;
51074408Smdodd			break;
51174408Smdodd                case LLC_XID:
51274408Smdodd                case LLC_XID_P:
51374408Smdodd			if(m->m_len < ISO88025_ADDR_LEN)
51474408Smdodd				goto dropanyway;
51574408Smdodd			l->llc_window = 0;
51674408Smdodd			l->llc_fid = 9;
51774408Smdodd			l->llc_class = 1;
51874408Smdodd			l->llc_dsap = l->llc_ssap = 0;
51974408Smdodd			/* Fall through to */
52074408Smdodd		case LLC_TEST:
52174408Smdodd		case LLC_TEST_P:
52274408Smdodd		{
52374408Smdodd			struct sockaddr sa;
52474408Smdodd			struct arpcom *ac = (struct arpcom *)ifp;
52574408Smdodd			struct iso88025_sockaddr_data *th2;
52674408Smdodd			int i;
52774408Smdodd			u_char c = l->llc_dsap;
52844165Sjulian
52974408Smdodd			if (th->iso88025_shost[0] & TR_RII) { /* XXX */
53074408Smdodd				printf("iso88025_input: dropping source routed LLC_TEST\n");
53174408Smdodd				m_free(m);
53274408Smdodd				return;
53374408Smdodd			}
53474408Smdodd			l->llc_dsap = l->llc_ssap;
53574408Smdodd			l->llc_ssap = c;
53674408Smdodd			if (m->m_flags & (M_BCAST | M_MCAST))
53774408Smdodd				bcopy((caddr_t)ac->ac_enaddr,
53874408Smdodd			      		(caddr_t)th->iso88025_dhost,
53974408Smdodd					ISO88025_ADDR_LEN);
54074408Smdodd			sa.sa_family = AF_UNSPEC;
54174408Smdodd			sa.sa_len = sizeof(sa);
54274408Smdodd			th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
54374408Smdodd			for (i = 0; i < ISO88025_ADDR_LEN; i++) {
54474408Smdodd				th2->ether_shost[i] = c = th->iso88025_dhost[i];
54574408Smdodd				th2->ether_dhost[i] = th->iso88025_dhost[i] =
54674408Smdodd					th->iso88025_shost[i];
54774408Smdodd				th->iso88025_shost[i] = c;
54874408Smdodd			}
54974408Smdodd			th2->ac = TR_AC;
55074408Smdodd			th2->fc = TR_LLC_FRAME;
55174408Smdodd			ifp->if_output(ifp, m, &sa, NULL);
55274408Smdodd			return;
55374408Smdodd		}
55474408Smdodd		default:
55574408Smdodd			printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
55674408Smdodd			m_freem(m);
55774408Smdodd			return;
55874408Smdodd		}
55974408Smdodd		break;
56044165Sjulian	default:
56174408Smdodd		printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
56274408Smdodd		ifp->if_noproto++;
56374408Smdodd	dropanyway:
56474408Smdodd		m_freem(m);
56574408Smdodd		return;
56644165Sjulian	}
56744165Sjulian
56869152Sjlemon	if (! IF_HANDOFF(inq, m, NULL))
56944165Sjulian                printf("iso88025_input: Packet dropped (Queue full).\n");
57044165Sjulian}
571