if_iso88025subr.c revision 112273
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 112273 2003-03-15 16:49:08Z mdodd $
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>
49112271Smdodd#include <sys/kernel.h>
50112271Smdodd#include <sys/malloc.h>
5144165Sjulian#include <sys/mbuf.h>
52112271Smdodd#include <sys/module.h>
5344165Sjulian#include <sys/socket.h>
5444165Sjulian#include <sys/sockio.h>
5544165Sjulian
5644165Sjulian#include <net/if.h>
57112271Smdodd#include <net/if_dl.h>
5844165Sjulian#include <net/if_llc.h>
5944165Sjulian#include <net/if_types.h>
6044165Sjulian
61112271Smdodd#include <net/netisr.h>
62112271Smdodd#include <net/route.h>
63112271Smdodd#include <net/bpf.h>
6444165Sjulian#include <net/iso88025.h>
6544165Sjulian
6674408Smdodd#if defined(INET) || defined(INET6)
6744165Sjulian#include <netinet/in.h>
6844165Sjulian#include <netinet/in_var.h>
6944165Sjulian#include <netinet/if_ether.h>
7044165Sjulian#endif
7174408Smdodd#ifdef INET6
7274408Smdodd#include <netinet6/nd6.h>
7374408Smdodd#endif
7444165Sjulian
7574408Smdodd#ifdef IPX
7674408Smdodd#include <netipx/ipx.h>
7774408Smdodd#include <netipx/ipx_if.h>
7874408Smdodd#endif
7974408Smdodd
80112273Smdoddstatic int iso88025_resolvemulti (struct ifnet *, struct sockaddr **,
81112273Smdodd				  struct sockaddr *));
82112273Smdodd
8374408Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP)
8474408Smdodd
8544165Sjulianvoid
8658313Slileiso88025_ifattach(struct ifnet *ifp)
8744165Sjulian{
88111774Smdodd    struct ifaddr *ifa = NULL;
89111774Smdodd    struct sockaddr_dl *sdl;
9044165Sjulian
9144165Sjulian    ifp->if_type = IFT_ISO88025;
9258313Slile    ifp->if_addrlen = ISO88025_ADDR_LEN;
9358313Slile    ifp->if_hdrlen = ISO88025_HDR_LEN;
9444165Sjulian    if (ifp->if_baudrate == 0)
9558313Slile        ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
9644165Sjulian    if (ifp->if_mtu == 0)
9744165Sjulian        ifp->if_mtu = ISO88025_DEFAULT_MTU;
9884931Sfjoe    ifp->if_broadcastaddr = etherbroadcastaddr;
9944165Sjulian
100112272Smdodd    ifa = ifaddr_byindex(ifp->if_index);
101112272Smdodd    if (ifa == 0) {
102112272Smdodd            printf("iso88025_ifattach: no lladdr!\n");
103112272Smdodd            return;
104112272Smdodd    }
105112272Smdodd    sdl = (struct sockaddr_dl *)ifa->ifa_addr;
106112272Smdodd    sdl->sdl_type = IFT_ISO88025;
107112272Smdodd    sdl->sdl_alen = ifp->if_addrlen;
108112272Smdodd    bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
10944165Sjulian}
11044165Sjulian
11174408Smdodd/*
11274408Smdodd * Perform common duties while detaching a Token Ring interface
11374408Smdodd */
11474408Smdoddvoid
11574408Smdoddiso88025_ifdetach(ifp, bpf)
11674408Smdodd        struct ifnet *ifp;
11774408Smdodd        int bpf;
11874408Smdodd{
11974408Smdodd	if (bpf)
12074408Smdodd                bpfdetach(ifp);
12174408Smdodd	if_detach(ifp);
12274408Smdodd}
12374408Smdodd
12474408Smdodd
12544165Sjulianint
12644165Sjulianiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data)
12744165Sjulian{
12844165Sjulian        struct ifaddr *ifa = (struct ifaddr *) data;
12944165Sjulian        struct ifreq *ifr = (struct ifreq *) data;
13044165Sjulian        int error = 0;
13144165Sjulian
13244165Sjulian        switch (command) {
13344165Sjulian        case SIOCSIFADDR:
13444165Sjulian                ifp->if_flags |= IFF_UP;
13544165Sjulian
13644165Sjulian                switch (ifa->ifa_addr->sa_family) {
13744165Sjulian#ifdef INET
13844165Sjulian                case AF_INET:
13944165Sjulian                        ifp->if_init(ifp->if_softc);    /* before arpwhohas */
14084931Sfjoe                        arp_ifinit(ifp, ifa);
14144165Sjulian                        break;
14274408Smdodd#endif	/* INET */
14374408Smdodd#ifdef IPX
14474408Smdodd                /*
14574408Smdodd                 * XXX - This code is probably wrong
14674408Smdodd                 */
14774408Smdodd                case AF_IPX:
14874408Smdodd                        {
149111774Smdodd                        struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
15074408Smdodd                        struct arpcom *ac = IFP2AC(ifp);
15174408Smdodd
15274408Smdodd                        if (ipx_nullhost(*ina))
15374408Smdodd                                ina->x_host =
15474408Smdodd                                    *(union ipx_host *)
15574408Smdodd                                    ac->ac_enaddr;
15674408Smdodd                        else {
15774408Smdodd                                bcopy((caddr_t) ina->x_host.c_host,
15874408Smdodd                                      (caddr_t) ac->ac_enaddr,
15974408Smdodd                                      sizeof(ac->ac_enaddr));
16074408Smdodd                        }
16174408Smdodd
16274408Smdodd                        /*
16374408Smdodd                         * Set new address
16474408Smdodd                         */
16574408Smdodd                        ifp->if_init(ifp->if_softc);
16674408Smdodd                        break;
16774408Smdodd                        }
16874408Smdodd#endif	/* IPX */
16944165Sjulian                default:
17044165Sjulian                        ifp->if_init(ifp->if_softc);
17144165Sjulian                        break;
17244165Sjulian                }
17344165Sjulian                break;
17444165Sjulian
17544165Sjulian        case SIOCGIFADDR:
17644165Sjulian                {
17744165Sjulian                        struct sockaddr *sa;
17844165Sjulian
17944165Sjulian                        sa = (struct sockaddr *) & ifr->ifr_data;
180111775Smdodd                        bcopy(IFP2AC(ifp)->ac_enaddr,
18144165Sjulian                              (caddr_t) sa->sa_data, ISO88025_ADDR_LEN);
18244165Sjulian                }
18344165Sjulian                break;
18444165Sjulian
18544165Sjulian        case SIOCSIFMTU:
18644165Sjulian                /*
18744165Sjulian                 * Set the interface MTU.
18844165Sjulian                 */
18958313Slile                if (ifr->ifr_mtu > ISO88025_MAX_MTU) {
19044165Sjulian                        error = EINVAL;
19144165Sjulian                } else {
19244165Sjulian                        ifp->if_mtu = ifr->ifr_mtu;
19344165Sjulian                }
19444165Sjulian                break;
19544165Sjulian        }
19644165Sjulian        return (error);
19744165Sjulian}
19844165Sjulian
19944165Sjulian/*
20044165Sjulian * ISO88025 encapsulation
20144165Sjulian */
20244165Sjulianint
20374408Smdoddiso88025_output(ifp, m, dst, rt0)
20474408Smdodd	struct ifnet *ifp;
20574408Smdodd	struct mbuf *m;
20674408Smdodd	struct sockaddr *dst;
20774408Smdodd	struct rtentry *rt0;
20844165Sjulian{
20974408Smdodd	u_int16_t snap_type = 0;
21087914Sjlemon	int loop_copy = 0, error = 0, rif_len = 0;
21187914Sjlemon	u_char edst[ISO88025_ADDR_LEN];
21274408Smdodd	struct iso88025_header *th;
21344627Sjulian	struct iso88025_header gen_th;
21474408Smdodd	struct sockaddr_dl *sdl = NULL;
21574408Smdodd	struct rtentry *rt;
21644165Sjulian	struct arpcom *ac = (struct arpcom *)ifp;
21744165Sjulian
21844165Sjulian	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
21944165Sjulian		senderr(ENETDOWN);
22074408Smdodd	getmicrotime(&ifp->if_lastchange);
22174408Smdodd
222111767Smdodd	error = rt_check(&rt, &rt0, dst);
223111767Smdodd	if (error) {
224111767Smdodd		goto bad;
22544165Sjulian	}
22644627Sjulian
22744627Sjulian	/* Calculate routing info length based on arp table entry */
22844627Sjulian	if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
229102291Sarchie		if (SDL_ISO88025(sdl)->trld_rcf != 0)
23096184Skbyanc			rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
23144627Sjulian
23244627Sjulian	/* Generate a generic 802.5 header for the packet */
23358313Slile	gen_th.ac = TR_AC;
23458313Slile	gen_th.fc = TR_LLC_FRAME;
23574408Smdodd	(void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr,
23674408Smdodd		sizeof(ac->ac_enaddr));
23744627Sjulian	if (rif_len) {
23858313Slile		gen_th.iso88025_shost[0] |= TR_RII;
23944627Sjulian		if (rif_len > 2) {
24096184Skbyanc			gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
24174408Smdodd			(void)memcpy((caddr_t)gen_th.rd,
24296184Skbyanc				(caddr_t)SDL_ISO88025(sdl)->trld_route,
24396184Skbyanc				rif_len - 2);
24444627Sjulian		}
24544627Sjulian	}
24644627Sjulian
24744165Sjulian	switch (dst->sa_family) {
24844165Sjulian#ifdef INET
24944165Sjulian	case AF_INET:
25084931Sfjoe		if (!arpresolve(ifp, rt, m, dst, edst, rt0))
25144165Sjulian			return (0);	/* if not yet resolved */
25274408Smdodd		snap_type = ETHERTYPE_IP;
25374408Smdodd		break;
25474408Smdodd#endif	/* INET */
25574408Smdodd#ifdef NOT_YET
25674408Smdodd#ifdef INET6
25774408Smdodd	case AF_INET6:
25874408Smdodd		if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
25974408Smdodd			/* Something bad happened */
26074408Smdodd			return(0);
26174408Smdodd		}
26274408Smdodd		snap_type = ETHERTYPE_IPV6;
26374408Smdodd		break;
26474408Smdodd#endif	/* INET6 */
26574408Smdodd#endif	/* NOT_YET */
26674408Smdodd#ifdef IPX
26774408Smdodd	case AF_IPX:
26874408Smdodd	{
26974408Smdodd		u_int8_t	*cp;
27074408Smdodd
27174408Smdodd		snap_type = 0;
27274408Smdodd		bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
27374408Smdodd			sizeof (edst));
27474408Smdodd
275111119Simp		M_PREPEND(m, 3, M_TRYWAIT);
27644627Sjulian		if (m == 0)
27744627Sjulian			senderr(ENOBUFS);
27874408Smdodd		m = m_pullup(m, 3);
27974408Smdodd		if (m == 0)
28074408Smdodd			senderr(ENOBUFS);
28174408Smdodd		cp = mtod(m, u_int8_t *);
28274408Smdodd		*cp++ = ETHERTYPE_IPX_8022;
28374408Smdodd		*cp++ = ETHERTYPE_IPX_8022;
28474408Smdodd		*cp++ = LLC_UI;
28574408Smdodd	}
28674408Smdodd	break;
28774408Smdodd#endif	/* IPX */
28844165Sjulian	case AF_UNSPEC:
28974408Smdodd	{
29074408Smdodd		struct iso88025_sockaddr_data *sd;
29144627Sjulian		/*
29244627Sjulian		 * For AF_UNSPEC sockaddr.sa_data must contain all of the
29344627Sjulian		 * mac information needed to send the packet.  This allows
29444627Sjulian		 * full mac, llc, and source routing function to be controlled.
29544627Sjulian		 * llc and source routing information must already be in the
29644627Sjulian		 * mbuf provided, ac/fc are set in sa_data.  sockaddr.sa_data
297108533Sschweikh		 * should be an iso88025_sockaddr_data structure see iso88025.h
29844627Sjulian		 */
29944165Sjulian                loop_copy = -1;
30044627Sjulian		sd = (struct iso88025_sockaddr_data *)dst->sa_data;
30144627Sjulian		gen_th.ac = sd->ac;
30244627Sjulian		gen_th.fc = sd->fc;
30374408Smdodd		(void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost,
30474408Smdodd			sizeof(sd->ether_dhost));
30574408Smdodd		(void)memcpy((caddr_t)gen_th.iso88025_shost,
30674408Smdodd			(caddr_t)sd->ether_shost, sizeof(sd->ether_shost));
30744627Sjulian		rif_len = 0;
30844165Sjulian		break;
30974408Smdodd	}
31044165Sjulian	default:
311105598Sbrooks		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
31244165Sjulian		senderr(EAFNOSUPPORT);
31374408Smdodd		break;
31444165Sjulian	}
31544165Sjulian
31674408Smdodd	if (snap_type != 0) {
31774408Smdodd        	struct llc *l;
318111790Smdodd		M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT);
31974408Smdodd		if (m == 0)
32074408Smdodd			senderr(ENOBUFS);
32174408Smdodd		l = mtod(m, struct llc *);
322112268Smdodd		l->llc_snap.ether_type = htons(snap_type);
32374408Smdodd		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
324112268Smdodd		l->llc_snap.control = LLC_UI;
325112268Smdodd		l->llc_snap.org_code[0] =
326112268Smdodd			l->llc_snap.org_code[1] =
327112268Smdodd			l->llc_snap.org_code[2] = 0;
32874408Smdodd	}
32974408Smdodd
33044165Sjulian	/*
33144165Sjulian	 * Add local net header.  If no space in first mbuf,
33244165Sjulian	 * allocate another.
33344165Sjulian	 */
334111119Simp	M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT);
33544165Sjulian	if (m == 0)
33644165Sjulian		senderr(ENOBUFS);
33744627Sjulian
33874408Smdodd	(void)memcpy((caddr_t)&gen_th.iso88025_dhost, (caddr_t)edst,
33974408Smdodd		     sizeof(edst));
34074408Smdodd
34144627Sjulian	/* Copy as much of the generic header as is needed into the mbuf */
34244165Sjulian	th = mtod(m, struct iso88025_header *);
34344627Sjulian	memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
34444627Sjulian
34544165Sjulian        /*
34644165Sjulian         * If a simplex interface, and the packet is being sent to our
34744165Sjulian         * Ethernet address or a broadcast address, loopback a copy.
34844165Sjulian         * XXX To make a simplex device behave exactly like a duplex
34944165Sjulian         * device, we should copy in the case of sending to our own
35044165Sjulian         * ethernet address (thus letting the original actually appear
35144165Sjulian         * on the wire). However, we don't do that here for security
35244165Sjulian         * reasons and compatibility with the original behavior.
35344165Sjulian         */
35474408Smdodd        if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
35544165Sjulian                if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
35674408Smdodd                        struct mbuf *n;
35774408Smdodd			n = m_copy(m, 0, (int)M_COPYALL);
35874408Smdodd                        (void)if_simloop(ifp, n, dst->sa_family,
35974408Smdodd					  ISO88025_HDR_LEN);
36074408Smdodd                } else
36174408Smdodd			if (bcmp(th->iso88025_dhost, th->iso88025_shost,
36274408Smdodd				 ETHER_ADDR_LEN) == 0) {
36374408Smdodd				(void)if_simloop(ifp, m, dst->sa_family,
36474408Smdodd						 ISO88025_HDR_LEN);
36574408Smdodd                        	return(0);      /* XXX */
36674408Smdodd			}
36744165Sjulian        }
36844165Sjulian
369111790Smdodd	if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN) ) {
37069152Sjlemon		printf("iso88025_output: packet dropped QFULL.\n");
37144165Sjulian		senderr(ENOBUFS);
37244165Sjulian	}
37344165Sjulian	return (error);
37444165Sjulian
37544165Sjulianbad:
37644165Sjulian	if (m)
37744165Sjulian		m_freem(m);
37844165Sjulian	return (error);
37944165Sjulian}
38044165Sjulian
38144165Sjulian/*
38244165Sjulian * ISO 88025 de-encapsulation
38344165Sjulian */
38444165Sjulianvoid
38574408Smdoddiso88025_input(ifp, th, m)
38674408Smdodd	struct ifnet *ifp;
38774408Smdodd	struct iso88025_header *th;
38874408Smdodd	struct mbuf *m;
38944165Sjulian{
390111888Sjlemon	int isr;
391111774Smdodd	struct llc *l;
39244165Sjulian
39358313Slile	if ((ifp->if_flags & IFF_UP) == 0) {
39458313Slile		m_freem(m);
39558313Slile		return;
39658313Slile	}
39744165Sjulian
39874408Smdodd	getmicrotime(&ifp->if_lastchange);
39974408Smdodd	ifp->if_ibytes += m->m_pkthdr.len + sizeof(*th);
40058313Slile
40144165Sjulian	if (th->iso88025_dhost[0] & 1) {
40274408Smdodd		if (bcmp((caddr_t)etherbroadcastaddr,
40374408Smdodd			 (caddr_t)th->iso88025_dhost,
40474408Smdodd			 sizeof(etherbroadcastaddr)) == 0)
40544165Sjulian			m->m_flags |= M_BCAST;
40644165Sjulian		else
40744165Sjulian			m->m_flags |= M_MCAST;
40874408Smdodd		ifp->if_imcasts++;
40944165Sjulian	}
41044165Sjulian
41174408Smdodd	l = mtod(m, struct llc *);
41244165Sjulian
41374408Smdodd	switch (l->llc_dsap) {
41474408Smdodd#ifdef IPX
41574408Smdodd	case ETHERTYPE_IPX_8022:	/* Thanks a bunch Novell */
41674408Smdodd		if ((l->llc_control != LLC_UI) ||
41774408Smdodd		    (l->llc_ssap != ETHERTYPE_IPX_8022))
41874408Smdodd			goto dropanyway;
41974408Smdodd
42074408Smdodd		th->iso88025_shost[0] &= ~(TR_RII);
42174408Smdodd		m_adj(m, 3);
422111888Sjlemon		isr = NETISR_IPX;
42374408Smdodd		break;
42474408Smdodd#endif	/* IPX */
42574408Smdodd	case LLC_SNAP_LSAP: {
42674408Smdodd		u_int16_t type;
42774408Smdodd		if ((l->llc_control != LLC_UI) ||
42874408Smdodd		    (l->llc_ssap != LLC_SNAP_LSAP))
42974408Smdodd			goto dropanyway;
43074408Smdodd
431112268Smdodd		if (l->llc_snap.org_code[0] != 0 ||
432112268Smdodd		    l->llc_snap.org_code[1] != 0 ||
433112268Smdodd		    l->llc_snap.org_code[2] != 0)
43474408Smdodd			goto dropanyway;
43574408Smdodd
436112268Smdodd		type = ntohs(l->llc_snap.ether_type);
437111790Smdodd		m_adj(m, LLC_SNAPFRAMELEN);
43874408Smdodd		switch (type) {
43944165Sjulian#ifdef INET
44074408Smdodd		case ETHERTYPE_IP:
44174408Smdodd			th->iso88025_shost[0] &= ~(TR_RII);
44274408Smdodd			if (ipflow_fastforward(m))
44374408Smdodd				return;
444111888Sjlemon			isr = NETISR_IP;
44574408Smdodd			break;
44674408Smdodd
44774408Smdodd		case ETHERTYPE_ARP:
44878295Sjlemon			if (ifp->if_flags & IFF_NOARP)
44978295Sjlemon				goto dropanyway;
450111888Sjlemon			isr = NETISR_ARP;
45174408Smdodd			break;
45274408Smdodd#endif	/* INET */
45374408Smdodd#ifdef IPX_SNAP	/* XXX: Not supported! */
45474408Smdodd		case ETHERTYPE_IPX:
45574408Smdodd			th->iso88025_shost[0] &= ~(TR_RII);
456111888Sjlemon			isr = NETISR_IPX;
45774408Smdodd			break;
45874408Smdodd#endif	/* IPX_SNAP */
45974408Smdodd#ifdef NOT_YET
46074408Smdodd#ifdef INET6
46174408Smdodd		case ETHERTYPE_IPV6:
46274408Smdodd			th->iso88025_shost[0] &= ~(TR_RII);
463111888Sjlemon			isr = NETISR_IPV6;
46474408Smdodd			break;
46574408Smdodd#endif	/* INET6 */
46674408Smdodd#endif	/* NOT_YET */
46774408Smdodd		default:
46874408Smdodd			printf("iso88025_input: unexpected llc_snap ether_type  0x%02x\n", type);
46974408Smdodd			m_freem(m);
47044165Sjulian			return;
47174408Smdodd		}
47244165Sjulian		break;
47374408Smdodd	}
47474408Smdodd	case LLC_ISO_LSAP:
47574408Smdodd		switch (l->llc_control) {
47674408Smdodd		case LLC_UI:
47774408Smdodd			goto dropanyway;
47874408Smdodd			break;
47974408Smdodd                case LLC_XID:
48074408Smdodd                case LLC_XID_P:
48174408Smdodd			if(m->m_len < ISO88025_ADDR_LEN)
48274408Smdodd				goto dropanyway;
48374408Smdodd			l->llc_window = 0;
48474408Smdodd			l->llc_fid = 9;
48574408Smdodd			l->llc_class = 1;
48674408Smdodd			l->llc_dsap = l->llc_ssap = 0;
48774408Smdodd			/* Fall through to */
48874408Smdodd		case LLC_TEST:
48974408Smdodd		case LLC_TEST_P:
49074408Smdodd		{
49174408Smdodd			struct sockaddr sa;
49274408Smdodd			struct arpcom *ac = (struct arpcom *)ifp;
49374408Smdodd			struct iso88025_sockaddr_data *th2;
49474408Smdodd			int i;
49574408Smdodd			u_char c = l->llc_dsap;
49644165Sjulian
49774408Smdodd			if (th->iso88025_shost[0] & TR_RII) { /* XXX */
49874408Smdodd				printf("iso88025_input: dropping source routed LLC_TEST\n");
49974408Smdodd				m_free(m);
50074408Smdodd				return;
50174408Smdodd			}
50274408Smdodd			l->llc_dsap = l->llc_ssap;
50374408Smdodd			l->llc_ssap = c;
50474408Smdodd			if (m->m_flags & (M_BCAST | M_MCAST))
50574408Smdodd				bcopy((caddr_t)ac->ac_enaddr,
50674408Smdodd			      		(caddr_t)th->iso88025_dhost,
50774408Smdodd					ISO88025_ADDR_LEN);
50874408Smdodd			sa.sa_family = AF_UNSPEC;
50974408Smdodd			sa.sa_len = sizeof(sa);
51074408Smdodd			th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
51174408Smdodd			for (i = 0; i < ISO88025_ADDR_LEN; i++) {
51274408Smdodd				th2->ether_shost[i] = c = th->iso88025_dhost[i];
51374408Smdodd				th2->ether_dhost[i] = th->iso88025_dhost[i] =
51474408Smdodd					th->iso88025_shost[i];
51574408Smdodd				th->iso88025_shost[i] = c;
51674408Smdodd			}
51774408Smdodd			th2->ac = TR_AC;
51874408Smdodd			th2->fc = TR_LLC_FRAME;
51974408Smdodd			ifp->if_output(ifp, m, &sa, NULL);
52074408Smdodd			return;
52174408Smdodd		}
52274408Smdodd		default:
52374408Smdodd			printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
52474408Smdodd			m_freem(m);
52574408Smdodd			return;
52674408Smdodd		}
52774408Smdodd		break;
52844165Sjulian	default:
52974408Smdodd		printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
53074408Smdodd		ifp->if_noproto++;
53174408Smdodd	dropanyway:
53274408Smdodd		m_freem(m);
53374408Smdodd		return;
53444165Sjulian	}
535111888Sjlemon	netisr_dispatch(isr, m);
53644165Sjulian}
537112269Smdodd
538112273Smdoddstatic int
539112273Smdoddiso88025_resolvemulti (ifp, llsa, sa)
540112273Smdodd	struct ifnet *ifp;
541112273Smdodd	struct sockaddr **llsa;
542112273Smdodd	struct sockaddr *sa;
543112273Smdodd{
544112273Smdodd	struct sockaddr_dl *sdl;
545112273Smdodd	struct sockaddr_in *sin;
546112273Smdodd#ifdef INET6
547112273Smdodd	struct sockaddr_in6 *sin6;
548112273Smdodd#endif
549112273Smdodd	u_char *e_addr;
550112273Smdodd
551112273Smdodd	switch(sa->sa_family) {
552112273Smdodd	case AF_LINK:
553112273Smdodd		/*
554112273Smdodd		 * No mapping needed. Just check that it's a valid MC address.
555112273Smdodd		 */
556112273Smdodd		sdl = (struct sockaddr_dl *)sa;
557112273Smdodd		e_addr = LLADDR(sdl);
558112273Smdodd		if ((e_addr[0] & 1) != 1) {
559112273Smdodd			return (EADDRNOTAVAIL);
560112273Smdodd		}
561112273Smdodd		*llsa = 0;
562112273Smdodd		return (0);
563112273Smdodd
564112273Smdodd#ifdef INET
565112273Smdodd	case AF_INET:
566112273Smdodd		sin = (struct sockaddr_in *)sa;
567112273Smdodd		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
568112273Smdodd			return (EADDRNOTAVAIL);
569112273Smdodd		}
570112273Smdodd		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
571112273Smdodd		       M_WAITOK|M_ZERO);
572112273Smdodd		sdl->sdl_len = sizeof *sdl;
573112273Smdodd		sdl->sdl_family = AF_LINK;
574112273Smdodd		sdl->sdl_index = ifp->if_index;
575112273Smdodd		sdl->sdl_type = IFT_ISO88025;
576112273Smdodd		sdl->sdl_alen = ISO88025_ADDR_LEN;
577112273Smdodd		e_addr = LLADDR(sdl);
578112273Smdodd		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
579112273Smdodd		*llsa = (struct sockaddr *)sdl;
580112273Smdodd		return (0);
581112273Smdodd#endif
582112273Smdodd#ifdef INET6
583112273Smdodd	case AF_INET6:
584112273Smdodd		sin6 = (struct sockaddr_in6 *)sa;
585112273Smdodd		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
586112273Smdodd			/*
587112273Smdodd			 * An IP6 address of 0 means listen to all
588112273Smdodd			 * of the Ethernet multicast address used for IP6.
589112273Smdodd			 * (This is used for multicast routers.)
590112273Smdodd			 */
591112273Smdodd			ifp->if_flags |= IFF_ALLMULTI;
592112273Smdodd			*llsa = 0;
593112273Smdodd			return (0);
594112273Smdodd		}
595112273Smdodd		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
596112273Smdodd			return (EADDRNOTAVAIL);
597112273Smdodd		}
598112273Smdodd		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
599112273Smdodd		       M_WAITOK|M_ZERO);
600112273Smdodd		sdl->sdl_len = sizeof *sdl;
601112273Smdodd		sdl->sdl_family = AF_LINK;
602112273Smdodd		sdl->sdl_index = ifp->if_index;
603112273Smdodd		sdl->sdl_type = IFT_ISO88025;
604112273Smdodd		sdl->sdl_alen = ISO88025_ADDR_LEN;
605112273Smdodd		e_addr = LLADDR(sdl);
606112273Smdodd		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
607112273Smdodd		*llsa = (struct sockaddr *)sdl;
608112273Smdodd		return (0);
609112273Smdodd#endif
610112273Smdodd
611112273Smdodd	default:
612112273Smdodd		/*
613112273Smdodd		 * Well, the text isn't quite right, but it's the name
614112273Smdodd		 * that counts...
615112273Smdodd		 */
616112273Smdodd		return (EAFNOSUPPORT);
617112273Smdodd	}
618112273Smdodd
619112273Smdodd	return (0);
620112273Smdodd}
621112273Smdodd
622112269Smdoddstatic moduledata_t iso88025_mod = {
623112269Smdodd	"iso88025",
624112269Smdodd	NULL,
625112269Smdodd	0
626112269Smdodd};
627112269Smdodd
628112269SmdoddDECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
629112269SmdoddMODULE_VERSION(iso88025, 1);
630