if_iso88025subr.c revision 112308
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 112308 2003-03-16 00:17:44Z 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 **, 86112294Smdodd struct sockaddr *); 87112273Smdodd 88112276Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP) 89112276Smdodd#define senderr(e) do { error = (e); goto bad; } while (0) 9074408Smdodd 91112297Smdodd/* 92112297Smdodd * Perform common duties while attaching to interface list 93112297Smdodd */ 9444165Sjulianvoid 95112297Smdoddiso88025_ifattach(struct ifnet *ifp, int bpf) 9644165Sjulian{ 97112296Smdodd struct ifaddr *ifa; 98111774Smdodd struct sockaddr_dl *sdl; 9944165Sjulian 100112296Smdodd ifa = NULL; 101112296Smdodd 10244165Sjulian ifp->if_type = IFT_ISO88025; 10358313Slile ifp->if_addrlen = ISO88025_ADDR_LEN; 10458313Slile ifp->if_hdrlen = ISO88025_HDR_LEN; 105112297Smdodd 106112297Smdodd if_attach(ifp); /* Must be called before additional assignments */ 107112297Smdodd 108112297Smdodd ifp->if_output = iso88025_output; 109112297Smdodd ifp->if_input = iso88025_input; 110112297Smdodd ifp->if_resolvemulti = iso88025_resolvemulti; 111112297Smdodd ifp->if_broadcastaddr = iso88025_broadcastaddr; 112112297Smdodd 11344165Sjulian if (ifp->if_baudrate == 0) 11458313Slile ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */ 11544165Sjulian if (ifp->if_mtu == 0) 11644165Sjulian ifp->if_mtu = ISO88025_DEFAULT_MTU; 11744165Sjulian 118112272Smdodd ifa = ifaddr_byindex(ifp->if_index); 119112272Smdodd if (ifa == 0) { 120112298Smdodd if_printf(ifp, "%s() no lladdr!\n", __func__); 121112298Smdodd return; 122112272Smdodd } 123112297Smdodd 124112272Smdodd sdl = (struct sockaddr_dl *)ifa->ifa_addr; 125112272Smdodd sdl->sdl_type = IFT_ISO88025; 126112272Smdodd sdl->sdl_alen = ifp->if_addrlen; 127112272Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 128112297Smdodd 129112297Smdodd if (bpf) 130112297Smdodd bpfattach(ifp, DLT_IEEE802, ISO88025_HDR_LEN); 131112297Smdodd 132112297Smdodd return; 13344165Sjulian} 13444165Sjulian 13574408Smdodd/* 13674408Smdodd * Perform common duties while detaching a Token Ring interface 13774408Smdodd */ 13874408Smdoddvoid 13974408Smdoddiso88025_ifdetach(ifp, bpf) 14074408Smdodd struct ifnet *ifp; 14174408Smdodd int bpf; 14274408Smdodd{ 143112274Smdodd 14474408Smdodd if (bpf) 14574408Smdodd bpfdetach(ifp); 146112274Smdodd 14774408Smdodd if_detach(ifp); 148112274Smdodd 149112274Smdodd return; 15074408Smdodd} 15174408Smdodd 15244165Sjulianint 15344165Sjulianiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data) 15444165Sjulian{ 155112274Smdodd struct ifaddr *ifa; 156112274Smdodd struct ifreq *ifr; 157112274Smdodd int error; 15844165Sjulian 159112274Smdodd ifa = (struct ifaddr *) data; 160112274Smdodd ifr = (struct ifreq *) data; 161112274Smdodd error = 0; 162112274Smdodd 16344165Sjulian switch (command) { 16444165Sjulian case SIOCSIFADDR: 16544165Sjulian ifp->if_flags |= IFF_UP; 16644165Sjulian 16744165Sjulian switch (ifa->ifa_addr->sa_family) { 16844165Sjulian#ifdef INET 16944165Sjulian case AF_INET: 17044165Sjulian ifp->if_init(ifp->if_softc); /* before arpwhohas */ 17184931Sfjoe arp_ifinit(ifp, ifa); 17244165Sjulian break; 17374408Smdodd#endif /* INET */ 17474408Smdodd#ifdef IPX 17574408Smdodd /* 17674408Smdodd * XXX - This code is probably wrong 17774408Smdodd */ 17874408Smdodd case AF_IPX: 17974408Smdodd { 180111774Smdodd struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 18174408Smdodd struct arpcom *ac = IFP2AC(ifp); 18274408Smdodd 18374408Smdodd if (ipx_nullhost(*ina)) 184112274Smdodd ina->x_host = *(union ipx_host *)ac->ac_enaddr; 18574408Smdodd else { 18674408Smdodd bcopy((caddr_t) ina->x_host.c_host, 18774408Smdodd (caddr_t) ac->ac_enaddr, 188112278Smdodd ISO88025_ADDR_LEN); 18974408Smdodd } 19074408Smdodd 19174408Smdodd /* 19274408Smdodd * Set new address 19374408Smdodd */ 19474408Smdodd ifp->if_init(ifp->if_softc); 19574408Smdodd break; 19674408Smdodd } 19774408Smdodd#endif /* IPX */ 19844165Sjulian default: 19944165Sjulian ifp->if_init(ifp->if_softc); 20044165Sjulian break; 20144165Sjulian } 20244165Sjulian break; 20344165Sjulian 20444165Sjulian case SIOCGIFADDR: 20544165Sjulian { 20644165Sjulian struct sockaddr *sa; 20744165Sjulian 20844165Sjulian sa = (struct sockaddr *) & ifr->ifr_data; 209111775Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, 21044165Sjulian (caddr_t) sa->sa_data, ISO88025_ADDR_LEN); 21144165Sjulian } 21244165Sjulian break; 21344165Sjulian 21444165Sjulian case SIOCSIFMTU: 21544165Sjulian /* 21644165Sjulian * Set the interface MTU. 21744165Sjulian */ 21858313Slile if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 21944165Sjulian error = EINVAL; 22044165Sjulian } else { 22144165Sjulian ifp->if_mtu = ifr->ifr_mtu; 22244165Sjulian } 22344165Sjulian break; 224112274Smdodd default: 225112274Smdodd error = EINVAL; /* XXX netbsd has ENOTTY??? */ 226112274Smdodd break; 22744165Sjulian } 228112274Smdodd 22944165Sjulian return (error); 23044165Sjulian} 23144165Sjulian 23244165Sjulian/* 23344165Sjulian * ISO88025 encapsulation 23444165Sjulian */ 23544165Sjulianint 23674408Smdoddiso88025_output(ifp, m, dst, rt0) 23774408Smdodd struct ifnet *ifp; 23874408Smdodd struct mbuf *m; 23974408Smdodd struct sockaddr *dst; 24074408Smdodd struct rtentry *rt0; 24144165Sjulian{ 24274408Smdodd u_int16_t snap_type = 0; 24387914Sjlemon int loop_copy = 0, error = 0, rif_len = 0; 24487914Sjlemon u_char edst[ISO88025_ADDR_LEN]; 24574408Smdodd struct iso88025_header *th; 24644627Sjulian struct iso88025_header gen_th; 24774408Smdodd struct sockaddr_dl *sdl = NULL; 24874408Smdodd struct rtentry *rt; 249112308Smdodd struct arpcom *ac = IFP2AC(ifp); 25044165Sjulian 251112285Smdodd#ifdef MAC 252112285Smdodd error = mac_check_ifnet_transmit(ifp, m); 253112285Smdodd if (error) 254112285Smdodd senderr(error); 255112285Smdodd#endif 256112285Smdodd 257112308Smdodd if (ifp->if_flags & IFF_MONITOR) 258112308Smdodd senderr(ENETDOWN); 25944165Sjulian if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 26044165Sjulian senderr(ENETDOWN); 26174408Smdodd getmicrotime(&ifp->if_lastchange); 26274408Smdodd 263111767Smdodd error = rt_check(&rt, &rt0, dst); 264112274Smdodd if (error) 265111767Smdodd goto bad; 26644627Sjulian 26744627Sjulian /* Calculate routing info length based on arp table entry */ 26844627Sjulian if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway)) 269102291Sarchie if (SDL_ISO88025(sdl)->trld_rcf != 0) 27096184Skbyanc rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 27144627Sjulian 27244627Sjulian /* Generate a generic 802.5 header for the packet */ 27358313Slile gen_th.ac = TR_AC; 27458313Slile gen_th.fc = TR_LLC_FRAME; 27574408Smdodd (void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr, 276112278Smdodd ISO88025_ADDR_LEN); 27744627Sjulian if (rif_len) { 27858313Slile gen_th.iso88025_shost[0] |= TR_RII; 27944627Sjulian if (rif_len > 2) { 28096184Skbyanc gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 28174408Smdodd (void)memcpy((caddr_t)gen_th.rd, 28296184Skbyanc (caddr_t)SDL_ISO88025(sdl)->trld_route, 28396184Skbyanc rif_len - 2); 28444627Sjulian } 28544627Sjulian } 28644627Sjulian 28744165Sjulian switch (dst->sa_family) { 28844165Sjulian#ifdef INET 28944165Sjulian case AF_INET: 29084931Sfjoe if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 29144165Sjulian return (0); /* if not yet resolved */ 29274408Smdodd snap_type = ETHERTYPE_IP; 29374408Smdodd break; 29474408Smdodd#endif /* INET */ 29574408Smdodd#ifdef NOT_YET 29674408Smdodd#ifdef INET6 29774408Smdodd case AF_INET6: 29874408Smdodd if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 29974408Smdodd /* Something bad happened */ 30074408Smdodd return(0); 30174408Smdodd } 30274408Smdodd snap_type = ETHERTYPE_IPV6; 30374408Smdodd break; 30474408Smdodd#endif /* INET6 */ 30574408Smdodd#endif /* NOT_YET */ 30674408Smdodd#ifdef IPX 30774408Smdodd case AF_IPX: 30874408Smdodd { 30974408Smdodd u_int8_t *cp; 31074408Smdodd 31174408Smdodd bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 312112278Smdodd ISO88025_ADDR_LEN); 31374408Smdodd 314111119Simp M_PREPEND(m, 3, M_TRYWAIT); 31544627Sjulian if (m == 0) 31644627Sjulian senderr(ENOBUFS); 31774408Smdodd m = m_pullup(m, 3); 31874408Smdodd if (m == 0) 31974408Smdodd senderr(ENOBUFS); 32074408Smdodd cp = mtod(m, u_int8_t *); 32174408Smdodd *cp++ = ETHERTYPE_IPX_8022; 32274408Smdodd *cp++ = ETHERTYPE_IPX_8022; 32374408Smdodd *cp++ = LLC_UI; 32474408Smdodd } 32574408Smdodd break; 32674408Smdodd#endif /* IPX */ 32744165Sjulian case AF_UNSPEC: 32874408Smdodd { 32974408Smdodd struct iso88025_sockaddr_data *sd; 33044627Sjulian /* 33144627Sjulian * For AF_UNSPEC sockaddr.sa_data must contain all of the 33244627Sjulian * mac information needed to send the packet. This allows 33344627Sjulian * full mac, llc, and source routing function to be controlled. 33444627Sjulian * llc and source routing information must already be in the 33544627Sjulian * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 336108533Sschweikh * should be an iso88025_sockaddr_data structure see iso88025.h 33744627Sjulian */ 33844165Sjulian loop_copy = -1; 33944627Sjulian sd = (struct iso88025_sockaddr_data *)dst->sa_data; 34044627Sjulian gen_th.ac = sd->ac; 34144627Sjulian gen_th.fc = sd->fc; 34274408Smdodd (void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost, 343112278Smdodd ISO88025_ADDR_LEN); 34474408Smdodd (void)memcpy((caddr_t)gen_th.iso88025_shost, 345112280Smdodd (caddr_t)sd->ether_shost, ISO88025_ADDR_LEN); 34644627Sjulian rif_len = 0; 34744165Sjulian break; 34874408Smdodd } 34944165Sjulian default: 350105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 35144165Sjulian senderr(EAFNOSUPPORT); 35274408Smdodd break; 35344165Sjulian } 35444165Sjulian 355112274Smdodd /* 356112274Smdodd * Add LLC header. 357112274Smdodd */ 35874408Smdodd if (snap_type != 0) { 35974408Smdodd struct llc *l; 360111790Smdodd M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 36174408Smdodd if (m == 0) 36274408Smdodd senderr(ENOBUFS); 36374408Smdodd l = mtod(m, struct llc *); 364112281Smdodd l->llc_control = LLC_UI; 36574408Smdodd l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 366112268Smdodd l->llc_snap.org_code[0] = 367112268Smdodd l->llc_snap.org_code[1] = 368112268Smdodd l->llc_snap.org_code[2] = 0; 369112274Smdodd l->llc_snap.ether_type = htons(snap_type); 37074408Smdodd } 37174408Smdodd 37244165Sjulian /* 37344165Sjulian * Add local net header. If no space in first mbuf, 37444165Sjulian * allocate another. 37544165Sjulian */ 376111119Simp M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT); 37744165Sjulian if (m == 0) 37844165Sjulian senderr(ENOBUFS); 379112274Smdodd th = mtod(m, struct iso88025_header *); 380112291Smdodd bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN); 38144627Sjulian 38244627Sjulian /* Copy as much of the generic header as is needed into the mbuf */ 38344627Sjulian memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 38444627Sjulian 38544165Sjulian /* 38644165Sjulian * If a simplex interface, and the packet is being sent to our 38744165Sjulian * Ethernet address or a broadcast address, loopback a copy. 38844165Sjulian * XXX To make a simplex device behave exactly like a duplex 38944165Sjulian * device, we should copy in the case of sending to our own 39044165Sjulian * ethernet address (thus letting the original actually appear 39144165Sjulian * on the wire). However, we don't do that here for security 39244165Sjulian * reasons and compatibility with the original behavior. 39344165Sjulian */ 39474408Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 39544165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 39674408Smdodd struct mbuf *n; 39774408Smdodd n = m_copy(m, 0, (int)M_COPYALL); 398112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 39974408Smdodd ISO88025_HDR_LEN); 400112279Smdodd } else if (bcmp(th->iso88025_dhost, th->iso88025_shost, 40174408Smdodd ETHER_ADDR_LEN) == 0) { 402112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 403112279Smdodd ISO88025_HDR_LEN); 404112279Smdodd return(0); /* XXX */ 405112279Smdodd } 40644165Sjulian } 40744165Sjulian 408111790Smdodd if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN) ) { 40969152Sjlemon printf("iso88025_output: packet dropped QFULL.\n"); 41044165Sjulian senderr(ENOBUFS); 41144165Sjulian } 41244165Sjulian return (error); 41344165Sjulian 41444165Sjulianbad: 415112296Smdodd ifp->if_oerrors++; 41644165Sjulian if (m) 41744165Sjulian m_freem(m); 41844165Sjulian return (error); 41944165Sjulian} 42044165Sjulian 42144165Sjulian/* 42244165Sjulian * ISO 88025 de-encapsulation 42344165Sjulian */ 42444165Sjulianvoid 425112299Smdoddiso88025_input(ifp, m) 42674408Smdodd struct ifnet *ifp; 42774408Smdodd struct mbuf *m; 42844165Sjulian{ 429112299Smdodd struct iso88025_header *th; 430112299Smdodd struct llc *l; 431111888Sjlemon int isr; 432112299Smdodd int mac_hdr_len; 43344165Sjulian 434112308Smdodd /* 435112308Smdodd * Do consistency checks to verify assumptions 436112308Smdodd * made by code past this point. 437112308Smdodd */ 438112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 439112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 440112308Smdodd ifp->if_ierrors++; 441112308Smdodd m_freem(m); 442112308Smdodd return; 443112308Smdodd } 444112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 445112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 446112308Smdodd ifp->if_ierrors++; 447112308Smdodd m_freem(m); 448112308Smdodd return; 449112308Smdodd } 450112308Smdodd 451112299Smdodd m = m_pullup(m, ISO88025_HDR_LEN); 452112299Smdodd if (m == NULL) { 453112299Smdodd ifp->if_ierrors++; 454112299Smdodd goto dropanyway; 455112299Smdodd } 456112299Smdodd th = mtod(m, struct iso88025_header *); 457112299Smdodd m->m_pkthdr.header = (void *)th; 458112299Smdodd 459112286Smdodd /* 460112286Smdodd * Discard packet if interface is not up. 461112286Smdodd */ 462112286Smdodd if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 463112286Smdodd goto dropanyway; 46444165Sjulian 465112308Smdodd /* 466112308Smdodd * Give bpf a chance at the packet. 467112308Smdodd */ 468112308Smdodd BPF_MTAP(ifp, m); 469112308Smdodd 470112308Smdodd /* 471112308Smdodd * Interface marked for monitoring; discard packet. 472112308Smdodd */ 473112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 474112308Smdodd m_freem(m); 475112308Smdodd return; 476112308Smdodd } 477112308Smdodd 478112285Smdodd#ifdef MAC 479112285Smdodd mac_create_mbuf_from_ifnet(ifp, m); 480112285Smdodd#endif 481112285Smdodd 482112286Smdodd /* 483112286Smdodd * Update interface statistics. 484112286Smdodd */ 485112299Smdodd ifp->if_ibytes += m->m_pkthdr.len; 48674408Smdodd getmicrotime(&ifp->if_lastchange); 48758313Slile 488112280Smdodd /* 489112286Smdodd * Discard non local unicast packets when interface 490112286Smdodd * is in promiscuous mode. 491112286Smdodd */ 492112286Smdodd if ((ifp->if_flags & IFF_PROMISC) && 493112286Smdodd ((th->iso88025_dhost[0] & 1) == 0) && 494112286Smdodd (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t) th->iso88025_dhost, 495112286Smdodd ISO88025_ADDR_LEN) != 0)) 496112286Smdodd goto dropanyway; 497112286Smdodd 498112286Smdodd /* 499112280Smdodd * Set mbuf flags for bcast/mcast. 500112280Smdodd */ 50144165Sjulian if (th->iso88025_dhost[0] & 1) { 502112277Smdodd if (bcmp((caddr_t)iso88025_broadcastaddr, 503112277Smdodd (caddr_t)th->iso88025_dhost, ISO88025_ADDR_LEN) == 0) 50444165Sjulian m->m_flags |= M_BCAST; 50544165Sjulian else 50644165Sjulian m->m_flags |= M_MCAST; 50774408Smdodd ifp->if_imcasts++; 508112274Smdodd } 50944165Sjulian 510112299Smdodd mac_hdr_len = ISO88025_HDR_LEN; 511112299Smdodd /* Check for source routing info */ 512112299Smdodd if (th->iso88025_shost[0] & TR_RII) 513112299Smdodd mac_hdr_len += TR_RCF_RIFLEN(th->rcf); 514112299Smdodd 515112299Smdodd /* Strip off ISO88025 header. */ 516112299Smdodd m_adj(m, mac_hdr_len); 517112299Smdodd 518112299Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 519112299Smdodd if (m == 0) { 520112299Smdodd ifp->if_ierrors++; 521112299Smdodd goto dropanyway; 522112299Smdodd } 52374408Smdodd l = mtod(m, struct llc *); 52444165Sjulian 52574408Smdodd switch (l->llc_dsap) { 52674408Smdodd#ifdef IPX 52774408Smdodd case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 52874408Smdodd if ((l->llc_control != LLC_UI) || 529112289Smdodd (l->llc_ssap != ETHERTYPE_IPX_8022)) { 530112289Smdodd ifp->if_noproto++; 53174408Smdodd goto dropanyway; 532112289Smdodd } 53374408Smdodd 53474408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 53574408Smdodd m_adj(m, 3); 536111888Sjlemon isr = NETISR_IPX; 53774408Smdodd break; 53874408Smdodd#endif /* IPX */ 53974408Smdodd case LLC_SNAP_LSAP: { 54074408Smdodd u_int16_t type; 54174408Smdodd if ((l->llc_control != LLC_UI) || 542112289Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 543112289Smdodd ifp->if_noproto++; 54474408Smdodd goto dropanyway; 545112289Smdodd } 54674408Smdodd 547112268Smdodd if (l->llc_snap.org_code[0] != 0 || 548112268Smdodd l->llc_snap.org_code[1] != 0 || 549112294Smdodd l->llc_snap.org_code[2] != 0) { 550112294Smdodd ifp->if_noproto++; 55174408Smdodd goto dropanyway; 552112294Smdodd } 55374408Smdodd 554112268Smdodd type = ntohs(l->llc_snap.ether_type); 555111790Smdodd m_adj(m, LLC_SNAPFRAMELEN); 55674408Smdodd switch (type) { 55744165Sjulian#ifdef INET 55874408Smdodd case ETHERTYPE_IP: 55974408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 56074408Smdodd if (ipflow_fastforward(m)) 56174408Smdodd return; 562111888Sjlemon isr = NETISR_IP; 56374408Smdodd break; 56474408Smdodd 56574408Smdodd case ETHERTYPE_ARP: 56678295Sjlemon if (ifp->if_flags & IFF_NOARP) 56778295Sjlemon goto dropanyway; 568111888Sjlemon isr = NETISR_ARP; 56974408Smdodd break; 57074408Smdodd#endif /* INET */ 57174408Smdodd#ifdef IPX_SNAP /* XXX: Not supported! */ 57274408Smdodd case ETHERTYPE_IPX: 57374408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 574111888Sjlemon isr = NETISR_IPX; 57574408Smdodd break; 57674408Smdodd#endif /* IPX_SNAP */ 57774408Smdodd#ifdef NOT_YET 57874408Smdodd#ifdef INET6 57974408Smdodd case ETHERTYPE_IPV6: 58074408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 581111888Sjlemon isr = NETISR_IPV6; 58274408Smdodd break; 58374408Smdodd#endif /* INET6 */ 58474408Smdodd#endif /* NOT_YET */ 58574408Smdodd default: 58674408Smdodd printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 587112289Smdodd ifp->if_noproto++; 588112289Smdodd goto dropanyway; 58974408Smdodd } 59044165Sjulian break; 59174408Smdodd } 592112296Smdodd#ifdef ISO 59374408Smdodd case LLC_ISO_LSAP: 59474408Smdodd switch (l->llc_control) { 59574408Smdodd case LLC_UI: 596112289Smdodd ifp->if_noproto++; 59774408Smdodd goto dropanyway; 59874408Smdodd break; 59974408Smdodd case LLC_XID: 60074408Smdodd case LLC_XID_P: 60174408Smdodd if(m->m_len < ISO88025_ADDR_LEN) 60274408Smdodd goto dropanyway; 60374408Smdodd l->llc_window = 0; 60474408Smdodd l->llc_fid = 9; 60574408Smdodd l->llc_class = 1; 60674408Smdodd l->llc_dsap = l->llc_ssap = 0; 60774408Smdodd /* Fall through to */ 60874408Smdodd case LLC_TEST: 60974408Smdodd case LLC_TEST_P: 61074408Smdodd { 61174408Smdodd struct sockaddr sa; 612112296Smdodd struct arpcom *ac; 61374408Smdodd struct iso88025_sockaddr_data *th2; 61474408Smdodd int i; 615112296Smdodd u_char c; 61644165Sjulian 617112308Smdodd ac = IFP2AC(ifp); 618112296Smdodd c = l->llc_dsap; 619112296Smdodd 62074408Smdodd if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 62174408Smdodd printf("iso88025_input: dropping source routed LLC_TEST\n"); 622112289Smdodd goto dropanyway; 62374408Smdodd } 62474408Smdodd l->llc_dsap = l->llc_ssap; 62574408Smdodd l->llc_ssap = c; 62674408Smdodd if (m->m_flags & (M_BCAST | M_MCAST)) 62774408Smdodd bcopy((caddr_t)ac->ac_enaddr, 628112280Smdodd (caddr_t)th->iso88025_dhost, 62974408Smdodd ISO88025_ADDR_LEN); 63074408Smdodd sa.sa_family = AF_UNSPEC; 63174408Smdodd sa.sa_len = sizeof(sa); 63274408Smdodd th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 63374408Smdodd for (i = 0; i < ISO88025_ADDR_LEN; i++) { 63474408Smdodd th2->ether_shost[i] = c = th->iso88025_dhost[i]; 63574408Smdodd th2->ether_dhost[i] = th->iso88025_dhost[i] = 63674408Smdodd th->iso88025_shost[i]; 63774408Smdodd th->iso88025_shost[i] = c; 63874408Smdodd } 63974408Smdodd th2->ac = TR_AC; 64074408Smdodd th2->fc = TR_LLC_FRAME; 64174408Smdodd ifp->if_output(ifp, m, &sa, NULL); 64274408Smdodd return; 64374408Smdodd } 64474408Smdodd default: 64574408Smdodd printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 646112289Smdodd ifp->if_noproto++; 647112289Smdodd goto dropanyway; 648112294Smdodd break; 64974408Smdodd } 65074408Smdodd break; 651112296Smdodd#endif /* ISO */ 65244165Sjulian default: 65374408Smdodd printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 65474408Smdodd ifp->if_noproto++; 655112289Smdodd goto dropanyway; 656112294Smdodd break; 65744165Sjulian } 658112274Smdodd 659111888Sjlemon netisr_dispatch(isr, m); 660112274Smdodd return; 661112289Smdodd 662112289Smdodddropanyway: 663112289Smdodd ifp->if_iqdrops++; 664112289Smdodd if (m) 665112289Smdodd m_freem(m); 666112289Smdodd return; 66744165Sjulian} 668112269Smdodd 669112273Smdoddstatic int 670112273Smdoddiso88025_resolvemulti (ifp, llsa, sa) 671112273Smdodd struct ifnet *ifp; 672112273Smdodd struct sockaddr **llsa; 673112273Smdodd struct sockaddr *sa; 674112273Smdodd{ 675112273Smdodd struct sockaddr_dl *sdl; 676112273Smdodd struct sockaddr_in *sin; 677112273Smdodd#ifdef INET6 678112273Smdodd struct sockaddr_in6 *sin6; 679112273Smdodd#endif 680112273Smdodd u_char *e_addr; 681112273Smdodd 682112273Smdodd switch(sa->sa_family) { 683112273Smdodd case AF_LINK: 684112273Smdodd /* 685112273Smdodd * No mapping needed. Just check that it's a valid MC address. 686112273Smdodd */ 687112273Smdodd sdl = (struct sockaddr_dl *)sa; 688112273Smdodd e_addr = LLADDR(sdl); 689112273Smdodd if ((e_addr[0] & 1) != 1) { 690112273Smdodd return (EADDRNOTAVAIL); 691112273Smdodd } 692112273Smdodd *llsa = 0; 693112273Smdodd return (0); 694112273Smdodd 695112273Smdodd#ifdef INET 696112273Smdodd case AF_INET: 697112273Smdodd sin = (struct sockaddr_in *)sa; 698112273Smdodd if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 699112273Smdodd return (EADDRNOTAVAIL); 700112273Smdodd } 701112273Smdodd MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 702112273Smdodd M_WAITOK|M_ZERO); 703112273Smdodd sdl->sdl_len = sizeof *sdl; 704112273Smdodd sdl->sdl_family = AF_LINK; 705112273Smdodd sdl->sdl_index = ifp->if_index; 706112273Smdodd sdl->sdl_type = IFT_ISO88025; 707112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 708112273Smdodd e_addr = LLADDR(sdl); 709112273Smdodd ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 710112273Smdodd *llsa = (struct sockaddr *)sdl; 711112273Smdodd return (0); 712112273Smdodd#endif 713112273Smdodd#ifdef INET6 714112273Smdodd case AF_INET6: 715112273Smdodd sin6 = (struct sockaddr_in6 *)sa; 716112273Smdodd if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 717112273Smdodd /* 718112273Smdodd * An IP6 address of 0 means listen to all 719112273Smdodd * of the Ethernet multicast address used for IP6. 720112273Smdodd * (This is used for multicast routers.) 721112273Smdodd */ 722112273Smdodd ifp->if_flags |= IFF_ALLMULTI; 723112273Smdodd *llsa = 0; 724112273Smdodd return (0); 725112273Smdodd } 726112273Smdodd if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 727112273Smdodd return (EADDRNOTAVAIL); 728112273Smdodd } 729112273Smdodd MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 730112273Smdodd M_WAITOK|M_ZERO); 731112273Smdodd sdl->sdl_len = sizeof *sdl; 732112273Smdodd sdl->sdl_family = AF_LINK; 733112273Smdodd sdl->sdl_index = ifp->if_index; 734112273Smdodd sdl->sdl_type = IFT_ISO88025; 735112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 736112273Smdodd e_addr = LLADDR(sdl); 737112273Smdodd ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 738112273Smdodd *llsa = (struct sockaddr *)sdl; 739112273Smdodd return (0); 740112273Smdodd#endif 741112273Smdodd 742112273Smdodd default: 743112273Smdodd /* 744112273Smdodd * Well, the text isn't quite right, but it's the name 745112273Smdodd * that counts... 746112273Smdodd */ 747112273Smdodd return (EAFNOSUPPORT); 748112273Smdodd } 749112273Smdodd 750112273Smdodd return (0); 751112273Smdodd} 752112273Smdodd 753112269Smdoddstatic moduledata_t iso88025_mod = { 754112269Smdodd "iso88025", 755112269Smdodd NULL, 756112269Smdodd 0 757112269Smdodd}; 758112269Smdodd 759112269SmdoddDECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 760112269SmdoddMODULE_VERSION(iso88025, 1); 761