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 332160 2018-04-07 00:04:28Z brooks $ 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 203332160Sbrooks case SIOCGIFADDR: 204332160Sbrooks bcopy(IF_LLADDR(ifp), &ifr->ifr_addr.sa_data[0], 205332160Sbrooks ISO88025_ADDR_LEN); 20644165Sjulian break; 20744165Sjulian 20844165Sjulian case SIOCSIFMTU: 20944165Sjulian /* 21044165Sjulian * Set the interface MTU. 21144165Sjulian */ 21258313Slile if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 21344165Sjulian error = EINVAL; 21444165Sjulian } else { 21544165Sjulian ifp->if_mtu = ifr->ifr_mtu; 21644165Sjulian } 21744165Sjulian break; 218112274Smdodd default: 219112274Smdodd error = EINVAL; /* XXX netbsd has ENOTTY??? */ 220112274Smdodd break; 22144165Sjulian } 222112274Smdodd 22344165Sjulian return (error); 22444165Sjulian} 22544165Sjulian 22644165Sjulian/* 22744165Sjulian * ISO88025 encapsulation 22844165Sjulian */ 22944165Sjulianint 230249925Sglebiusiso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 231249925Sglebius struct route *ro) 23244165Sjulian{ 23374408Smdodd u_int16_t snap_type = 0; 23487914Sjlemon int loop_copy = 0, error = 0, rif_len = 0; 23587914Sjlemon u_char edst[ISO88025_ADDR_LEN]; 23674408Smdodd struct iso88025_header *th; 23744627Sjulian struct iso88025_header gen_th; 23874408Smdodd struct sockaddr_dl *sdl = NULL; 239193891Sbz struct rtentry *rt0 = NULL; 240193891Sbz#if defined(INET) || defined(INET6) 241186119Sqingli struct llentry *lle; 242193891Sbz#endif 24344165Sjulian 244191148Skmacy if (ro != NULL) 245191148Skmacy rt0 = ro->ro_rt; 246191148Skmacy 247112285Smdodd#ifdef MAC 248172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 249112285Smdodd if (error) 250112285Smdodd senderr(error); 251112285Smdodd#endif 252112285Smdodd 253112308Smdodd if (ifp->if_flags & IFF_MONITOR) 254112308Smdodd senderr(ENETDOWN); 255148887Srwatson if (!((ifp->if_flags & IFF_UP) && 256148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 25744165Sjulian senderr(ENETDOWN); 25874408Smdodd getmicrotime(&ifp->if_lastchange); 25974408Smdodd 260128636Sluigi /* Calculate routing info length based on arp table entry */ 261128636Sluigi /* XXX any better way to do this ? */ 26244627Sjulian 263186119Sqingli if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway)) 264102291Sarchie if (SDL_ISO88025(sdl)->trld_rcf != 0) 26596184Skbyanc rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 26644627Sjulian 26744627Sjulian /* Generate a generic 802.5 header for the packet */ 26858313Slile gen_th.ac = TR_AC; 26958313Slile gen_th.fc = TR_LLC_FRAME; 270152315Sru (void)memcpy((caddr_t)gen_th.iso88025_shost, IF_LLADDR(ifp), 271112278Smdodd ISO88025_ADDR_LEN); 27244627Sjulian if (rif_len) { 27358313Slile gen_th.iso88025_shost[0] |= TR_RII; 27444627Sjulian if (rif_len > 2) { 27596184Skbyanc gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 27674408Smdodd (void)memcpy((caddr_t)gen_th.rd, 27796184Skbyanc (caddr_t)SDL_ISO88025(sdl)->trld_route, 27896184Skbyanc rif_len - 2); 27944627Sjulian } 28044627Sjulian } 28144627Sjulian 28244165Sjulian switch (dst->sa_family) { 28344165Sjulian#ifdef INET 28444165Sjulian case AF_INET: 285186119Sqingli error = arpresolve(ifp, rt0, m, dst, edst, &lle); 286128636Sluigi if (error) 287128636Sluigi return (error == EWOULDBLOCK ? 0 : error); 28874408Smdodd snap_type = ETHERTYPE_IP; 28974408Smdodd break; 290126951Smdodd case AF_ARP: 291126951Smdodd { 292126951Smdodd struct arphdr *ah; 293126951Smdodd ah = mtod(m, struct arphdr *); 294126951Smdodd ah->ar_hrd = htons(ARPHRD_IEEE802); 295126951Smdodd 296126951Smdodd loop_copy = -1; /* if this is for us, don't do it */ 297126951Smdodd 298126951Smdodd switch(ntohs(ah->ar_op)) { 299126951Smdodd case ARPOP_REVREQUEST: 300126951Smdodd case ARPOP_REVREPLY: 301126951Smdodd snap_type = ETHERTYPE_REVARP; 302126951Smdodd break; 303126951Smdodd case ARPOP_REQUEST: 304126951Smdodd case ARPOP_REPLY: 305126951Smdodd default: 306126951Smdodd snap_type = ETHERTYPE_ARP; 307126951Smdodd break; 308126951Smdodd } 309126951Smdodd 310126951Smdodd if (m->m_flags & M_BCAST) 311126951Smdodd bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN); 312126951Smdodd else 313126951Smdodd bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN); 314126951Smdodd 315126951Smdodd } 316126951Smdodd break; 31774408Smdodd#endif /* INET */ 31874408Smdodd#ifdef INET6 31974408Smdodd case AF_INET6: 320186217Sqingli error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); 321128636Sluigi if (error) 322128636Sluigi return (error); 32374408Smdodd snap_type = ETHERTYPE_IPV6; 32474408Smdodd break; 32574408Smdodd#endif /* INET6 */ 32674408Smdodd#ifdef IPX 32774408Smdodd case AF_IPX: 32874408Smdodd { 32974408Smdodd u_int8_t *cp; 33074408Smdodd 33174408Smdodd bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 332112278Smdodd ISO88025_ADDR_LEN); 33374408Smdodd 334243882Sglebius M_PREPEND(m, 3, M_WAITOK); 33574408Smdodd m = m_pullup(m, 3); 33674408Smdodd if (m == 0) 33774408Smdodd senderr(ENOBUFS); 33874408Smdodd cp = mtod(m, u_int8_t *); 33974408Smdodd *cp++ = ETHERTYPE_IPX_8022; 34074408Smdodd *cp++ = ETHERTYPE_IPX_8022; 34174408Smdodd *cp++ = LLC_UI; 34274408Smdodd } 34374408Smdodd break; 34474408Smdodd#endif /* IPX */ 34544165Sjulian case AF_UNSPEC: 34674408Smdodd { 347249925Sglebius const struct iso88025_sockaddr_data *sd; 34844627Sjulian /* 34944627Sjulian * For AF_UNSPEC sockaddr.sa_data must contain all of the 35044627Sjulian * mac information needed to send the packet. This allows 35144627Sjulian * full mac, llc, and source routing function to be controlled. 35244627Sjulian * llc and source routing information must already be in the 35344627Sjulian * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 354108533Sschweikh * should be an iso88025_sockaddr_data structure see iso88025.h 35544627Sjulian */ 35644165Sjulian loop_copy = -1; 357249925Sglebius sd = (const struct iso88025_sockaddr_data *)dst->sa_data; 35844627Sjulian gen_th.ac = sd->ac; 35944627Sjulian gen_th.fc = sd->fc; 360249925Sglebius (void)memcpy(edst, sd->ether_dhost, ISO88025_ADDR_LEN); 361249925Sglebius (void)memcpy(gen_th.iso88025_shost, sd->ether_shost, 362249925Sglebius ISO88025_ADDR_LEN); 36344627Sjulian rif_len = 0; 36444165Sjulian break; 36574408Smdodd } 36644165Sjulian default: 367105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 36844165Sjulian senderr(EAFNOSUPPORT); 36974408Smdodd break; 37044165Sjulian } 37144165Sjulian 372112274Smdodd /* 373112274Smdodd * Add LLC header. 374112274Smdodd */ 37574408Smdodd if (snap_type != 0) { 37674408Smdodd struct llc *l; 377243882Sglebius M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT); 37874408Smdodd if (m == 0) 37974408Smdodd senderr(ENOBUFS); 38074408Smdodd l = mtod(m, struct llc *); 381112281Smdodd l->llc_control = LLC_UI; 38274408Smdodd l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 383112268Smdodd l->llc_snap.org_code[0] = 384112268Smdodd l->llc_snap.org_code[1] = 385112268Smdodd l->llc_snap.org_code[2] = 0; 386112274Smdodd l->llc_snap.ether_type = htons(snap_type); 38774408Smdodd } 38874408Smdodd 38944165Sjulian /* 39044165Sjulian * Add local net header. If no space in first mbuf, 39144165Sjulian * allocate another. 39244165Sjulian */ 393243882Sglebius M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_NOWAIT); 39444165Sjulian if (m == 0) 39544165Sjulian senderr(ENOBUFS); 396112274Smdodd th = mtod(m, struct iso88025_header *); 397112291Smdodd bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN); 39844627Sjulian 39944627Sjulian /* Copy as much of the generic header as is needed into the mbuf */ 40044627Sjulian memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 40144627Sjulian 40244165Sjulian /* 40344165Sjulian * If a simplex interface, and the packet is being sent to our 40444165Sjulian * Ethernet address or a broadcast address, loopback a copy. 40544165Sjulian * XXX To make a simplex device behave exactly like a duplex 40644165Sjulian * device, we should copy in the case of sending to our own 40744165Sjulian * ethernet address (thus letting the original actually appear 40844165Sjulian * on the wire). However, we don't do that here for security 40944165Sjulian * reasons and compatibility with the original behavior. 41044165Sjulian */ 41174408Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 41244165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 41374408Smdodd struct mbuf *n; 41474408Smdodd n = m_copy(m, 0, (int)M_COPYALL); 415112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 41674408Smdodd ISO88025_HDR_LEN); 417112279Smdodd } else if (bcmp(th->iso88025_dhost, th->iso88025_shost, 41874408Smdodd ETHER_ADDR_LEN) == 0) { 419112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 420112279Smdodd ISO88025_HDR_LEN); 421112279Smdodd return(0); /* XXX */ 422112279Smdodd } 42344165Sjulian } 42444165Sjulian 425130549Smlaier IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error); 426130549Smlaier if (error) { 42769152Sjlemon printf("iso88025_output: packet dropped QFULL.\n"); 428130549Smlaier ifp->if_oerrors++; 42944165Sjulian } 43044165Sjulian return (error); 43144165Sjulian 43244165Sjulianbad: 433112296Smdodd ifp->if_oerrors++; 43444165Sjulian if (m) 43544165Sjulian m_freem(m); 43644165Sjulian return (error); 43744165Sjulian} 43844165Sjulian 43944165Sjulian/* 44044165Sjulian * ISO 88025 de-encapsulation 44144165Sjulian */ 44244165Sjulianvoid 443112299Smdoddiso88025_input(ifp, m) 44474408Smdodd struct ifnet *ifp; 44574408Smdodd struct mbuf *m; 44644165Sjulian{ 447112299Smdodd struct iso88025_header *th; 448112299Smdodd struct llc *l; 449111888Sjlemon int isr; 450112299Smdodd int mac_hdr_len; 45144165Sjulian 452112308Smdodd /* 453112308Smdodd * Do consistency checks to verify assumptions 454112308Smdodd * made by code past this point. 455112308Smdodd */ 456112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 457112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 458112308Smdodd ifp->if_ierrors++; 459112308Smdodd m_freem(m); 460112308Smdodd return; 461112308Smdodd } 462112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 463112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 464112308Smdodd ifp->if_ierrors++; 465112308Smdodd m_freem(m); 466112308Smdodd return; 467112308Smdodd } 468112308Smdodd 469112299Smdodd m = m_pullup(m, ISO88025_HDR_LEN); 470112299Smdodd if (m == NULL) { 471112299Smdodd ifp->if_ierrors++; 472112299Smdodd goto dropanyway; 473112299Smdodd } 474112299Smdodd th = mtod(m, struct iso88025_header *); 475112299Smdodd 476112286Smdodd /* 477112286Smdodd * Discard packet if interface is not up. 478112286Smdodd */ 479148887Srwatson if (!((ifp->if_flags & IFF_UP) && 480148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 481112286Smdodd goto dropanyway; 48244165Sjulian 483112308Smdodd /* 484112308Smdodd * Give bpf a chance at the packet. 485112308Smdodd */ 486112308Smdodd BPF_MTAP(ifp, m); 487112308Smdodd 488112308Smdodd /* 489112308Smdodd * Interface marked for monitoring; discard packet. 490112308Smdodd */ 491112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 492112308Smdodd m_freem(m); 493112308Smdodd return; 494112308Smdodd } 495112308Smdodd 496112285Smdodd#ifdef MAC 497172930Srwatson mac_ifnet_create_mbuf(ifp, m); 498112285Smdodd#endif 499112285Smdodd 500112286Smdodd /* 501112286Smdodd * Update interface statistics. 502112286Smdodd */ 503112299Smdodd ifp->if_ibytes += m->m_pkthdr.len; 50474408Smdodd getmicrotime(&ifp->if_lastchange); 50558313Slile 506112280Smdodd /* 507112286Smdodd * Discard non local unicast packets when interface 508112286Smdodd * is in promiscuous mode. 509112286Smdodd */ 510112286Smdodd if ((ifp->if_flags & IFF_PROMISC) && 511112286Smdodd ((th->iso88025_dhost[0] & 1) == 0) && 512152315Sru (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost, 513112286Smdodd ISO88025_ADDR_LEN) != 0)) 514112286Smdodd goto dropanyway; 515112286Smdodd 516112286Smdodd /* 517112280Smdodd * Set mbuf flags for bcast/mcast. 518112280Smdodd */ 51944165Sjulian if (th->iso88025_dhost[0] & 1) { 520126907Srwatson if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost, 521126907Srwatson ISO88025_ADDR_LEN) == 0) 52244165Sjulian m->m_flags |= M_BCAST; 52344165Sjulian else 52444165Sjulian m->m_flags |= M_MCAST; 52574408Smdodd ifp->if_imcasts++; 526112274Smdodd } 52744165Sjulian 528112299Smdodd mac_hdr_len = ISO88025_HDR_LEN; 529112299Smdodd /* Check for source routing info */ 530112299Smdodd if (th->iso88025_shost[0] & TR_RII) 531112299Smdodd mac_hdr_len += TR_RCF_RIFLEN(th->rcf); 532112299Smdodd 533112299Smdodd /* Strip off ISO88025 header. */ 534112299Smdodd m_adj(m, mac_hdr_len); 535112299Smdodd 536112299Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 537112299Smdodd if (m == 0) { 538112299Smdodd ifp->if_ierrors++; 539112299Smdodd goto dropanyway; 540112299Smdodd } 54174408Smdodd l = mtod(m, struct llc *); 54244165Sjulian 54374408Smdodd switch (l->llc_dsap) { 54474408Smdodd#ifdef IPX 54574408Smdodd case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 54674408Smdodd if ((l->llc_control != LLC_UI) || 547112289Smdodd (l->llc_ssap != ETHERTYPE_IPX_8022)) { 548112289Smdodd ifp->if_noproto++; 54974408Smdodd goto dropanyway; 550112289Smdodd } 55174408Smdodd 55274408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 55374408Smdodd m_adj(m, 3); 554111888Sjlemon isr = NETISR_IPX; 55574408Smdodd break; 55674408Smdodd#endif /* IPX */ 55774408Smdodd case LLC_SNAP_LSAP: { 55874408Smdodd u_int16_t type; 55974408Smdodd if ((l->llc_control != LLC_UI) || 560112289Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 561112289Smdodd ifp->if_noproto++; 56274408Smdodd goto dropanyway; 563112289Smdodd } 56474408Smdodd 565112268Smdodd if (l->llc_snap.org_code[0] != 0 || 566112268Smdodd l->llc_snap.org_code[1] != 0 || 567112294Smdodd l->llc_snap.org_code[2] != 0) { 568112294Smdodd ifp->if_noproto++; 56974408Smdodd goto dropanyway; 570112294Smdodd } 57174408Smdodd 572112268Smdodd type = ntohs(l->llc_snap.ether_type); 573111790Smdodd m_adj(m, LLC_SNAPFRAMELEN); 57474408Smdodd switch (type) { 57544165Sjulian#ifdef INET 57674408Smdodd case ETHERTYPE_IP: 57774408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 578295896Sgnn if ((m = ip_fastforward(m)) == NULL) 579295896Sgnn return; 580111888Sjlemon isr = NETISR_IP; 58174408Smdodd break; 58274408Smdodd 58374408Smdodd case ETHERTYPE_ARP: 58478295Sjlemon if (ifp->if_flags & IFF_NOARP) 58578295Sjlemon goto dropanyway; 586111888Sjlemon isr = NETISR_ARP; 58774408Smdodd break; 58874408Smdodd#endif /* INET */ 58974408Smdodd#ifdef IPX_SNAP /* XXX: Not supported! */ 59074408Smdodd case ETHERTYPE_IPX: 59174408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 592111888Sjlemon isr = NETISR_IPX; 59374408Smdodd break; 59474408Smdodd#endif /* IPX_SNAP */ 59574408Smdodd#ifdef INET6 59674408Smdodd case ETHERTYPE_IPV6: 59774408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 598111888Sjlemon isr = NETISR_IPV6; 59974408Smdodd break; 60074408Smdodd#endif /* INET6 */ 60174408Smdodd default: 60274408Smdodd printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 603112289Smdodd ifp->if_noproto++; 604112289Smdodd goto dropanyway; 60574408Smdodd } 60644165Sjulian break; 60774408Smdodd } 608112296Smdodd#ifdef ISO 60974408Smdodd case LLC_ISO_LSAP: 61074408Smdodd switch (l->llc_control) { 61174408Smdodd case LLC_UI: 612112289Smdodd ifp->if_noproto++; 61374408Smdodd goto dropanyway; 61474408Smdodd break; 61574408Smdodd case LLC_XID: 61674408Smdodd case LLC_XID_P: 61774408Smdodd if(m->m_len < ISO88025_ADDR_LEN) 61874408Smdodd goto dropanyway; 61974408Smdodd l->llc_window = 0; 62074408Smdodd l->llc_fid = 9; 62174408Smdodd l->llc_class = 1; 62274408Smdodd l->llc_dsap = l->llc_ssap = 0; 62374408Smdodd /* Fall through to */ 62474408Smdodd case LLC_TEST: 62574408Smdodd case LLC_TEST_P: 62674408Smdodd { 62774408Smdodd struct sockaddr sa; 628112296Smdodd struct arpcom *ac; 62974408Smdodd struct iso88025_sockaddr_data *th2; 63074408Smdodd int i; 631112296Smdodd u_char c; 63244165Sjulian 633112296Smdodd c = l->llc_dsap; 634112296Smdodd 63574408Smdodd if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 63674408Smdodd printf("iso88025_input: dropping source routed LLC_TEST\n"); 637112289Smdodd goto dropanyway; 63874408Smdodd } 63974408Smdodd l->llc_dsap = l->llc_ssap; 64074408Smdodd l->llc_ssap = c; 64174408Smdodd if (m->m_flags & (M_BCAST | M_MCAST)) 642152315Sru bcopy((caddr_t)IF_LLADDR(ifp), 643112280Smdodd (caddr_t)th->iso88025_dhost, 64474408Smdodd ISO88025_ADDR_LEN); 64574408Smdodd sa.sa_family = AF_UNSPEC; 64674408Smdodd sa.sa_len = sizeof(sa); 64774408Smdodd th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 64874408Smdodd for (i = 0; i < ISO88025_ADDR_LEN; i++) { 64974408Smdodd th2->ether_shost[i] = c = th->iso88025_dhost[i]; 65074408Smdodd th2->ether_dhost[i] = th->iso88025_dhost[i] = 65174408Smdodd th->iso88025_shost[i]; 65274408Smdodd th->iso88025_shost[i] = c; 65374408Smdodd } 65474408Smdodd th2->ac = TR_AC; 65574408Smdodd th2->fc = TR_LLC_FRAME; 65674408Smdodd ifp->if_output(ifp, m, &sa, NULL); 65774408Smdodd return; 65874408Smdodd } 65974408Smdodd default: 66074408Smdodd printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 661112289Smdodd ifp->if_noproto++; 662112289Smdodd goto dropanyway; 663112294Smdodd break; 66474408Smdodd } 66574408Smdodd break; 666112296Smdodd#endif /* ISO */ 66744165Sjulian default: 66874408Smdodd printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 66974408Smdodd ifp->if_noproto++; 670112289Smdodd goto dropanyway; 671112294Smdodd break; 67244165Sjulian } 673112274Smdodd 674223741Sbz M_SETFIB(m, ifp->if_fib); 675111888Sjlemon netisr_dispatch(isr, m); 676112274Smdodd return; 677112289Smdodd 678112289Smdodddropanyway: 679112289Smdodd ifp->if_iqdrops++; 680112289Smdodd if (m) 681112289Smdodd m_freem(m); 682112289Smdodd return; 68344165Sjulian} 684112269Smdodd 685112273Smdoddstatic int 686112273Smdoddiso88025_resolvemulti (ifp, llsa, sa) 687112273Smdodd struct ifnet *ifp; 688112273Smdodd struct sockaddr **llsa; 689112273Smdodd struct sockaddr *sa; 690112273Smdodd{ 691112273Smdodd struct sockaddr_dl *sdl; 692184710Sbz#ifdef INET 693112273Smdodd struct sockaddr_in *sin; 694184710Sbz#endif 695112273Smdodd#ifdef INET6 696112273Smdodd struct sockaddr_in6 *sin6; 697112273Smdodd#endif 698112273Smdodd u_char *e_addr; 699112273Smdodd 700112273Smdodd switch(sa->sa_family) { 701112273Smdodd case AF_LINK: 702112273Smdodd /* 703112273Smdodd * No mapping needed. Just check that it's a valid MC address. 704112273Smdodd */ 705112273Smdodd sdl = (struct sockaddr_dl *)sa; 706112273Smdodd e_addr = LLADDR(sdl); 707112273Smdodd if ((e_addr[0] & 1) != 1) { 708112273Smdodd return (EADDRNOTAVAIL); 709112273Smdodd } 710112273Smdodd *llsa = 0; 711112273Smdodd return (0); 712112273Smdodd 713112273Smdodd#ifdef INET 714112273Smdodd case AF_INET: 715112273Smdodd sin = (struct sockaddr_in *)sa; 716112273Smdodd if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 717112273Smdodd return (EADDRNOTAVAIL); 718112273Smdodd } 719184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 720148641Srwatson M_NOWAIT|M_ZERO); 721148641Srwatson if (sdl == NULL) 722148641Srwatson return (ENOMEM); 723112273Smdodd sdl->sdl_len = sizeof *sdl; 724112273Smdodd sdl->sdl_family = AF_LINK; 725112273Smdodd sdl->sdl_index = ifp->if_index; 726112273Smdodd sdl->sdl_type = IFT_ISO88025; 727112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 728112273Smdodd e_addr = LLADDR(sdl); 729112273Smdodd ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 730112273Smdodd *llsa = (struct sockaddr *)sdl; 731112273Smdodd return (0); 732112273Smdodd#endif 733112273Smdodd#ifdef INET6 734112273Smdodd case AF_INET6: 735112273Smdodd sin6 = (struct sockaddr_in6 *)sa; 736112273Smdodd if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 737112273Smdodd /* 738112273Smdodd * An IP6 address of 0 means listen to all 739112273Smdodd * of the Ethernet multicast address used for IP6. 740112273Smdodd * (This is used for multicast routers.) 741112273Smdodd */ 742112273Smdodd ifp->if_flags |= IFF_ALLMULTI; 743112273Smdodd *llsa = 0; 744112273Smdodd return (0); 745112273Smdodd } 746112273Smdodd if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 747112273Smdodd return (EADDRNOTAVAIL); 748112273Smdodd } 749184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 750148641Srwatson M_NOWAIT|M_ZERO); 751148641Srwatson if (sdl == NULL) 752148641Srwatson return (ENOMEM); 753112273Smdodd sdl->sdl_len = sizeof *sdl; 754112273Smdodd sdl->sdl_family = AF_LINK; 755112273Smdodd sdl->sdl_index = ifp->if_index; 756112273Smdodd sdl->sdl_type = IFT_ISO88025; 757112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 758112273Smdodd e_addr = LLADDR(sdl); 759112273Smdodd ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 760112273Smdodd *llsa = (struct sockaddr *)sdl; 761112273Smdodd return (0); 762112273Smdodd#endif 763112273Smdodd 764112273Smdodd default: 765112273Smdodd /* 766112273Smdodd * Well, the text isn't quite right, but it's the name 767112273Smdodd * that counts... 768112273Smdodd */ 769112273Smdodd return (EAFNOSUPPORT); 770112273Smdodd } 771112273Smdodd 772112273Smdodd return (0); 773112273Smdodd} 774112273Smdodd 775227293Sedstatic MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals"); 776147256Sbrooks 777147256Sbrooksstatic void* 778147256Sbrooksiso88025_alloc(u_char type, struct ifnet *ifp) 779147256Sbrooks{ 780147256Sbrooks struct arpcom *ac; 781147256Sbrooks 782147256Sbrooks ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO); 783147256Sbrooks ac->ac_ifp = ifp; 784147256Sbrooks 785147256Sbrooks return (ac); 786147256Sbrooks} 787147256Sbrooks 788147256Sbrooksstatic void 789147256Sbrooksiso88025_free(void *com, u_char type) 790147256Sbrooks{ 791147256Sbrooks 792147256Sbrooks free(com, M_ISO88025); 793147256Sbrooks} 794147256Sbrooks 795147256Sbrooksstatic int 796147256Sbrooksiso88025_modevent(module_t mod, int type, void *data) 797147256Sbrooks{ 798147256Sbrooks 799147256Sbrooks switch (type) { 800147256Sbrooks case MOD_LOAD: 801147256Sbrooks if_register_com_alloc(IFT_ISO88025, iso88025_alloc, 802147256Sbrooks iso88025_free); 803147256Sbrooks break; 804147256Sbrooks case MOD_UNLOAD: 805147256Sbrooks if_deregister_com_alloc(IFT_ISO88025); 806147256Sbrooks break; 807147256Sbrooks default: 808147256Sbrooks return EOPNOTSUPP; 809147256Sbrooks } 810147256Sbrooks 811147256Sbrooks return (0); 812147256Sbrooks} 813147256Sbrooks 814112269Smdoddstatic moduledata_t iso88025_mod = { 815112269Smdodd "iso88025", 816147256Sbrooks iso88025_modevent, 817241394Skevlo 0 818112269Smdodd}; 819112269Smdodd 820112269SmdoddDECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 821112269SmdoddMODULE_VERSION(iso88025, 1); 822