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