if_iso88025subr.c revision 295896
1139823Simp/*- 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: stable/10/sys/net/if_iso88025subr.c 295896 2016-02-22 19:17:59Z gnn $ 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> 57184710Sbz#include <net/if_arp.h> 58112271Smdodd#include <net/if_dl.h> 5944165Sjulian#include <net/if_llc.h> 6044165Sjulian#include <net/if_types.h> 61186119Sqingli#include <net/if_llatbl.h> 6244165Sjulian 63184710Sbz#include <net/ethernet.h> 64112271Smdodd#include <net/netisr.h> 65112271Smdodd#include <net/route.h> 66112271Smdodd#include <net/bpf.h> 6744165Sjulian#include <net/iso88025.h> 6844165Sjulian 6974408Smdodd#if defined(INET) || defined(INET6) 7044165Sjulian#include <netinet/in.h> 7144165Sjulian#include <netinet/in_var.h> 7244165Sjulian#include <netinet/if_ether.h> 7344165Sjulian#endif 7474408Smdodd#ifdef INET6 7574408Smdodd#include <netinet6/nd6.h> 7674408Smdodd#endif 7744165Sjulian 7874408Smdodd#ifdef IPX 7974408Smdodd#include <netipx/ipx.h> 8074408Smdodd#include <netipx/ipx_if.h> 8174408Smdodd#endif 8274408Smdodd 83163606Srwatson#include <security/mac/mac_framework.h> 84163606Srwatson 85126907Srwatsonstatic const u_char iso88025_broadcastaddr[ISO88025_ADDR_LEN] = 86112277Smdodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 87112277Smdodd 88112273Smdoddstatic int iso88025_resolvemulti (struct ifnet *, struct sockaddr **, 89112294Smdodd struct sockaddr *); 90112273Smdodd 91112276Smdodd#define senderr(e) do { error = (e); goto bad; } while (0) 9274408Smdodd 93112297Smdodd/* 94112297Smdodd * Perform common duties while attaching to interface list 95112297Smdodd */ 9644165Sjulianvoid 97152296Sruiso88025_ifattach(struct ifnet *ifp, const u_int8_t *lla, int bpf) 9844165Sjulian{ 99112296Smdodd struct ifaddr *ifa; 100111774Smdodd struct sockaddr_dl *sdl; 10144165Sjulian 102112296Smdodd ifa = NULL; 103112296Smdodd 10444165Sjulian ifp->if_type = IFT_ISO88025; 10558313Slile ifp->if_addrlen = ISO88025_ADDR_LEN; 10658313Slile ifp->if_hdrlen = ISO88025_HDR_LEN; 107112297Smdodd 108112297Smdodd if_attach(ifp); /* Must be called before additional assignments */ 109112297Smdodd 110112297Smdodd ifp->if_output = iso88025_output; 111112297Smdodd ifp->if_input = iso88025_input; 112112297Smdodd ifp->if_resolvemulti = iso88025_resolvemulti; 113112297Smdodd ifp->if_broadcastaddr = iso88025_broadcastaddr; 114112297Smdodd 11544165Sjulian if (ifp->if_baudrate == 0) 11658313Slile ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */ 11744165Sjulian if (ifp->if_mtu == 0) 11844165Sjulian ifp->if_mtu = ISO88025_DEFAULT_MTU; 11944165Sjulian 120152315Sru ifa = ifp->if_addr; 121152315Sru KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 122112297Smdodd 123112272Smdodd sdl = (struct sockaddr_dl *)ifa->ifa_addr; 124112272Smdodd sdl->sdl_type = IFT_ISO88025; 125112272Smdodd sdl->sdl_alen = ifp->if_addrlen; 126152296Sru bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 127112297Smdodd 128112297Smdodd if (bpf) 129112297Smdodd bpfattach(ifp, DLT_IEEE802, ISO88025_HDR_LEN); 130112297Smdodd 131112297Smdodd return; 13244165Sjulian} 13344165Sjulian 13474408Smdodd/* 13574408Smdodd * Perform common duties while detaching a Token Ring interface 13674408Smdodd */ 13774408Smdoddvoid 13874408Smdoddiso88025_ifdetach(ifp, bpf) 13974408Smdodd struct ifnet *ifp; 14074408Smdodd int bpf; 14174408Smdodd{ 142112274Smdodd 14374408Smdodd if (bpf) 14474408Smdodd bpfdetach(ifp); 145112274Smdodd 14674408Smdodd if_detach(ifp); 147112274Smdodd 148112274Smdodd return; 14974408Smdodd} 15074408Smdodd 15144165Sjulianint 152194581Srdivackyiso88025_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 15344165Sjulian{ 154112274Smdodd struct ifaddr *ifa; 155112274Smdodd struct ifreq *ifr; 156112274Smdodd int error; 15744165Sjulian 158112274Smdodd ifa = (struct ifaddr *) data; 159112274Smdodd ifr = (struct ifreq *) data; 160112274Smdodd error = 0; 161112274Smdodd 16244165Sjulian switch (command) { 16344165Sjulian case SIOCSIFADDR: 16444165Sjulian ifp->if_flags |= IFF_UP; 16544165Sjulian 16644165Sjulian switch (ifa->ifa_addr->sa_family) { 16744165Sjulian#ifdef INET 16844165Sjulian case AF_INET: 16944165Sjulian ifp->if_init(ifp->if_softc); /* before arpwhohas */ 17084931Sfjoe arp_ifinit(ifp, ifa); 17144165Sjulian break; 17274408Smdodd#endif /* INET */ 17374408Smdodd#ifdef IPX 17474408Smdodd /* 17574408Smdodd * XXX - This code is probably wrong 17674408Smdodd */ 177120048Smdodd case AF_IPX: { 178120048Smdodd struct ipx_addr *ina; 17974408Smdodd 180120048Smdodd ina = &(IA_SIPX(ifa)->sipx_addr); 18174408Smdodd 182120048Smdodd if (ipx_nullhost(*ina)) 183120048Smdodd ina->x_host = *(union ipx_host *) 184152315Sru IF_LLADDR(ifp); 185120048Smdodd else 186120048Smdodd bcopy((caddr_t) ina->x_host.c_host, 187152315Sru (caddr_t) IF_LLADDR(ifp), 188120048Smdodd ISO88025_ADDR_LEN); 189120048Smdodd 190120048Smdodd /* 191120048Smdodd * Set new address 192120048Smdodd */ 193120048Smdodd ifp->if_init(ifp->if_softc); 194120048Smdodd } 195120048Smdodd break; 19674408Smdodd#endif /* IPX */ 19744165Sjulian default: 19844165Sjulian ifp->if_init(ifp->if_softc); 19944165Sjulian break; 20044165Sjulian } 20144165Sjulian break; 20244165Sjulian 203120047Smdodd case SIOCGIFADDR: { 20444165Sjulian struct sockaddr *sa; 20544165Sjulian 20644165Sjulian sa = (struct sockaddr *) & ifr->ifr_data; 207152315Sru bcopy(IF_LLADDR(ifp), 20844165Sjulian (caddr_t) sa->sa_data, ISO88025_ADDR_LEN); 20944165Sjulian } 21044165Sjulian break; 21144165Sjulian 21244165Sjulian case SIOCSIFMTU: 21344165Sjulian /* 21444165Sjulian * Set the interface MTU. 21544165Sjulian */ 21658313Slile if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 21744165Sjulian error = EINVAL; 21844165Sjulian } else { 21944165Sjulian ifp->if_mtu = ifr->ifr_mtu; 22044165Sjulian } 22144165Sjulian break; 222112274Smdodd default: 223112274Smdodd error = EINVAL; /* XXX netbsd has ENOTTY??? */ 224112274Smdodd break; 22544165Sjulian } 226112274Smdodd 22744165Sjulian return (error); 22844165Sjulian} 22944165Sjulian 23044165Sjulian/* 23144165Sjulian * ISO88025 encapsulation 23244165Sjulian */ 23344165Sjulianint 234249925Sglebiusiso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 235249925Sglebius struct route *ro) 23644165Sjulian{ 23774408Smdodd u_int16_t snap_type = 0; 23887914Sjlemon int loop_copy = 0, error = 0, rif_len = 0; 23987914Sjlemon u_char edst[ISO88025_ADDR_LEN]; 24074408Smdodd struct iso88025_header *th; 24144627Sjulian struct iso88025_header gen_th; 24274408Smdodd struct sockaddr_dl *sdl = NULL; 243193891Sbz struct rtentry *rt0 = NULL; 244193891Sbz#if defined(INET) || defined(INET6) 245186119Sqingli struct llentry *lle; 246193891Sbz#endif 24744165Sjulian 248191148Skmacy if (ro != NULL) 249191148Skmacy rt0 = ro->ro_rt; 250191148Skmacy 251112285Smdodd#ifdef MAC 252172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 253112285Smdodd if (error) 254112285Smdodd senderr(error); 255112285Smdodd#endif 256112285Smdodd 257112308Smdodd if (ifp->if_flags & IFF_MONITOR) 258112308Smdodd senderr(ENETDOWN); 259148887Srwatson if (!((ifp->if_flags & IFF_UP) && 260148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 26144165Sjulian senderr(ENETDOWN); 26274408Smdodd getmicrotime(&ifp->if_lastchange); 26374408Smdodd 264128636Sluigi /* Calculate routing info length based on arp table entry */ 265128636Sluigi /* XXX any better way to do this ? */ 26644627Sjulian 267186119Sqingli if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway)) 268102291Sarchie if (SDL_ISO88025(sdl)->trld_rcf != 0) 26996184Skbyanc rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 27044627Sjulian 27144627Sjulian /* Generate a generic 802.5 header for the packet */ 27258313Slile gen_th.ac = TR_AC; 27358313Slile gen_th.fc = TR_LLC_FRAME; 274152315Sru (void)memcpy((caddr_t)gen_th.iso88025_shost, IF_LLADDR(ifp), 275112278Smdodd ISO88025_ADDR_LEN); 27644627Sjulian if (rif_len) { 27758313Slile gen_th.iso88025_shost[0] |= TR_RII; 27844627Sjulian if (rif_len > 2) { 27996184Skbyanc gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 28074408Smdodd (void)memcpy((caddr_t)gen_th.rd, 28196184Skbyanc (caddr_t)SDL_ISO88025(sdl)->trld_route, 28296184Skbyanc rif_len - 2); 28344627Sjulian } 28444627Sjulian } 28544627Sjulian 28644165Sjulian switch (dst->sa_family) { 28744165Sjulian#ifdef INET 28844165Sjulian case AF_INET: 289186119Sqingli error = arpresolve(ifp, rt0, m, dst, edst, &lle); 290128636Sluigi if (error) 291128636Sluigi return (error == EWOULDBLOCK ? 0 : error); 29274408Smdodd snap_type = ETHERTYPE_IP; 29374408Smdodd break; 294126951Smdodd case AF_ARP: 295126951Smdodd { 296126951Smdodd struct arphdr *ah; 297126951Smdodd ah = mtod(m, struct arphdr *); 298126951Smdodd ah->ar_hrd = htons(ARPHRD_IEEE802); 299126951Smdodd 300126951Smdodd loop_copy = -1; /* if this is for us, don't do it */ 301126951Smdodd 302126951Smdodd switch(ntohs(ah->ar_op)) { 303126951Smdodd case ARPOP_REVREQUEST: 304126951Smdodd case ARPOP_REVREPLY: 305126951Smdodd snap_type = ETHERTYPE_REVARP; 306126951Smdodd break; 307126951Smdodd case ARPOP_REQUEST: 308126951Smdodd case ARPOP_REPLY: 309126951Smdodd default: 310126951Smdodd snap_type = ETHERTYPE_ARP; 311126951Smdodd break; 312126951Smdodd } 313126951Smdodd 314126951Smdodd if (m->m_flags & M_BCAST) 315126951Smdodd bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN); 316126951Smdodd else 317126951Smdodd bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN); 318126951Smdodd 319126951Smdodd } 320126951Smdodd break; 32174408Smdodd#endif /* INET */ 32274408Smdodd#ifdef INET6 32374408Smdodd case AF_INET6: 324186217Sqingli error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); 325128636Sluigi if (error) 326128636Sluigi return (error); 32774408Smdodd snap_type = ETHERTYPE_IPV6; 32874408Smdodd break; 32974408Smdodd#endif /* INET6 */ 33074408Smdodd#ifdef IPX 33174408Smdodd case AF_IPX: 33274408Smdodd { 33374408Smdodd u_int8_t *cp; 33474408Smdodd 33574408Smdodd bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 336112278Smdodd ISO88025_ADDR_LEN); 33774408Smdodd 338243882Sglebius M_PREPEND(m, 3, M_WAITOK); 33974408Smdodd m = m_pullup(m, 3); 34074408Smdodd if (m == 0) 34174408Smdodd senderr(ENOBUFS); 34274408Smdodd cp = mtod(m, u_int8_t *); 34374408Smdodd *cp++ = ETHERTYPE_IPX_8022; 34474408Smdodd *cp++ = ETHERTYPE_IPX_8022; 34574408Smdodd *cp++ = LLC_UI; 34674408Smdodd } 34774408Smdodd break; 34874408Smdodd#endif /* IPX */ 34944165Sjulian case AF_UNSPEC: 35074408Smdodd { 351249925Sglebius const struct iso88025_sockaddr_data *sd; 35244627Sjulian /* 35344627Sjulian * For AF_UNSPEC sockaddr.sa_data must contain all of the 35444627Sjulian * mac information needed to send the packet. This allows 35544627Sjulian * full mac, llc, and source routing function to be controlled. 35644627Sjulian * llc and source routing information must already be in the 35744627Sjulian * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 358108533Sschweikh * should be an iso88025_sockaddr_data structure see iso88025.h 35944627Sjulian */ 36044165Sjulian loop_copy = -1; 361249925Sglebius sd = (const struct iso88025_sockaddr_data *)dst->sa_data; 36244627Sjulian gen_th.ac = sd->ac; 36344627Sjulian gen_th.fc = sd->fc; 364249925Sglebius (void)memcpy(edst, sd->ether_dhost, ISO88025_ADDR_LEN); 365249925Sglebius (void)memcpy(gen_th.iso88025_shost, sd->ether_shost, 366249925Sglebius ISO88025_ADDR_LEN); 36744627Sjulian rif_len = 0; 36844165Sjulian break; 36974408Smdodd } 37044165Sjulian default: 371105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 37244165Sjulian senderr(EAFNOSUPPORT); 37374408Smdodd break; 37444165Sjulian } 37544165Sjulian 376112274Smdodd /* 377112274Smdodd * Add LLC header. 378112274Smdodd */ 37974408Smdodd if (snap_type != 0) { 38074408Smdodd struct llc *l; 381243882Sglebius M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT); 38274408Smdodd if (m == 0) 38374408Smdodd senderr(ENOBUFS); 38474408Smdodd l = mtod(m, struct llc *); 385112281Smdodd l->llc_control = LLC_UI; 38674408Smdodd l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 387112268Smdodd l->llc_snap.org_code[0] = 388112268Smdodd l->llc_snap.org_code[1] = 389112268Smdodd l->llc_snap.org_code[2] = 0; 390112274Smdodd l->llc_snap.ether_type = htons(snap_type); 39174408Smdodd } 39274408Smdodd 39344165Sjulian /* 39444165Sjulian * Add local net header. If no space in first mbuf, 39544165Sjulian * allocate another. 39644165Sjulian */ 397243882Sglebius M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_NOWAIT); 39844165Sjulian if (m == 0) 39944165Sjulian senderr(ENOBUFS); 400112274Smdodd th = mtod(m, struct iso88025_header *); 401112291Smdodd bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN); 40244627Sjulian 40344627Sjulian /* Copy as much of the generic header as is needed into the mbuf */ 40444627Sjulian memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 40544627Sjulian 40644165Sjulian /* 40744165Sjulian * If a simplex interface, and the packet is being sent to our 40844165Sjulian * Ethernet address or a broadcast address, loopback a copy. 40944165Sjulian * XXX To make a simplex device behave exactly like a duplex 41044165Sjulian * device, we should copy in the case of sending to our own 41144165Sjulian * ethernet address (thus letting the original actually appear 41244165Sjulian * on the wire). However, we don't do that here for security 41344165Sjulian * reasons and compatibility with the original behavior. 41444165Sjulian */ 41574408Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 41644165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 41774408Smdodd struct mbuf *n; 41874408Smdodd n = m_copy(m, 0, (int)M_COPYALL); 419112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 42074408Smdodd ISO88025_HDR_LEN); 421112279Smdodd } else if (bcmp(th->iso88025_dhost, th->iso88025_shost, 42274408Smdodd ETHER_ADDR_LEN) == 0) { 423112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 424112279Smdodd ISO88025_HDR_LEN); 425112279Smdodd return(0); /* XXX */ 426112279Smdodd } 42744165Sjulian } 42844165Sjulian 429130549Smlaier IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error); 430130549Smlaier if (error) { 43169152Sjlemon printf("iso88025_output: packet dropped QFULL.\n"); 432130549Smlaier ifp->if_oerrors++; 43344165Sjulian } 43444165Sjulian return (error); 43544165Sjulian 43644165Sjulianbad: 437112296Smdodd ifp->if_oerrors++; 43844165Sjulian if (m) 43944165Sjulian m_freem(m); 44044165Sjulian return (error); 44144165Sjulian} 44244165Sjulian 44344165Sjulian/* 44444165Sjulian * ISO 88025 de-encapsulation 44544165Sjulian */ 44644165Sjulianvoid 447112299Smdoddiso88025_input(ifp, m) 44874408Smdodd struct ifnet *ifp; 44974408Smdodd struct mbuf *m; 45044165Sjulian{ 451112299Smdodd struct iso88025_header *th; 452112299Smdodd struct llc *l; 453111888Sjlemon int isr; 454112299Smdodd int mac_hdr_len; 45544165Sjulian 456112308Smdodd /* 457112308Smdodd * Do consistency checks to verify assumptions 458112308Smdodd * made by code past this point. 459112308Smdodd */ 460112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 461112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 462112308Smdodd ifp->if_ierrors++; 463112308Smdodd m_freem(m); 464112308Smdodd return; 465112308Smdodd } 466112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 467112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 468112308Smdodd ifp->if_ierrors++; 469112308Smdodd m_freem(m); 470112308Smdodd return; 471112308Smdodd } 472112308Smdodd 473112299Smdodd m = m_pullup(m, ISO88025_HDR_LEN); 474112299Smdodd if (m == NULL) { 475112299Smdodd ifp->if_ierrors++; 476112299Smdodd goto dropanyway; 477112299Smdodd } 478112299Smdodd th = mtod(m, struct iso88025_header *); 479112299Smdodd 480112286Smdodd /* 481112286Smdodd * Discard packet if interface is not up. 482112286Smdodd */ 483148887Srwatson if (!((ifp->if_flags & IFF_UP) && 484148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 485112286Smdodd goto dropanyway; 48644165Sjulian 487112308Smdodd /* 488112308Smdodd * Give bpf a chance at the packet. 489112308Smdodd */ 490112308Smdodd BPF_MTAP(ifp, m); 491112308Smdodd 492112308Smdodd /* 493112308Smdodd * Interface marked for monitoring; discard packet. 494112308Smdodd */ 495112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 496112308Smdodd m_freem(m); 497112308Smdodd return; 498112308Smdodd } 499112308Smdodd 500112285Smdodd#ifdef MAC 501172930Srwatson mac_ifnet_create_mbuf(ifp, m); 502112285Smdodd#endif 503112285Smdodd 504112286Smdodd /* 505112286Smdodd * Update interface statistics. 506112286Smdodd */ 507112299Smdodd ifp->if_ibytes += m->m_pkthdr.len; 50874408Smdodd getmicrotime(&ifp->if_lastchange); 50958313Slile 510112280Smdodd /* 511112286Smdodd * Discard non local unicast packets when interface 512112286Smdodd * is in promiscuous mode. 513112286Smdodd */ 514112286Smdodd if ((ifp->if_flags & IFF_PROMISC) && 515112286Smdodd ((th->iso88025_dhost[0] & 1) == 0) && 516152315Sru (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost, 517112286Smdodd ISO88025_ADDR_LEN) != 0)) 518112286Smdodd goto dropanyway; 519112286Smdodd 520112286Smdodd /* 521112280Smdodd * Set mbuf flags for bcast/mcast. 522112280Smdodd */ 52344165Sjulian if (th->iso88025_dhost[0] & 1) { 524126907Srwatson if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost, 525126907Srwatson ISO88025_ADDR_LEN) == 0) 52644165Sjulian m->m_flags |= M_BCAST; 52744165Sjulian else 52844165Sjulian m->m_flags |= M_MCAST; 52974408Smdodd ifp->if_imcasts++; 530112274Smdodd } 53144165Sjulian 532112299Smdodd mac_hdr_len = ISO88025_HDR_LEN; 533112299Smdodd /* Check for source routing info */ 534112299Smdodd if (th->iso88025_shost[0] & TR_RII) 535112299Smdodd mac_hdr_len += TR_RCF_RIFLEN(th->rcf); 536112299Smdodd 537112299Smdodd /* Strip off ISO88025 header. */ 538112299Smdodd m_adj(m, mac_hdr_len); 539112299Smdodd 540112299Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 541112299Smdodd if (m == 0) { 542112299Smdodd ifp->if_ierrors++; 543112299Smdodd goto dropanyway; 544112299Smdodd } 54574408Smdodd l = mtod(m, struct llc *); 54644165Sjulian 54774408Smdodd switch (l->llc_dsap) { 54874408Smdodd#ifdef IPX 54974408Smdodd case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 55074408Smdodd if ((l->llc_control != LLC_UI) || 551112289Smdodd (l->llc_ssap != ETHERTYPE_IPX_8022)) { 552112289Smdodd ifp->if_noproto++; 55374408Smdodd goto dropanyway; 554112289Smdodd } 55574408Smdodd 55674408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 55774408Smdodd m_adj(m, 3); 558111888Sjlemon isr = NETISR_IPX; 55974408Smdodd break; 56074408Smdodd#endif /* IPX */ 56174408Smdodd case LLC_SNAP_LSAP: { 56274408Smdodd u_int16_t type; 56374408Smdodd if ((l->llc_control != LLC_UI) || 564112289Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 565112289Smdodd ifp->if_noproto++; 56674408Smdodd goto dropanyway; 567112289Smdodd } 56874408Smdodd 569112268Smdodd if (l->llc_snap.org_code[0] != 0 || 570112268Smdodd l->llc_snap.org_code[1] != 0 || 571112294Smdodd l->llc_snap.org_code[2] != 0) { 572112294Smdodd ifp->if_noproto++; 57374408Smdodd goto dropanyway; 574112294Smdodd } 57574408Smdodd 576112268Smdodd type = ntohs(l->llc_snap.ether_type); 577111790Smdodd m_adj(m, LLC_SNAPFRAMELEN); 57874408Smdodd switch (type) { 57944165Sjulian#ifdef INET 58074408Smdodd case ETHERTYPE_IP: 58174408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 582295896Sgnn if ((m = ip_fastforward(m)) == NULL) 583295896Sgnn return; 584111888Sjlemon isr = NETISR_IP; 58574408Smdodd break; 58674408Smdodd 58774408Smdodd case ETHERTYPE_ARP: 58878295Sjlemon if (ifp->if_flags & IFF_NOARP) 58978295Sjlemon goto dropanyway; 590111888Sjlemon isr = NETISR_ARP; 59174408Smdodd break; 59274408Smdodd#endif /* INET */ 59374408Smdodd#ifdef IPX_SNAP /* XXX: Not supported! */ 59474408Smdodd case ETHERTYPE_IPX: 59574408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 596111888Sjlemon isr = NETISR_IPX; 59774408Smdodd break; 59874408Smdodd#endif /* IPX_SNAP */ 59974408Smdodd#ifdef INET6 60074408Smdodd case ETHERTYPE_IPV6: 60174408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 602111888Sjlemon isr = NETISR_IPV6; 60374408Smdodd break; 60474408Smdodd#endif /* INET6 */ 60574408Smdodd default: 60674408Smdodd printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 607112289Smdodd ifp->if_noproto++; 608112289Smdodd goto dropanyway; 60974408Smdodd } 61044165Sjulian break; 61174408Smdodd } 612112296Smdodd#ifdef ISO 61374408Smdodd case LLC_ISO_LSAP: 61474408Smdodd switch (l->llc_control) { 61574408Smdodd case LLC_UI: 616112289Smdodd ifp->if_noproto++; 61774408Smdodd goto dropanyway; 61874408Smdodd break; 61974408Smdodd case LLC_XID: 62074408Smdodd case LLC_XID_P: 62174408Smdodd if(m->m_len < ISO88025_ADDR_LEN) 62274408Smdodd goto dropanyway; 62374408Smdodd l->llc_window = 0; 62474408Smdodd l->llc_fid = 9; 62574408Smdodd l->llc_class = 1; 62674408Smdodd l->llc_dsap = l->llc_ssap = 0; 62774408Smdodd /* Fall through to */ 62874408Smdodd case LLC_TEST: 62974408Smdodd case LLC_TEST_P: 63074408Smdodd { 63174408Smdodd struct sockaddr sa; 632112296Smdodd struct arpcom *ac; 63374408Smdodd struct iso88025_sockaddr_data *th2; 63474408Smdodd int i; 635112296Smdodd u_char c; 63644165Sjulian 637112296Smdodd c = l->llc_dsap; 638112296Smdodd 63974408Smdodd if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 64074408Smdodd printf("iso88025_input: dropping source routed LLC_TEST\n"); 641112289Smdodd goto dropanyway; 64274408Smdodd } 64374408Smdodd l->llc_dsap = l->llc_ssap; 64474408Smdodd l->llc_ssap = c; 64574408Smdodd if (m->m_flags & (M_BCAST | M_MCAST)) 646152315Sru bcopy((caddr_t)IF_LLADDR(ifp), 647112280Smdodd (caddr_t)th->iso88025_dhost, 64874408Smdodd ISO88025_ADDR_LEN); 64974408Smdodd sa.sa_family = AF_UNSPEC; 65074408Smdodd sa.sa_len = sizeof(sa); 65174408Smdodd th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 65274408Smdodd for (i = 0; i < ISO88025_ADDR_LEN; i++) { 65374408Smdodd th2->ether_shost[i] = c = th->iso88025_dhost[i]; 65474408Smdodd th2->ether_dhost[i] = th->iso88025_dhost[i] = 65574408Smdodd th->iso88025_shost[i]; 65674408Smdodd th->iso88025_shost[i] = c; 65774408Smdodd } 65874408Smdodd th2->ac = TR_AC; 65974408Smdodd th2->fc = TR_LLC_FRAME; 66074408Smdodd ifp->if_output(ifp, m, &sa, NULL); 66174408Smdodd return; 66274408Smdodd } 66374408Smdodd default: 66474408Smdodd printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 665112289Smdodd ifp->if_noproto++; 666112289Smdodd goto dropanyway; 667112294Smdodd break; 66874408Smdodd } 66974408Smdodd break; 670112296Smdodd#endif /* ISO */ 67144165Sjulian default: 67274408Smdodd printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 67374408Smdodd ifp->if_noproto++; 674112289Smdodd goto dropanyway; 675112294Smdodd break; 67644165Sjulian } 677112274Smdodd 678223741Sbz M_SETFIB(m, ifp->if_fib); 679111888Sjlemon netisr_dispatch(isr, m); 680112274Smdodd return; 681112289Smdodd 682112289Smdodddropanyway: 683112289Smdodd ifp->if_iqdrops++; 684112289Smdodd if (m) 685112289Smdodd m_freem(m); 686112289Smdodd return; 68744165Sjulian} 688112269Smdodd 689112273Smdoddstatic int 690112273Smdoddiso88025_resolvemulti (ifp, llsa, sa) 691112273Smdodd struct ifnet *ifp; 692112273Smdodd struct sockaddr **llsa; 693112273Smdodd struct sockaddr *sa; 694112273Smdodd{ 695112273Smdodd struct sockaddr_dl *sdl; 696184710Sbz#ifdef INET 697112273Smdodd struct sockaddr_in *sin; 698184710Sbz#endif 699112273Smdodd#ifdef INET6 700112273Smdodd struct sockaddr_in6 *sin6; 701112273Smdodd#endif 702112273Smdodd u_char *e_addr; 703112273Smdodd 704112273Smdodd switch(sa->sa_family) { 705112273Smdodd case AF_LINK: 706112273Smdodd /* 707112273Smdodd * No mapping needed. Just check that it's a valid MC address. 708112273Smdodd */ 709112273Smdodd sdl = (struct sockaddr_dl *)sa; 710112273Smdodd e_addr = LLADDR(sdl); 711112273Smdodd if ((e_addr[0] & 1) != 1) { 712112273Smdodd return (EADDRNOTAVAIL); 713112273Smdodd } 714112273Smdodd *llsa = 0; 715112273Smdodd return (0); 716112273Smdodd 717112273Smdodd#ifdef INET 718112273Smdodd case AF_INET: 719112273Smdodd sin = (struct sockaddr_in *)sa; 720112273Smdodd if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 721112273Smdodd return (EADDRNOTAVAIL); 722112273Smdodd } 723184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 724148641Srwatson M_NOWAIT|M_ZERO); 725148641Srwatson if (sdl == NULL) 726148641Srwatson return (ENOMEM); 727112273Smdodd sdl->sdl_len = sizeof *sdl; 728112273Smdodd sdl->sdl_family = AF_LINK; 729112273Smdodd sdl->sdl_index = ifp->if_index; 730112273Smdodd sdl->sdl_type = IFT_ISO88025; 731112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 732112273Smdodd e_addr = LLADDR(sdl); 733112273Smdodd ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 734112273Smdodd *llsa = (struct sockaddr *)sdl; 735112273Smdodd return (0); 736112273Smdodd#endif 737112273Smdodd#ifdef INET6 738112273Smdodd case AF_INET6: 739112273Smdodd sin6 = (struct sockaddr_in6 *)sa; 740112273Smdodd if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 741112273Smdodd /* 742112273Smdodd * An IP6 address of 0 means listen to all 743112273Smdodd * of the Ethernet multicast address used for IP6. 744112273Smdodd * (This is used for multicast routers.) 745112273Smdodd */ 746112273Smdodd ifp->if_flags |= IFF_ALLMULTI; 747112273Smdodd *llsa = 0; 748112273Smdodd return (0); 749112273Smdodd } 750112273Smdodd if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 751112273Smdodd return (EADDRNOTAVAIL); 752112273Smdodd } 753184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 754148641Srwatson M_NOWAIT|M_ZERO); 755148641Srwatson if (sdl == NULL) 756148641Srwatson return (ENOMEM); 757112273Smdodd sdl->sdl_len = sizeof *sdl; 758112273Smdodd sdl->sdl_family = AF_LINK; 759112273Smdodd sdl->sdl_index = ifp->if_index; 760112273Smdodd sdl->sdl_type = IFT_ISO88025; 761112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 762112273Smdodd e_addr = LLADDR(sdl); 763112273Smdodd ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 764112273Smdodd *llsa = (struct sockaddr *)sdl; 765112273Smdodd return (0); 766112273Smdodd#endif 767112273Smdodd 768112273Smdodd default: 769112273Smdodd /* 770112273Smdodd * Well, the text isn't quite right, but it's the name 771112273Smdodd * that counts... 772112273Smdodd */ 773112273Smdodd return (EAFNOSUPPORT); 774112273Smdodd } 775112273Smdodd 776112273Smdodd return (0); 777112273Smdodd} 778112273Smdodd 779227293Sedstatic MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals"); 780147256Sbrooks 781147256Sbrooksstatic void* 782147256Sbrooksiso88025_alloc(u_char type, struct ifnet *ifp) 783147256Sbrooks{ 784147256Sbrooks struct arpcom *ac; 785147256Sbrooks 786147256Sbrooks ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO); 787147256Sbrooks ac->ac_ifp = ifp; 788147256Sbrooks 789147256Sbrooks return (ac); 790147256Sbrooks} 791147256Sbrooks 792147256Sbrooksstatic void 793147256Sbrooksiso88025_free(void *com, u_char type) 794147256Sbrooks{ 795147256Sbrooks 796147256Sbrooks free(com, M_ISO88025); 797147256Sbrooks} 798147256Sbrooks 799147256Sbrooksstatic int 800147256Sbrooksiso88025_modevent(module_t mod, int type, void *data) 801147256Sbrooks{ 802147256Sbrooks 803147256Sbrooks switch (type) { 804147256Sbrooks case MOD_LOAD: 805147256Sbrooks if_register_com_alloc(IFT_ISO88025, iso88025_alloc, 806147256Sbrooks iso88025_free); 807147256Sbrooks break; 808147256Sbrooks case MOD_UNLOAD: 809147256Sbrooks if_deregister_com_alloc(IFT_ISO88025); 810147256Sbrooks break; 811147256Sbrooks default: 812147256Sbrooks return EOPNOTSUPP; 813147256Sbrooks } 814147256Sbrooks 815147256Sbrooks return (0); 816147256Sbrooks} 817147256Sbrooks 818112269Smdoddstatic moduledata_t iso88025_mod = { 819112269Smdodd "iso88025", 820147256Sbrooks iso88025_modevent, 821241394Skevlo 0 822112269Smdodd}; 823112269Smdodd 824112269SmdoddDECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 825112269SmdoddMODULE_VERSION(iso88025, 1); 826