if_iso88025subr.c revision 112273
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 112273 2003-03-15 16:49:08Z 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" 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> 57112271Smdodd#include <net/if_dl.h> 5844165Sjulian#include <net/if_llc.h> 5944165Sjulian#include <net/if_types.h> 6044165Sjulian 61112271Smdodd#include <net/netisr.h> 62112271Smdodd#include <net/route.h> 63112271Smdodd#include <net/bpf.h> 6444165Sjulian#include <net/iso88025.h> 6544165Sjulian 6674408Smdodd#if defined(INET) || defined(INET6) 6744165Sjulian#include <netinet/in.h> 6844165Sjulian#include <netinet/in_var.h> 6944165Sjulian#include <netinet/if_ether.h> 7044165Sjulian#endif 7174408Smdodd#ifdef INET6 7274408Smdodd#include <netinet6/nd6.h> 7374408Smdodd#endif 7444165Sjulian 7574408Smdodd#ifdef IPX 7674408Smdodd#include <netipx/ipx.h> 7774408Smdodd#include <netipx/ipx_if.h> 7874408Smdodd#endif 7974408Smdodd 80112273Smdoddstatic int iso88025_resolvemulti (struct ifnet *, struct sockaddr **, 81112273Smdodd struct sockaddr *)); 82112273Smdodd 8374408Smdodd#define IFP2AC(IFP) ((struct arpcom *)IFP) 8474408Smdodd 8544165Sjulianvoid 8658313Slileiso88025_ifattach(struct ifnet *ifp) 8744165Sjulian{ 88111774Smdodd struct ifaddr *ifa = NULL; 89111774Smdodd struct sockaddr_dl *sdl; 9044165Sjulian 9144165Sjulian ifp->if_type = IFT_ISO88025; 9258313Slile ifp->if_addrlen = ISO88025_ADDR_LEN; 9358313Slile ifp->if_hdrlen = ISO88025_HDR_LEN; 9444165Sjulian if (ifp->if_baudrate == 0) 9558313Slile ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */ 9644165Sjulian if (ifp->if_mtu == 0) 9744165Sjulian ifp->if_mtu = ISO88025_DEFAULT_MTU; 9884931Sfjoe ifp->if_broadcastaddr = etherbroadcastaddr; 9944165Sjulian 100112272Smdodd ifa = ifaddr_byindex(ifp->if_index); 101112272Smdodd if (ifa == 0) { 102112272Smdodd printf("iso88025_ifattach: no lladdr!\n"); 103112272Smdodd return; 104112272Smdodd } 105112272Smdodd sdl = (struct sockaddr_dl *)ifa->ifa_addr; 106112272Smdodd sdl->sdl_type = IFT_ISO88025; 107112272Smdodd sdl->sdl_alen = ifp->if_addrlen; 108112272Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 10944165Sjulian} 11044165Sjulian 11174408Smdodd/* 11274408Smdodd * Perform common duties while detaching a Token Ring interface 11374408Smdodd */ 11474408Smdoddvoid 11574408Smdoddiso88025_ifdetach(ifp, bpf) 11674408Smdodd struct ifnet *ifp; 11774408Smdodd int bpf; 11874408Smdodd{ 11974408Smdodd if (bpf) 12074408Smdodd bpfdetach(ifp); 12174408Smdodd if_detach(ifp); 12274408Smdodd} 12374408Smdodd 12474408Smdodd 12544165Sjulianint 12644165Sjulianiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data) 12744165Sjulian{ 12844165Sjulian struct ifaddr *ifa = (struct ifaddr *) data; 12944165Sjulian struct ifreq *ifr = (struct ifreq *) data; 13044165Sjulian int error = 0; 13144165Sjulian 13244165Sjulian switch (command) { 13344165Sjulian case SIOCSIFADDR: 13444165Sjulian ifp->if_flags |= IFF_UP; 13544165Sjulian 13644165Sjulian switch (ifa->ifa_addr->sa_family) { 13744165Sjulian#ifdef INET 13844165Sjulian case AF_INET: 13944165Sjulian ifp->if_init(ifp->if_softc); /* before arpwhohas */ 14084931Sfjoe arp_ifinit(ifp, ifa); 14144165Sjulian break; 14274408Smdodd#endif /* INET */ 14374408Smdodd#ifdef IPX 14474408Smdodd /* 14574408Smdodd * XXX - This code is probably wrong 14674408Smdodd */ 14774408Smdodd case AF_IPX: 14874408Smdodd { 149111774Smdodd struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 15074408Smdodd struct arpcom *ac = IFP2AC(ifp); 15174408Smdodd 15274408Smdodd if (ipx_nullhost(*ina)) 15374408Smdodd ina->x_host = 15474408Smdodd *(union ipx_host *) 15574408Smdodd ac->ac_enaddr; 15674408Smdodd else { 15774408Smdodd bcopy((caddr_t) ina->x_host.c_host, 15874408Smdodd (caddr_t) ac->ac_enaddr, 15974408Smdodd sizeof(ac->ac_enaddr)); 16074408Smdodd } 16174408Smdodd 16274408Smdodd /* 16374408Smdodd * Set new address 16474408Smdodd */ 16574408Smdodd ifp->if_init(ifp->if_softc); 16674408Smdodd break; 16774408Smdodd } 16874408Smdodd#endif /* IPX */ 16944165Sjulian default: 17044165Sjulian ifp->if_init(ifp->if_softc); 17144165Sjulian break; 17244165Sjulian } 17344165Sjulian break; 17444165Sjulian 17544165Sjulian case SIOCGIFADDR: 17644165Sjulian { 17744165Sjulian struct sockaddr *sa; 17844165Sjulian 17944165Sjulian sa = (struct sockaddr *) & ifr->ifr_data; 180111775Smdodd bcopy(IFP2AC(ifp)->ac_enaddr, 18144165Sjulian (caddr_t) sa->sa_data, ISO88025_ADDR_LEN); 18244165Sjulian } 18344165Sjulian break; 18444165Sjulian 18544165Sjulian case SIOCSIFMTU: 18644165Sjulian /* 18744165Sjulian * Set the interface MTU. 18844165Sjulian */ 18958313Slile if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 19044165Sjulian error = EINVAL; 19144165Sjulian } else { 19244165Sjulian ifp->if_mtu = ifr->ifr_mtu; 19344165Sjulian } 19444165Sjulian break; 19544165Sjulian } 19644165Sjulian return (error); 19744165Sjulian} 19844165Sjulian 19944165Sjulian/* 20044165Sjulian * ISO88025 encapsulation 20144165Sjulian */ 20244165Sjulianint 20374408Smdoddiso88025_output(ifp, m, dst, rt0) 20474408Smdodd struct ifnet *ifp; 20574408Smdodd struct mbuf *m; 20674408Smdodd struct sockaddr *dst; 20774408Smdodd struct rtentry *rt0; 20844165Sjulian{ 20974408Smdodd u_int16_t snap_type = 0; 21087914Sjlemon int loop_copy = 0, error = 0, rif_len = 0; 21187914Sjlemon u_char edst[ISO88025_ADDR_LEN]; 21274408Smdodd struct iso88025_header *th; 21344627Sjulian struct iso88025_header gen_th; 21474408Smdodd struct sockaddr_dl *sdl = NULL; 21574408Smdodd struct rtentry *rt; 21644165Sjulian struct arpcom *ac = (struct arpcom *)ifp; 21744165Sjulian 21844165Sjulian if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 21944165Sjulian senderr(ENETDOWN); 22074408Smdodd getmicrotime(&ifp->if_lastchange); 22174408Smdodd 222111767Smdodd error = rt_check(&rt, &rt0, dst); 223111767Smdodd if (error) { 224111767Smdodd goto bad; 22544165Sjulian } 22644627Sjulian 22744627Sjulian /* Calculate routing info length based on arp table entry */ 22844627Sjulian if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway)) 229102291Sarchie if (SDL_ISO88025(sdl)->trld_rcf != 0) 23096184Skbyanc rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 23144627Sjulian 23244627Sjulian /* Generate a generic 802.5 header for the packet */ 23358313Slile gen_th.ac = TR_AC; 23458313Slile gen_th.fc = TR_LLC_FRAME; 23574408Smdodd (void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr, 23674408Smdodd sizeof(ac->ac_enaddr)); 23744627Sjulian if (rif_len) { 23858313Slile gen_th.iso88025_shost[0] |= TR_RII; 23944627Sjulian if (rif_len > 2) { 24096184Skbyanc gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 24174408Smdodd (void)memcpy((caddr_t)gen_th.rd, 24296184Skbyanc (caddr_t)SDL_ISO88025(sdl)->trld_route, 24396184Skbyanc rif_len - 2); 24444627Sjulian } 24544627Sjulian } 24644627Sjulian 24744165Sjulian switch (dst->sa_family) { 24844165Sjulian#ifdef INET 24944165Sjulian case AF_INET: 25084931Sfjoe if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 25144165Sjulian return (0); /* if not yet resolved */ 25274408Smdodd snap_type = ETHERTYPE_IP; 25374408Smdodd break; 25474408Smdodd#endif /* INET */ 25574408Smdodd#ifdef NOT_YET 25674408Smdodd#ifdef INET6 25774408Smdodd case AF_INET6: 25874408Smdodd if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 25974408Smdodd /* Something bad happened */ 26074408Smdodd return(0); 26174408Smdodd } 26274408Smdodd snap_type = ETHERTYPE_IPV6; 26374408Smdodd break; 26474408Smdodd#endif /* INET6 */ 26574408Smdodd#endif /* NOT_YET */ 26674408Smdodd#ifdef IPX 26774408Smdodd case AF_IPX: 26874408Smdodd { 26974408Smdodd u_int8_t *cp; 27074408Smdodd 27174408Smdodd snap_type = 0; 27274408Smdodd bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 27374408Smdodd sizeof (edst)); 27474408Smdodd 275111119Simp M_PREPEND(m, 3, M_TRYWAIT); 27644627Sjulian if (m == 0) 27744627Sjulian senderr(ENOBUFS); 27874408Smdodd m = m_pullup(m, 3); 27974408Smdodd if (m == 0) 28074408Smdodd senderr(ENOBUFS); 28174408Smdodd cp = mtod(m, u_int8_t *); 28274408Smdodd *cp++ = ETHERTYPE_IPX_8022; 28374408Smdodd *cp++ = ETHERTYPE_IPX_8022; 28474408Smdodd *cp++ = LLC_UI; 28574408Smdodd } 28674408Smdodd break; 28774408Smdodd#endif /* IPX */ 28844165Sjulian case AF_UNSPEC: 28974408Smdodd { 29074408Smdodd struct iso88025_sockaddr_data *sd; 29144627Sjulian /* 29244627Sjulian * For AF_UNSPEC sockaddr.sa_data must contain all of the 29344627Sjulian * mac information needed to send the packet. This allows 29444627Sjulian * full mac, llc, and source routing function to be controlled. 29544627Sjulian * llc and source routing information must already be in the 29644627Sjulian * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 297108533Sschweikh * should be an iso88025_sockaddr_data structure see iso88025.h 29844627Sjulian */ 29944165Sjulian loop_copy = -1; 30044627Sjulian sd = (struct iso88025_sockaddr_data *)dst->sa_data; 30144627Sjulian gen_th.ac = sd->ac; 30244627Sjulian gen_th.fc = sd->fc; 30374408Smdodd (void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost, 30474408Smdodd sizeof(sd->ether_dhost)); 30574408Smdodd (void)memcpy((caddr_t)gen_th.iso88025_shost, 30674408Smdodd (caddr_t)sd->ether_shost, sizeof(sd->ether_shost)); 30744627Sjulian rif_len = 0; 30844165Sjulian break; 30974408Smdodd } 31044165Sjulian default: 311105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 31244165Sjulian senderr(EAFNOSUPPORT); 31374408Smdodd break; 31444165Sjulian } 31544165Sjulian 31674408Smdodd if (snap_type != 0) { 31774408Smdodd struct llc *l; 318111790Smdodd M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 31974408Smdodd if (m == 0) 32074408Smdodd senderr(ENOBUFS); 32174408Smdodd l = mtod(m, struct llc *); 322112268Smdodd l->llc_snap.ether_type = htons(snap_type); 32374408Smdodd l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 324112268Smdodd l->llc_snap.control = LLC_UI; 325112268Smdodd l->llc_snap.org_code[0] = 326112268Smdodd l->llc_snap.org_code[1] = 327112268Smdodd l->llc_snap.org_code[2] = 0; 32874408Smdodd } 32974408Smdodd 33044165Sjulian /* 33144165Sjulian * Add local net header. If no space in first mbuf, 33244165Sjulian * allocate another. 33344165Sjulian */ 334111119Simp M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT); 33544165Sjulian if (m == 0) 33644165Sjulian senderr(ENOBUFS); 33744627Sjulian 33874408Smdodd (void)memcpy((caddr_t)&gen_th.iso88025_dhost, (caddr_t)edst, 33974408Smdodd sizeof(edst)); 34074408Smdodd 34144627Sjulian /* Copy as much of the generic header as is needed into the mbuf */ 34244165Sjulian th = mtod(m, struct iso88025_header *); 34344627Sjulian memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 34444627Sjulian 34544165Sjulian /* 34644165Sjulian * If a simplex interface, and the packet is being sent to our 34744165Sjulian * Ethernet address or a broadcast address, loopback a copy. 34844165Sjulian * XXX To make a simplex device behave exactly like a duplex 34944165Sjulian * device, we should copy in the case of sending to our own 35044165Sjulian * ethernet address (thus letting the original actually appear 35144165Sjulian * on the wire). However, we don't do that here for security 35244165Sjulian * reasons and compatibility with the original behavior. 35344165Sjulian */ 35474408Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 35544165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 35674408Smdodd struct mbuf *n; 35774408Smdodd n = m_copy(m, 0, (int)M_COPYALL); 35874408Smdodd (void)if_simloop(ifp, n, dst->sa_family, 35974408Smdodd ISO88025_HDR_LEN); 36074408Smdodd } else 36174408Smdodd if (bcmp(th->iso88025_dhost, th->iso88025_shost, 36274408Smdodd ETHER_ADDR_LEN) == 0) { 36374408Smdodd (void)if_simloop(ifp, m, dst->sa_family, 36474408Smdodd ISO88025_HDR_LEN); 36574408Smdodd return(0); /* XXX */ 36674408Smdodd } 36744165Sjulian } 36844165Sjulian 369111790Smdodd if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN) ) { 37069152Sjlemon printf("iso88025_output: packet dropped QFULL.\n"); 37144165Sjulian senderr(ENOBUFS); 37244165Sjulian } 37344165Sjulian return (error); 37444165Sjulian 37544165Sjulianbad: 37644165Sjulian if (m) 37744165Sjulian m_freem(m); 37844165Sjulian return (error); 37944165Sjulian} 38044165Sjulian 38144165Sjulian/* 38244165Sjulian * ISO 88025 de-encapsulation 38344165Sjulian */ 38444165Sjulianvoid 38574408Smdoddiso88025_input(ifp, th, m) 38674408Smdodd struct ifnet *ifp; 38774408Smdodd struct iso88025_header *th; 38874408Smdodd struct mbuf *m; 38944165Sjulian{ 390111888Sjlemon int isr; 391111774Smdodd struct llc *l; 39244165Sjulian 39358313Slile if ((ifp->if_flags & IFF_UP) == 0) { 39458313Slile m_freem(m); 39558313Slile return; 39658313Slile } 39744165Sjulian 39874408Smdodd getmicrotime(&ifp->if_lastchange); 39974408Smdodd ifp->if_ibytes += m->m_pkthdr.len + sizeof(*th); 40058313Slile 40144165Sjulian if (th->iso88025_dhost[0] & 1) { 40274408Smdodd if (bcmp((caddr_t)etherbroadcastaddr, 40374408Smdodd (caddr_t)th->iso88025_dhost, 40474408Smdodd sizeof(etherbroadcastaddr)) == 0) 40544165Sjulian m->m_flags |= M_BCAST; 40644165Sjulian else 40744165Sjulian m->m_flags |= M_MCAST; 40874408Smdodd ifp->if_imcasts++; 40944165Sjulian } 41044165Sjulian 41174408Smdodd l = mtod(m, struct llc *); 41244165Sjulian 41374408Smdodd switch (l->llc_dsap) { 41474408Smdodd#ifdef IPX 41574408Smdodd case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 41674408Smdodd if ((l->llc_control != LLC_UI) || 41774408Smdodd (l->llc_ssap != ETHERTYPE_IPX_8022)) 41874408Smdodd goto dropanyway; 41974408Smdodd 42074408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 42174408Smdodd m_adj(m, 3); 422111888Sjlemon isr = NETISR_IPX; 42374408Smdodd break; 42474408Smdodd#endif /* IPX */ 42574408Smdodd case LLC_SNAP_LSAP: { 42674408Smdodd u_int16_t type; 42774408Smdodd if ((l->llc_control != LLC_UI) || 42874408Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) 42974408Smdodd goto dropanyway; 43074408Smdodd 431112268Smdodd if (l->llc_snap.org_code[0] != 0 || 432112268Smdodd l->llc_snap.org_code[1] != 0 || 433112268Smdodd l->llc_snap.org_code[2] != 0) 43474408Smdodd goto dropanyway; 43574408Smdodd 436112268Smdodd type = ntohs(l->llc_snap.ether_type); 437111790Smdodd m_adj(m, LLC_SNAPFRAMELEN); 43874408Smdodd switch (type) { 43944165Sjulian#ifdef INET 44074408Smdodd case ETHERTYPE_IP: 44174408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 44274408Smdodd if (ipflow_fastforward(m)) 44374408Smdodd return; 444111888Sjlemon isr = NETISR_IP; 44574408Smdodd break; 44674408Smdodd 44774408Smdodd case ETHERTYPE_ARP: 44878295Sjlemon if (ifp->if_flags & IFF_NOARP) 44978295Sjlemon goto dropanyway; 450111888Sjlemon isr = NETISR_ARP; 45174408Smdodd break; 45274408Smdodd#endif /* INET */ 45374408Smdodd#ifdef IPX_SNAP /* XXX: Not supported! */ 45474408Smdodd case ETHERTYPE_IPX: 45574408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 456111888Sjlemon isr = NETISR_IPX; 45774408Smdodd break; 45874408Smdodd#endif /* IPX_SNAP */ 45974408Smdodd#ifdef NOT_YET 46074408Smdodd#ifdef INET6 46174408Smdodd case ETHERTYPE_IPV6: 46274408Smdodd th->iso88025_shost[0] &= ~(TR_RII); 463111888Sjlemon isr = NETISR_IPV6; 46474408Smdodd break; 46574408Smdodd#endif /* INET6 */ 46674408Smdodd#endif /* NOT_YET */ 46774408Smdodd default: 46874408Smdodd printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 46974408Smdodd m_freem(m); 47044165Sjulian return; 47174408Smdodd } 47244165Sjulian break; 47374408Smdodd } 47474408Smdodd case LLC_ISO_LSAP: 47574408Smdodd switch (l->llc_control) { 47674408Smdodd case LLC_UI: 47774408Smdodd goto dropanyway; 47874408Smdodd break; 47974408Smdodd case LLC_XID: 48074408Smdodd case LLC_XID_P: 48174408Smdodd if(m->m_len < ISO88025_ADDR_LEN) 48274408Smdodd goto dropanyway; 48374408Smdodd l->llc_window = 0; 48474408Smdodd l->llc_fid = 9; 48574408Smdodd l->llc_class = 1; 48674408Smdodd l->llc_dsap = l->llc_ssap = 0; 48774408Smdodd /* Fall through to */ 48874408Smdodd case LLC_TEST: 48974408Smdodd case LLC_TEST_P: 49074408Smdodd { 49174408Smdodd struct sockaddr sa; 49274408Smdodd struct arpcom *ac = (struct arpcom *)ifp; 49374408Smdodd struct iso88025_sockaddr_data *th2; 49474408Smdodd int i; 49574408Smdodd u_char c = l->llc_dsap; 49644165Sjulian 49774408Smdodd if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 49874408Smdodd printf("iso88025_input: dropping source routed LLC_TEST\n"); 49974408Smdodd m_free(m); 50074408Smdodd return; 50174408Smdodd } 50274408Smdodd l->llc_dsap = l->llc_ssap; 50374408Smdodd l->llc_ssap = c; 50474408Smdodd if (m->m_flags & (M_BCAST | M_MCAST)) 50574408Smdodd bcopy((caddr_t)ac->ac_enaddr, 50674408Smdodd (caddr_t)th->iso88025_dhost, 50774408Smdodd ISO88025_ADDR_LEN); 50874408Smdodd sa.sa_family = AF_UNSPEC; 50974408Smdodd sa.sa_len = sizeof(sa); 51074408Smdodd th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 51174408Smdodd for (i = 0; i < ISO88025_ADDR_LEN; i++) { 51274408Smdodd th2->ether_shost[i] = c = th->iso88025_dhost[i]; 51374408Smdodd th2->ether_dhost[i] = th->iso88025_dhost[i] = 51474408Smdodd th->iso88025_shost[i]; 51574408Smdodd th->iso88025_shost[i] = c; 51674408Smdodd } 51774408Smdodd th2->ac = TR_AC; 51874408Smdodd th2->fc = TR_LLC_FRAME; 51974408Smdodd ifp->if_output(ifp, m, &sa, NULL); 52074408Smdodd return; 52174408Smdodd } 52274408Smdodd default: 52374408Smdodd printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 52474408Smdodd m_freem(m); 52574408Smdodd return; 52674408Smdodd } 52774408Smdodd break; 52844165Sjulian default: 52974408Smdodd printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 53074408Smdodd ifp->if_noproto++; 53174408Smdodd dropanyway: 53274408Smdodd m_freem(m); 53374408Smdodd return; 53444165Sjulian } 535111888Sjlemon netisr_dispatch(isr, m); 53644165Sjulian} 537112269Smdodd 538112273Smdoddstatic int 539112273Smdoddiso88025_resolvemulti (ifp, llsa, sa) 540112273Smdodd struct ifnet *ifp; 541112273Smdodd struct sockaddr **llsa; 542112273Smdodd struct sockaddr *sa; 543112273Smdodd{ 544112273Smdodd struct sockaddr_dl *sdl; 545112273Smdodd struct sockaddr_in *sin; 546112273Smdodd#ifdef INET6 547112273Smdodd struct sockaddr_in6 *sin6; 548112273Smdodd#endif 549112273Smdodd u_char *e_addr; 550112273Smdodd 551112273Smdodd switch(sa->sa_family) { 552112273Smdodd case AF_LINK: 553112273Smdodd /* 554112273Smdodd * No mapping needed. Just check that it's a valid MC address. 555112273Smdodd */ 556112273Smdodd sdl = (struct sockaddr_dl *)sa; 557112273Smdodd e_addr = LLADDR(sdl); 558112273Smdodd if ((e_addr[0] & 1) != 1) { 559112273Smdodd return (EADDRNOTAVAIL); 560112273Smdodd } 561112273Smdodd *llsa = 0; 562112273Smdodd return (0); 563112273Smdodd 564112273Smdodd#ifdef INET 565112273Smdodd case AF_INET: 566112273Smdodd sin = (struct sockaddr_in *)sa; 567112273Smdodd if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 568112273Smdodd return (EADDRNOTAVAIL); 569112273Smdodd } 570112273Smdodd MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 571112273Smdodd M_WAITOK|M_ZERO); 572112273Smdodd sdl->sdl_len = sizeof *sdl; 573112273Smdodd sdl->sdl_family = AF_LINK; 574112273Smdodd sdl->sdl_index = ifp->if_index; 575112273Smdodd sdl->sdl_type = IFT_ISO88025; 576112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 577112273Smdodd e_addr = LLADDR(sdl); 578112273Smdodd ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 579112273Smdodd *llsa = (struct sockaddr *)sdl; 580112273Smdodd return (0); 581112273Smdodd#endif 582112273Smdodd#ifdef INET6 583112273Smdodd case AF_INET6: 584112273Smdodd sin6 = (struct sockaddr_in6 *)sa; 585112273Smdodd if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 586112273Smdodd /* 587112273Smdodd * An IP6 address of 0 means listen to all 588112273Smdodd * of the Ethernet multicast address used for IP6. 589112273Smdodd * (This is used for multicast routers.) 590112273Smdodd */ 591112273Smdodd ifp->if_flags |= IFF_ALLMULTI; 592112273Smdodd *llsa = 0; 593112273Smdodd return (0); 594112273Smdodd } 595112273Smdodd if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 596112273Smdodd return (EADDRNOTAVAIL); 597112273Smdodd } 598112273Smdodd MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 599112273Smdodd M_WAITOK|M_ZERO); 600112273Smdodd sdl->sdl_len = sizeof *sdl; 601112273Smdodd sdl->sdl_family = AF_LINK; 602112273Smdodd sdl->sdl_index = ifp->if_index; 603112273Smdodd sdl->sdl_type = IFT_ISO88025; 604112273Smdodd sdl->sdl_alen = ISO88025_ADDR_LEN; 605112273Smdodd e_addr = LLADDR(sdl); 606112273Smdodd ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 607112273Smdodd *llsa = (struct sockaddr *)sdl; 608112273Smdodd return (0); 609112273Smdodd#endif 610112273Smdodd 611112273Smdodd default: 612112273Smdodd /* 613112273Smdodd * Well, the text isn't quite right, but it's the name 614112273Smdodd * that counts... 615112273Smdodd */ 616112273Smdodd return (EAFNOSUPPORT); 617112273Smdodd } 618112273Smdodd 619112273Smdodd return (0); 620112273Smdodd} 621112273Smdodd 622112269Smdoddstatic moduledata_t iso88025_mod = { 623112269Smdodd "iso88025", 624112269Smdodd NULL, 625112269Smdodd 0 626112269Smdodd}; 627112269Smdodd 628112269SmdoddDECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 629112269SmdoddMODULE_VERSION(iso88025, 1); 630