if_iso88025subr.c revision 112291
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 112291 2003-03-15 22:09:29Z 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" 46112285Smdodd#include "opt_mac.h" 4744165Sjulian 4844165Sjulian#include <sys/param.h> 4944165Sjulian#include <sys/systm.h> 50112271Smdodd#include <sys/kernel.h> 51112285Smdodd#include <sys/mac.h> 52112271Smdodd#include <sys/malloc.h> 5344165Sjulian#include <sys/mbuf.h> 54112271Smdodd#include <sys/module.h> 5544165Sjulian#include <sys/socket.h> 5644165Sjulian#include <sys/sockio.h> 5744165Sjulian 5844165Sjulian#include <net/if.h> 59112271Smdodd#include <net/if_dl.h> 6044165Sjulian#include <net/if_llc.h> 6144165Sjulian#include <net/if_types.h> 6244165Sjulian 63112271Smdodd#include <net/netisr.h> 64112271Smdodd#include <net/route.h> 65112271Smdodd#include <net/bpf.h> 6644165Sjulian#include <net/iso88025.h> 6744165Sjulian 6874408Smdodd#if defined(INET) || defined(INET6) 6944165Sjulian#include <netinet/in.h> 7044165Sjulian#include <netinet/in_var.h> 7144165Sjulian#include <netinet/if_ether.h> 7244165Sjulian#endif 7374408Smdodd#ifdef INET6 7474408Smdodd#include <netinet6/nd6.h> 7574408Smdodd#endif 7644165Sjulian 7774408Smdodd#ifdef IPX 7874408Smdodd#include <netipx/ipx.h> 7974408Smdodd#include <netipx/ipx_if.h> 8074408Smdodd#endif 8174408Smdodd 82112277Smdoddstatic u_char iso88025_broadcastaddr[ISO88025_ADDR_LEN] = 83112277Smdodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 84112277Smdodd 85112273Smdoddstatic int iso88025_resolvemulti (struct ifnet *, struct sockaddr **, 86112273Smdodd struct sockaddr *)); 87112273Smdodd 88112276Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP) 89112276Smdodd#define senderr(e) do { error = (e); goto bad; } while (0) 9074408Smdodd 9144165Sjulianvoid 9258313Slileiso88025_ifattach(struct ifnet *ifp) 9344165Sjulian{ 94111774Smdodd struct ifaddr *ifa = NULL; 95111774Smdodd 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; 104112277Smdodd ifp->if_broadcastaddr = iso88025_broadcastaddr; 10544165Sjulian 106112272Smdodd ifa = ifaddr_byindex(ifp->if_index); 107112272Smdodd if (ifa == 0) { 108112272Smdodd printf("iso88025_ifattach: no lladdr!\n"); 109112272Smdodd return; 110112272Smdodd } 111112272Smdodd sdl = (struct sockaddr_dl *)ifa->ifa_addr; 112112272Smdodd sdl->sdl_type = IFT_ISO88025; 113112272Smdodd sdl->sdl_alen = ifp->if_addrlen; 114112272Smdodd bcopy(IFP2AC(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{ 125112274Smdodd 12674408Smdodd if (bpf) 12774408Smdodd bpfdetach(ifp); 128112274Smdodd 12974408Smdodd if_detach(ifp); 130112274Smdodd 131112274Smdodd return; 13274408Smdodd} 13374408Smdodd 13444165Sjulianint 13544165Sjulianiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data) 13644165Sjulian{ 137112274Smdodd struct ifaddr *ifa; 138112274Smdodd struct ifreq *ifr; 139112274Smdodd int error; 14044165Sjulian 141112274Smdodd ifa = (struct ifaddr *) data; 142112274Smdodd ifr = (struct ifreq *) data; 143112274Smdodd error = 0; 144112274Smdodd 14544165Sjulian switch (command) { 14644165Sjulian case SIOCSIFADDR: 14744165Sjulian ifp->if_flags |= IFF_UP; 14844165Sjulian 14944165Sjulian switch (ifa->ifa_addr->sa_family) { 15044165Sjulian#ifdef INET 15144165Sjulian case AF_INET: 15244165Sjulian ifp->if_init(ifp->if_softc); /* before arpwhohas */ 15384931Sfjoe arp_ifinit(ifp, ifa); 15444165Sjulian break; 15574408Smdodd#endif /* INET */ 15674408Smdodd#ifdef IPX 15774408Smdodd /* 15874408Smdodd * XXX - This code is probably wrong 15974408Smdodd */ 16074408Smdodd case AF_IPX: 16174408Smdodd { 162111774Smdodd struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 16374408Smdodd struct arpcom *ac = IFP2AC(ifp); 16474408Smdodd 16574408Smdodd if (ipx_nullhost(*ina)) 166112274Smdodd ina->x_host = *(union ipx_host *)ac->ac_enaddr; 16774408Smdodd else { 16874408Smdodd bcopy((caddr_t) ina->x_host.c_host, 16974408Smdodd (caddr_t) ac->ac_enaddr, 170112278Smdodd ISO88025_ADDR_LEN); 17174408Smdodd } 17274408Smdodd 17374408Smdodd /* 17474408Smdodd * Set new address 17574408Smdodd */ 17674408Smdodd ifp->if_init(ifp->if_softc); 17774408Smdodd break; 17874408Smdodd } 17974408Smdodd#endif /* IPX */ 18044165Sjulian default: 18144165Sjulian ifp->if_init(ifp->if_softc); 18244165Sjulian break; 18344165Sjulian } 18444165Sjulian break; 18544165Sjulian 18644165Sjulian case SIOCGIFADDR: 18744165Sjulian { 18844165Sjulian struct sockaddr *sa; 18944165Sjulian 19044165Sjulian sa = (struct sockaddr *) & ifr->ifr_data; 191111775Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, 19244165Sjulian (caddr_t) sa->sa_data, ISO88025_ADDR_LEN); 19344165Sjulian } 19444165Sjulian break; 19544165Sjulian 19644165Sjulian case SIOCSIFMTU: 19744165Sjulian /* 19844165Sjulian * Set the interface MTU. 19944165Sjulian */ 20058313Slile if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 20144165Sjulian error = EINVAL; 20244165Sjulian } else { 20344165Sjulian ifp->if_mtu = ifr->ifr_mtu; 20444165Sjulian } 20544165Sjulian break; 206112274Smdodd default: 207112274Smdodd error = EINVAL; /* XXX netbsd has ENOTTY??? */ 208112274Smdodd break; 20944165Sjulian } 210112274Smdodd 21144165Sjulian return (error); 21244165Sjulian} 21344165Sjulian 21444165Sjulian/* 21544165Sjulian * ISO88025 encapsulation 21644165Sjulian */ 21744165Sjulianint 21874408Smdoddiso88025_output(ifp, m, dst, rt0) 21974408Smdodd struct ifnet *ifp; 22074408Smdodd struct mbuf *m; 22174408Smdodd struct sockaddr *dst; 22274408Smdodd struct rtentry *rt0; 22344165Sjulian{ 22474408Smdodd u_int16_t snap_type = 0; 22587914Sjlemon int loop_copy = 0, error = 0, rif_len = 0; 22687914Sjlemon u_char edst[ISO88025_ADDR_LEN]; 22774408Smdodd struct iso88025_header *th; 22844627Sjulian struct iso88025_header gen_th; 22974408Smdodd struct sockaddr_dl *sdl = NULL; 23074408Smdodd struct rtentry *rt; 23144165Sjulian struct arpcom *ac = (struct arpcom *)ifp; 23244165Sjulian 233112285Smdodd#ifdef MAC 234112285Smdodd error = mac_check_ifnet_transmit(ifp, m); 235112285Smdodd if (error) 236112285Smdodd senderr(error); 237112285Smdodd#endif 238112285Smdodd 23944165Sjulian if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 24044165Sjulian senderr(ENETDOWN); 24174408Smdodd getmicrotime(&ifp->if_lastchange); 24274408Smdodd 243111767Smdodd error = rt_check(&rt, &rt0, dst); 244112274Smdodd if (error) 245111767Smdodd goto bad; 24644627Sjulian 24744627Sjulian /* Calculate routing info length based on arp table entry */ 24844627Sjulian if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway)) 249102291Sarchie if (SDL_ISO88025(sdl)->trld_rcf != 0) 25096184Skbyanc rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 25144627Sjulian 25244627Sjulian /* Generate a generic 802.5 header for the packet */ 25358313Slile gen_th.ac = TR_AC; 25458313Slile gen_th.fc = TR_LLC_FRAME; 25574408Smdodd (void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr, 256112278Smdodd ISO88025_ADDR_LEN); 25744627Sjulian if (rif_len) { 25858313Slile gen_th.iso88025_shost[0] |= TR_RII; 25944627Sjulian if (rif_len > 2) { 26096184Skbyanc gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 26174408Smdodd (void)memcpy((caddr_t)gen_th.rd, 26296184Skbyanc (caddr_t)SDL_ISO88025(sdl)->trld_route, 26396184Skbyanc rif_len - 2); 26444627Sjulian } 26544627Sjulian } 26644627Sjulian 26744165Sjulian switch (dst->sa_family) { 26844165Sjulian#ifdef INET 26944165Sjulian case AF_INET: 27084931Sfjoe if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 27144165Sjulian return (0); /* if not yet resolved */ 27274408Smdodd snap_type = ETHERTYPE_IP; 27374408Smdodd break; 27474408Smdodd#endif /* INET */ 27574408Smdodd#ifdef NOT_YET 27674408Smdodd#ifdef INET6 27774408Smdodd case AF_INET6: 27874408Smdodd if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 27974408Smdodd /* Something bad happened */ 28074408Smdodd return(0); 28174408Smdodd } 28274408Smdodd snap_type = ETHERTYPE_IPV6; 28374408Smdodd break; 28474408Smdodd#endif /* INET6 */ 28574408Smdodd#endif /* NOT_YET */ 28674408Smdodd#ifdef IPX 28774408Smdodd case AF_IPX: 28874408Smdodd { 28974408Smdodd u_int8_t *cp; 29074408Smdodd 29174408Smdodd snap_type = 0; 29274408Smdodd bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 293112278Smdodd ISO88025_ADDR_LEN); 29474408Smdodd 295111119Simp M_PREPEND(m, 3, M_TRYWAIT); 29644627Sjulian if (m == 0) 29744627Sjulian senderr(ENOBUFS); 29874408Smdodd m = m_pullup(m, 3); 29974408Smdodd if (m == 0) 30074408Smdodd senderr(ENOBUFS); 30174408Smdodd cp = mtod(m, u_int8_t *); 30274408Smdodd *cp++ = ETHERTYPE_IPX_8022; 30374408Smdodd *cp++ = ETHERTYPE_IPX_8022; 30474408Smdodd *cp++ = LLC_UI; 30574408Smdodd } 30674408Smdodd break; 30774408Smdodd#endif /* IPX */ 30844165Sjulian case AF_UNSPEC: 30974408Smdodd { 31074408Smdodd struct iso88025_sockaddr_data *sd; 31144627Sjulian /* 31244627Sjulian * For AF_UNSPEC sockaddr.sa_data must contain all of the 31344627Sjulian * mac information needed to send the packet. This allows 31444627Sjulian * full mac, llc, and source routing function to be controlled. 31544627Sjulian * llc and source routing information must already be in the 31644627Sjulian * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 317108533Sschweikh * should be an iso88025_sockaddr_data structure see iso88025.h 31844627Sjulian */ 31944165Sjulian loop_copy = -1; 32044627Sjulian sd = (struct iso88025_sockaddr_data *)dst->sa_data; 32144627Sjulian gen_th.ac = sd->ac; 32244627Sjulian gen_th.fc = sd->fc; 32374408Smdodd (void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost, 324112278Smdodd ISO88025_ADDR_LEN); 32574408Smdodd (void)memcpy((caddr_t)gen_th.iso88025_shost, 326112280Smdodd (caddr_t)sd->ether_shost, ISO88025_ADDR_LEN); 32744627Sjulian rif_len = 0; 32844165Sjulian break; 32974408Smdodd } 33044165Sjulian default: 331105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 33244165Sjulian senderr(EAFNOSUPPORT); 33374408Smdodd break; 33444165Sjulian } 33544165Sjulian 336112274Smdodd /* 337112274Smdodd * Add LLC header. 338112274Smdodd */ 33974408Smdodd if (snap_type != 0) { 34074408Smdodd struct llc *l; 341111790Smdodd M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 34274408Smdodd if (m == 0) 34374408Smdodd senderr(ENOBUFS); 34474408Smdodd l = mtod(m, struct llc *); 345112281Smdodd l->llc_control = LLC_UI; 34674408Smdodd l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 347112268Smdodd l->llc_snap.org_code[0] = 348112268Smdodd l->llc_snap.org_code[1] = 349112268Smdodd l->llc_snap.org_code[2] = 0; 350112274Smdodd l->llc_snap.ether_type = htons(snap_type); 35174408Smdodd } 35274408Smdodd 35344165Sjulian /* 35444165Sjulian * Add local net header. If no space in first mbuf, 35544165Sjulian * allocate another. 35644165Sjulian */ 357111119Simp M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT); 35844165Sjulian if (m == 0) 35944165Sjulian senderr(ENOBUFS); 360112274Smdodd th = mtod(m, struct iso88025_header *); 361112291Smdodd bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN); 36244627Sjulian 36344627Sjulian /* Copy as much of the generic header as is needed into the mbuf */ 36444627Sjulian memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 36544627Sjulian 36644165Sjulian /* 36744165Sjulian * If a simplex interface, and the packet is being sent to our 36844165Sjulian * Ethernet address or a broadcast address, loopback a copy. 36944165Sjulian * XXX To make a simplex device behave exactly like a duplex 37044165Sjulian * device, we should copy in the case of sending to our own 37144165Sjulian * ethernet address (thus letting the original actually appear 37244165Sjulian * on the wire). However, we don't do that here for security 37344165Sjulian * reasons and compatibility with the original behavior. 37444165Sjulian */ 37574408Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 37644165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 37774408Smdodd struct mbuf *n; 37874408Smdodd n = m_copy(m, 0, (int)M_COPYALL); 379112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 38074408Smdodd ISO88025_HDR_LEN); 381112279Smdodd } else if (bcmp(th->iso88025_dhost, th->iso88025_shost, 38274408Smdodd ETHER_ADDR_LEN) == 0) { 383112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 384112279Smdodd ISO88025_HDR_LEN); 385112279Smdodd return(0); /* XXX */ 386112279Smdodd } 38744165Sjulian } 38844165Sjulian 389111790Smdodd if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN) ) { 39069152Sjlemon printf("iso88025_output: packet dropped QFULL.\n"); 39144165Sjulian senderr(ENOBUFS); 39244165Sjulian } 39344165Sjulian return (error); 39444165Sjulian 39544165Sjulianbad: 39644165Sjulian if (m) 39744165Sjulian m_freem(m); 39844165Sjulian return (error); 39944165Sjulian} 40044165Sjulian 40144165Sjulian/* 40244165Sjulian * ISO 88025 de-encapsulation 40344165Sjulian */ 40444165Sjulianvoid 40574408Smdoddiso88025_input(ifp, th, m) 40674408Smdodd struct ifnet *ifp; 40774408Smdodd struct iso88025_header *th; 40874408Smdodd struct mbuf *m; 40944165Sjulian{ 410111888Sjlemon int isr; 411111774Smdodd struct llc *l; 41244165Sjulian 413112286Smdodd /* 414112286Smdodd * Discard packet if interface is not up. 415112286Smdodd */ 416112286Smdodd if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 417112286Smdodd goto dropanyway; 41844165Sjulian 419112285Smdodd#ifdef MAC 420112285Smdodd mac_create_mbuf_from_ifnet(ifp, m); 421112285Smdodd#endif 422112285Smdodd 423112286Smdodd /* 424112286Smdodd * Update interface statistics. 425112286Smdodd */ 426112286Smdodd ifp->if_ibytes += m->m_pkthdr.len + sizeof(*th); 42774408Smdodd getmicrotime(&ifp->if_lastchange); 42858313Slile 429112280Smdodd /* 430112286Smdodd * Discard non local unicast packets when interface 431112286Smdodd * is in promiscuous mode. 432112286Smdodd */ 433112286Smdodd if ((ifp->if_flags & IFF_PROMISC) && 434112286Smdodd ((th->iso88025_dhost[0] & 1) == 0) && 435112286Smdodd (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t) th->iso88025_dhost, 436112286Smdodd ISO88025_ADDR_LEN) != 0)) 437112286Smdodd goto dropanyway; 438112286Smdodd } 439112286Smdodd 440112286Smdodd /* 441112280Smdodd * Set mbuf flags for bcast/mcast. 442112280Smdodd */ 44344165Sjulian if (th->iso88025_dhost[0] & 1) { 444112277Smdodd if (bcmp((caddr_t)iso88025_broadcastaddr, 445112277Smdodd (caddr_t)th->iso88025_dhost, ISO88025_ADDR_LEN) == 0) 44644165Sjulian m->m_flags |= M_BCAST; 44744165Sjulian else 44844165Sjulian m->m_flags |= M_MCAST; 44974408Smdodd ifp->if_imcasts++; 450112274Smdodd } 45144165Sjulian 45274408Smdodd l = mtod(m, struct llc *); 45344165Sjulian 45474408Smdodd switch (l->llc_dsap) { 45574408Smdodd#ifdef IPX 45674408Smdodd case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 45774408Smdodd if ((l->llc_control != LLC_UI) || 458112289Smdodd (l->llc_ssap != ETHERTYPE_IPX_8022)) { 459112289Smdodd ifp->if_noproto++; 46074408Smdodd goto dropanyway; 461112289Smdodd } 46274408Smdodd 46374408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 46474408Smdodd m_adj(m, 3); 465111888Sjlemon isr = NETISR_IPX; 46674408Smdodd break; 46774408Smdodd#endif /* IPX */ 46874408Smdodd case LLC_SNAP_LSAP: { 46974408Smdodd u_int16_t type; 47074408Smdodd if ((l->llc_control != LLC_UI) || 471112289Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 472112289Smdodd ifp->if_noproto++; 47374408Smdodd goto dropanyway; 474112289Smdodd } 47574408Smdodd 476112268Smdodd if (l->llc_snap.org_code[0] != 0 || 477112268Smdodd l->llc_snap.org_code[1] != 0 || 478112268Smdodd l->llc_snap.org_code[2] != 0) 47974408Smdodd goto dropanyway; 48074408Smdodd 481112268Smdodd type = ntohs(l->llc_snap.ether_type); 482111790Smdodd m_adj(m, LLC_SNAPFRAMELEN); 48374408Smdodd switch (type) { 48444165Sjulian#ifdef INET 48574408Smdodd case ETHERTYPE_IP: 48674408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 48774408Smdodd if (ipflow_fastforward(m)) 48874408Smdodd return; 489111888Sjlemon isr = NETISR_IP; 49074408Smdodd break; 49174408Smdodd 49274408Smdodd case ETHERTYPE_ARP: 49378295Sjlemon if (ifp->if_flags & IFF_NOARP) 49478295Sjlemon goto dropanyway; 495111888Sjlemon isr = NETISR_ARP; 49674408Smdodd break; 49774408Smdodd#endif /* INET */ 49874408Smdodd#ifdef IPX_SNAP /* XXX: Not supported! */ 49974408Smdodd case ETHERTYPE_IPX: 50074408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 501111888Sjlemon isr = NETISR_IPX; 50274408Smdodd break; 50374408Smdodd#endif /* IPX_SNAP */ 50474408Smdodd#ifdef NOT_YET 50574408Smdodd#ifdef INET6 50674408Smdodd case ETHERTYPE_IPV6: 50774408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 508111888Sjlemon isr = NETISR_IPV6; 50974408Smdodd break; 51074408Smdodd#endif /* INET6 */ 51174408Smdodd#endif /* NOT_YET */ 51274408Smdodd default: 51374408Smdodd printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 514112289Smdodd ifp->if_noproto++; 515112289Smdodd goto dropanyway; 51674408Smdodd } 51744165Sjulian break; 51874408Smdodd } 51974408Smdodd case LLC_ISO_LSAP: 52074408Smdodd switch (l->llc_control) { 52174408Smdodd case LLC_UI: 522112289Smdodd ifp->if_noproto++; 52374408Smdodd goto dropanyway; 52474408Smdodd break; 52574408Smdodd case LLC_XID: 52674408Smdodd case LLC_XID_P: 52774408Smdodd if(m->m_len < ISO88025_ADDR_LEN) 52874408Smdodd goto dropanyway; 52974408Smdodd l->llc_window = 0; 53074408Smdodd l->llc_fid = 9; 53174408Smdodd l->llc_class = 1; 53274408Smdodd l->llc_dsap = l->llc_ssap = 0; 53374408Smdodd /* Fall through to */ 53474408Smdodd case LLC_TEST: 53574408Smdodd case LLC_TEST_P: 53674408Smdodd { 53774408Smdodd struct sockaddr sa; 53874408Smdodd struct arpcom *ac = (struct arpcom *)ifp; 53974408Smdodd struct iso88025_sockaddr_data *th2; 54074408Smdodd int i; 54174408Smdodd u_char c = l->llc_dsap; 54244165Sjulian 54374408Smdodd if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 54474408Smdodd printf("iso88025_input: dropping source routed LLC_TEST\n"); 545112289Smdodd goto dropanyway; 54674408Smdodd } 54774408Smdodd l->llc_dsap = l->llc_ssap; 54874408Smdodd l->llc_ssap = c; 54974408Smdodd if (m->m_flags & (M_BCAST | M_MCAST)) 55074408Smdodd bcopy((caddr_t)ac->ac_enaddr, 551112280Smdodd (caddr_t)th->iso88025_dhost, 55274408Smdodd ISO88025_ADDR_LEN); 55374408Smdodd sa.sa_family = AF_UNSPEC; 55474408Smdodd sa.sa_len = sizeof(sa); 55574408Smdodd th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 55674408Smdodd for (i = 0; i < ISO88025_ADDR_LEN; i++) { 55774408Smdodd th2->ether_shost[i] = c = th->iso88025_dhost[i]; 55874408Smdodd th2->ether_dhost[i] = th->iso88025_dhost[i] = 55974408Smdodd th->iso88025_shost[i]; 56074408Smdodd th->iso88025_shost[i] = c; 56174408Smdodd } 56274408Smdodd th2->ac = TR_AC; 56374408Smdodd th2->fc = TR_LLC_FRAME; 56474408Smdodd ifp->if_output(ifp, m, &sa, NULL); 56574408Smdodd return; 56674408Smdodd } 56774408Smdodd default: 56874408Smdodd printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 569112289Smdodd ifp->if_noproto++; 570112289Smdodd goto dropanyway; 57174408Smdodd } 57274408Smdodd break; 57344165Sjulian default: 57474408Smdodd printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 57574408Smdodd ifp->if_noproto++; 576112289Smdodd goto dropanyway; 57744165Sjulian } 578112274Smdodd 579111888Sjlemon netisr_dispatch(isr, m); 580112274Smdodd return; 581112289Smdodd 582112289Smdodddropanyway: 583112289Smdodd ifp->if_iqdrops++; 584112289Smdodd if (m) 585112289Smdodd m_freem(m); 586112289Smdodd return; 58744165Sjulian} 588112269Smdodd 589112273Smdoddstatic int 590112273Smdoddiso88025_resolvemulti (ifp, llsa, sa) 591112273Smdodd struct ifnet *ifp; 592112273Smdodd struct sockaddr **llsa; 593112273Smdodd struct sockaddr *sa; 594112273Smdodd{ 595112273Smdodd struct sockaddr_dl *sdl; 596112273Smdodd struct sockaddr_in *sin; 597112273Smdodd#ifdef INET6 598112273Smdodd struct sockaddr_in6 *sin6; 599112273Smdodd#endif 600112273Smdodd u_char *e_addr; 601112273Smdodd 602112273Smdodd switch(sa->sa_family) { 603112273Smdodd case AF_LINK: 604112273Smdodd /* 605112273Smdodd * No mapping needed. Just check that it's a valid MC address. 606112273Smdodd */ 607112273Smdodd sdl = (struct sockaddr_dl *)sa; 608112273Smdodd e_addr = LLADDR(sdl); 609112273Smdodd if ((e_addr[0] & 1) != 1) { 610112273Smdodd return (EADDRNOTAVAIL); 611112273Smdodd } 612112273Smdodd *llsa = 0; 613112273Smdodd return (0); 614112273Smdodd 615112273Smdodd#ifdef INET 616112273Smdodd case AF_INET: 617112273Smdodd sin = (struct sockaddr_in *)sa; 618112273Smdodd if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 619112273Smdodd return (EADDRNOTAVAIL); 620112273Smdodd } 621112273Smdodd MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 622112273Smdodd M_WAITOK|M_ZERO); 623112273Smdodd sdl->sdl_len = sizeof *sdl; 624112273Smdodd sdl->sdl_family = AF_LINK; 625112273Smdodd sdl->sdl_index = ifp->if_index; 626112273Smdodd sdl->sdl_type = IFT_ISO88025; 627112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 628112273Smdodd e_addr = LLADDR(sdl); 629112273Smdodd ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 630112273Smdodd *llsa = (struct sockaddr *)sdl; 631112273Smdodd return (0); 632112273Smdodd#endif 633112273Smdodd#ifdef INET6 634112273Smdodd case AF_INET6: 635112273Smdodd sin6 = (struct sockaddr_in6 *)sa; 636112273Smdodd if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 637112273Smdodd /* 638112273Smdodd * An IP6 address of 0 means listen to all 639112273Smdodd * of the Ethernet multicast address used for IP6. 640112273Smdodd * (This is used for multicast routers.) 641112273Smdodd */ 642112273Smdodd ifp->if_flags |= IFF_ALLMULTI; 643112273Smdodd *llsa = 0; 644112273Smdodd return (0); 645112273Smdodd } 646112273Smdodd if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 647112273Smdodd return (EADDRNOTAVAIL); 648112273Smdodd } 649112273Smdodd MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 650112273Smdodd M_WAITOK|M_ZERO); 651112273Smdodd sdl->sdl_len = sizeof *sdl; 652112273Smdodd sdl->sdl_family = AF_LINK; 653112273Smdodd sdl->sdl_index = ifp->if_index; 654112273Smdodd sdl->sdl_type = IFT_ISO88025; 655112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 656112273Smdodd e_addr = LLADDR(sdl); 657112273Smdodd ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 658112273Smdodd *llsa = (struct sockaddr *)sdl; 659112273Smdodd return (0); 660112273Smdodd#endif 661112273Smdodd 662112273Smdodd default: 663112273Smdodd /* 664112273Smdodd * Well, the text isn't quite right, but it's the name 665112273Smdodd * that counts... 666112273Smdodd */ 667112273Smdodd return (EAFNOSUPPORT); 668112273Smdodd } 669112273Smdodd 670112273Smdodd return (0); 671112273Smdodd} 672112273Smdodd 673112269Smdoddstatic moduledata_t iso88025_mod = { 674112269Smdodd "iso88025", 675112269Smdodd NULL, 676112269Smdodd 0 677112269Smdodd}; 678112269Smdodd 679112269SmdoddDECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 680112269SmdoddMODULE_VERSION(iso88025, 1); 681