if_fddisubr.c revision 163606
1139823Simp/*- 221830Sjoerg * Copyright (c) 1995, 1996 321830Sjoerg * Matt Thomas <matt@3am-software.com>. All rights reserved. 47055Sdg * Copyright (c) 1982, 1989, 1993 57055Sdg * The Regents of the University of California. All rights reserved. 67055Sdg * 77055Sdg * Redistribution and use in source and binary forms, with or without 87055Sdg * modification, are permitted provided that the following conditions 97055Sdg * are met: 107055Sdg * 1. Redistributions of source code must retain the above copyright 117055Sdg * notice, this list of conditions and the following disclaimer. 127055Sdg * 2. Redistributions in binary form must reproduce the above copyright 137055Sdg * notice, this list of conditions and the following disclaimer in the 147055Sdg * documentation and/or other materials provided with the distribution. 157055Sdg * 3. All advertising materials mentioning features or use of this software 167055Sdg * must display the following acknowledgement: 177055Sdg * This product includes software developed by the University of 187055Sdg * California, Berkeley and its contributors. 197055Sdg * 4. Neither the name of the University nor the names of its contributors 207055Sdg * may be used to endorse or promote products derived from this software 217055Sdg * without specific prior written permission. 227055Sdg * 237055Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 247055Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 257055Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 267055Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 277055Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 287055Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 297055Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 307055Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 317055Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 327055Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 337055Sdg * SUCH DAMAGE. 347055Sdg * 357061Sdg * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 3650477Speter * $FreeBSD: head/sys/net/if_fddisubr.c 163606 2006-10-22 11:52:19Z rwatson $ 377055Sdg */ 387055Sdg 3932356Seivind#include "opt_atalk.h" 4032350Seivind#include "opt_inet.h" 4154263Sshin#include "opt_inet6.h" 4231742Seivind#include "opt_ipx.h" 43105577Srwatson#include "opt_mac.h" 4431742Seivind 457055Sdg#include <sys/param.h> 467055Sdg#include <sys/systm.h> 4793375Smdodd#include <sys/kernel.h> 4893375Smdodd#include <sys/malloc.h> 497055Sdg#include <sys/mbuf.h> 5093375Smdodd#include <sys/module.h> 517055Sdg#include <sys/socket.h> 5293375Smdodd#include <sys/sockio.h> 537055Sdg 547055Sdg#include <net/if.h> 55112271Smdodd#include <net/if_dl.h> 567055Sdg#include <net/if_llc.h> 577055Sdg#include <net/if_types.h> 58112271Smdodd 5993375Smdodd#include <net/netisr.h> 6093375Smdodd#include <net/route.h> 6193375Smdodd#include <net/bpf.h> 6293373Smdodd#include <net/fddi.h> 637055Sdg 6454263Sshin#if defined(INET) || defined(INET6) 657055Sdg#include <netinet/in.h> 667055Sdg#include <netinet/in_var.h> 6732350Seivind#include <netinet/if_ether.h> 687055Sdg#endif 6954263Sshin#ifdef INET6 7054263Sshin#include <netinet6/nd6.h> 7154263Sshin#endif 727055Sdg 7311819Sjulian#ifdef IPX 7421830Sjoerg#include <netipx/ipx.h> 7511819Sjulian#include <netipx/ipx_if.h> 7611819Sjulian#endif 7711819Sjulian 787055Sdg#ifdef DECNET 797055Sdg#include <netdnet/dn.h> 807055Sdg#endif 817055Sdg 8221830Sjoerg#ifdef NETATALK 8321830Sjoerg#include <netatalk/at.h> 8421830Sjoerg#include <netatalk/at_var.h> 8521830Sjoerg#include <netatalk/at_extern.h> 8621830Sjoerg 8721830Sjoergextern u_char at_org_code[ 3 ]; 8821830Sjoergextern u_char aarp_org_code[ 3 ]; 8921830Sjoerg#endif /* NETATALK */ 9021830Sjoerg 91163606Srwatson#include <security/mac/mac_framework.h> 92163606Srwatson 93126788Srwatsonstatic const u_char fddibroadcastaddr[FDDI_ADDR_LEN] = 9493382Smdodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 9593382Smdodd 9693383Smdoddstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 9793084Sbde struct sockaddr *); 9893383Smdoddstatic int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *, 9993383Smdodd struct rtentry *); 100106939Ssamstatic void fddi_input(struct ifnet *ifp, struct mbuf *m); 10168180Sume 102112276Smdodd#define senderr(e) do { error = (e); goto bad; } while (0) 10393369Smdodd 1047055Sdg/* 1057055Sdg * FDDI output routine. 1067055Sdg * Encapsulate a packet of type family for the local net. 1077055Sdg * Use trailer local net encapsulation if enough data in first 1087055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1097055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1107055Sdg */ 11193383Smdoddstatic int 11254799Sgreenfddi_output(ifp, m, dst, rt0) 11393367Smdodd struct ifnet *ifp; 11454799Sgreen struct mbuf *m; 1157055Sdg struct sockaddr *dst; 1167055Sdg struct rtentry *rt0; 1177055Sdg{ 11821830Sjoerg u_int16_t type; 11969152Sjlemon int loop_copy = 0, error = 0, hdrcmplt = 0; 12093373Smdodd u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 12193367Smdodd struct fddi_header *fh; 1227055Sdg 123105577Srwatson#ifdef MAC 124105577Srwatson error = mac_check_ifnet_transmit(ifp, m); 125105577Srwatson if (error) 126105577Srwatson senderr(error); 127105577Srwatson#endif 128105577Srwatson 129112308Smdodd if (ifp->if_flags & IFF_MONITOR) 130112308Smdodd senderr(ENETDOWN); 131148887Srwatson if (!((ifp->if_flags & IFF_UP) && 132148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 1337055Sdg senderr(ENETDOWN); 13434961Sphk getmicrotime(&ifp->if_lastchange); 135111767Smdodd 1367055Sdg switch (dst->sa_family) { 1377055Sdg#ifdef INET 13821830Sjoerg case AF_INET: { 139128636Sluigi error = arpresolve(ifp, rt0, m, dst, edst); 140128636Sluigi if (error) 141128636Sluigi return (error == EWOULDBLOCK ? 0 : error); 14221830Sjoerg type = htons(ETHERTYPE_IP); 1437055Sdg break; 14421830Sjoerg } 145126951Smdodd case AF_ARP: 146126951Smdodd { 147126951Smdodd struct arphdr *ah; 148126951Smdodd ah = mtod(m, struct arphdr *); 149126951Smdodd ah->ar_hrd = htons(ARPHRD_ETHER); 150126951Smdodd 151126951Smdodd loop_copy = -1; /* if this is for us, don't do it */ 152126951Smdodd 153126951Smdodd switch (ntohs(ah->ar_op)) { 154126951Smdodd case ARPOP_REVREQUEST: 155126951Smdodd case ARPOP_REVREPLY: 156126951Smdodd type = htons(ETHERTYPE_REVARP); 157126951Smdodd break; 158126951Smdodd case ARPOP_REQUEST: 159126951Smdodd case ARPOP_REPLY: 160126951Smdodd default: 161126951Smdodd type = htons(ETHERTYPE_ARP); 162126951Smdodd break; 163126951Smdodd } 164126951Smdodd 165126951Smdodd if (m->m_flags & M_BCAST) 166126951Smdodd bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN); 167126951Smdodd else 168126951Smdodd bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN); 169126951Smdodd 170126951Smdodd } 171126951Smdodd break; 172112266Smdodd#endif /* INET */ 17354263Sshin#ifdef INET6 17454263Sshin case AF_INET6: 175128636Sluigi error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); 176128636Sluigi if (error) 177128636Sluigi return (error); /* Something bad happened */ 17854263Sshin type = htons(ETHERTYPE_IPV6); 17954263Sshin break; 180112266Smdodd#endif /* INET6 */ 18111819Sjulian#ifdef IPX 18211819Sjulian case AF_IPX: 18321830Sjoerg type = htons(ETHERTYPE_IPX); 18411819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 18593373Smdodd (caddr_t)edst, FDDI_ADDR_LEN); 18611819Sjulian break; 187112266Smdodd#endif /* IPX */ 18821830Sjoerg#ifdef NETATALK 18921830Sjoerg case AF_APPLETALK: { 19021830Sjoerg struct at_ifaddr *aa; 191128636Sluigi if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst)) 19221830Sjoerg return (0); 19321830Sjoerg /* 19421830Sjoerg * ifaddr is the first thing in at_ifaddr 19521830Sjoerg */ 19630834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 19721830Sjoerg goto bad; 19821830Sjoerg 19921830Sjoerg /* 20021830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 20121830Sjoerg * Since we must preserve the value of m, which is passed to us by 20221830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 20321830Sjoerg */ 20421830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 20521830Sjoerg struct llc llc; 20621830Sjoerg 207111119Simp M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT); 20821830Sjoerg if (m == 0) 20921830Sjoerg senderr(ENOBUFS); 21021830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 21121830Sjoerg llc.llc_control = LLC_UI; 21293371Smdodd bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 21393371Smdodd llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 21493373Smdodd bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 21521830Sjoerg type = 0; 21621830Sjoerg } else { 21721830Sjoerg type = htons(ETHERTYPE_AT); 21821830Sjoerg } 21921830Sjoerg break; 22021830Sjoerg } 22121830Sjoerg#endif /* NETATALK */ 2227055Sdg 22352248Smsmith case pseudo_AF_HDRCMPLT: 22452248Smsmith { 22593376Smdodd struct ether_header *eh; 22652248Smsmith hdrcmplt = 1; 22793376Smdodd eh = (struct ether_header *)dst->sa_data; 22893376Smdodd bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 22952248Smsmith /* FALLTHROUGH */ 23052248Smsmith } 23152248Smsmith 2327055Sdg case AF_UNSPEC: 2337055Sdg { 2347055Sdg struct ether_header *eh; 23536992Sjulian loop_copy = -1; 2367055Sdg eh = (struct ether_header *)dst->sa_data; 23793375Smdodd bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 2387055Sdg if (*edst & 1) 2397055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2407055Sdg type = eh->ether_type; 2417055Sdg break; 2427055Sdg } 2437055Sdg 2447055Sdg case AF_IMPLINK: 2457055Sdg { 2467055Sdg fh = mtod(m, struct fddi_header *); 2477055Sdg error = EPROTONOSUPPORT; 2487055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2497055Sdg case FDDIFC_LLC_ASYNC: { 2507055Sdg /* legal priorities are 0 through 7 */ 2517055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2527055Sdg goto bad; 2537055Sdg break; 2547055Sdg } 2557055Sdg case FDDIFC_LLC_SYNC: { 2567055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2577055Sdg if (fh->fddi_fc & FDDIFC_Z) 2587055Sdg goto bad; 2597055Sdg break; 2607055Sdg } 2617055Sdg case FDDIFC_SMT: { 2627055Sdg /* FDDIFC_Z bits must be non zero */ 2637055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2647055Sdg goto bad; 2657055Sdg break; 2667055Sdg } 2677055Sdg default: { 2687055Sdg /* anything else is too dangerous */ 2697055Sdg goto bad; 2707055Sdg } 2717055Sdg } 2727055Sdg error = 0; 2737055Sdg if (fh->fddi_dhost[0] & 1) 2747055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2757055Sdg goto queue_it; 2767055Sdg } 2777055Sdg default: 278105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 2797055Sdg senderr(EAFNOSUPPORT); 2807055Sdg } 2817055Sdg 28293380Smdodd /* 28393380Smdodd * Add LLC header. 28493380Smdodd */ 2857055Sdg if (type != 0) { 28693367Smdodd struct llc *l; 287111119Simp M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 2887055Sdg if (m == 0) 2897055Sdg senderr(ENOBUFS); 2907055Sdg l = mtod(m, struct llc *); 2917055Sdg l->llc_control = LLC_UI; 2927055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 293112266Smdodd l->llc_snap.org_code[0] = 294112266Smdodd l->llc_snap.org_code[1] = 295112266Smdodd l->llc_snap.org_code[2] = 0; 296112266Smdodd l->llc_snap.ether_type = htons(type); 2977055Sdg } 29836908Sjulian 2997055Sdg /* 3007055Sdg * Add local net header. If no space in first mbuf, 3017055Sdg * allocate another. 3027055Sdg */ 303111119Simp M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 3047055Sdg if (m == 0) 3057055Sdg senderr(ENOBUFS); 3067055Sdg fh = mtod(m, struct fddi_header *); 3077055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 30893375Smdodd bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 3097055Sdg queue_it: 31052248Smsmith if (hdrcmplt) 31193375Smdodd bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 31252248Smsmith else 313152315Sru bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost, 31493373Smdodd FDDI_ADDR_LEN); 31593377Smdodd 31636908Sjulian /* 31736908Sjulian * If a simplex interface, and the packet is being sent to our 31836908Sjulian * Ethernet address or a broadcast address, loopback a copy. 31936908Sjulian * XXX To make a simplex device behave exactly like a duplex 32036908Sjulian * device, we should copy in the case of sending to our own 32136908Sjulian * ethernet address (thus letting the original actually appear 32236908Sjulian * on the wire). However, we don't do that here for security 32336908Sjulian * reasons and compatibility with the original behavior. 32436908Sjulian */ 32593377Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 326112279Smdodd if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 327112279Smdodd struct mbuf *n; 328112279Smdodd n = m_copy(m, 0, (int)M_COPYALL); 329112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 330112279Smdodd FDDI_HDR_LEN); 331112279Smdodd } else if (bcmp(fh->fddi_dhost, fh->fddi_shost, 332112279Smdodd FDDI_ADDR_LEN) == 0) { 333112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 334112279Smdodd FDDI_HDR_LEN); 33593369Smdodd return (0); /* XXX */ 33636908Sjulian } 33736908Sjulian } 33836908Sjulian 339130549Smlaier IFQ_HANDOFF(ifp, m, error); 340130549Smlaier if (error) 341130549Smlaier ifp->if_oerrors++; 342130549Smlaier 3437055Sdg return (error); 3447055Sdg 3457055Sdgbad: 34693379Smdodd ifp->if_oerrors++; 3477055Sdg if (m) 3487055Sdg m_freem(m); 3497055Sdg return (error); 3507055Sdg} 3517055Sdg 3527055Sdg/* 353112308Smdodd * Process a received FDDI packet. 3547055Sdg */ 355106939Ssamstatic void 356106939Ssamfddi_input(ifp, m) 3577055Sdg struct ifnet *ifp; 3587055Sdg struct mbuf *m; 3597055Sdg{ 360111888Sjlemon int isr; 36193367Smdodd struct llc *l; 362106939Ssam struct fddi_header *fh; 3637055Sdg 364112308Smdodd /* 365112308Smdodd * Do consistency checks to verify assumptions 366112308Smdodd * made by code past this point. 367112308Smdodd */ 368112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 369112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 370112308Smdodd ifp->if_ierrors++; 371112308Smdodd m_freem(m); 372112308Smdodd return; 373112308Smdodd } 374112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 375112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 376112308Smdodd ifp->if_ierrors++; 377112308Smdodd m_freem(m); 378112308Smdodd return; 379112308Smdodd } 380112308Smdodd 381112308Smdodd m = m_pullup(m, FDDI_HDR_LEN); 382112308Smdodd if (m == NULL) { 383112308Smdodd ifp->if_ierrors++; 384112308Smdodd goto dropanyway; 385112308Smdodd } 386106939Ssam fh = mtod(m, struct fddi_header *); 387112308Smdodd m->m_pkthdr.header = (void *)fh; 388106939Ssam 38993379Smdodd /* 39093379Smdodd * Discard packet if interface is not up. 39193379Smdodd */ 392148887Srwatson if (!((ifp->if_flags & IFF_UP) && 393148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 39493379Smdodd goto dropanyway; 39593379Smdodd 396112308Smdodd /* 397112308Smdodd * Give bpf a chance at the packet. 398112308Smdodd */ 399112308Smdodd BPF_MTAP(ifp, m); 400112308Smdodd 401112308Smdodd /* 402112308Smdodd * Interface marked for monitoring; discard packet. 403112308Smdodd */ 404112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 405112308Smdodd m_freem(m); 406112308Smdodd return; 407112308Smdodd } 408112308Smdodd 409105577Srwatson#ifdef MAC 410105577Srwatson mac_create_mbuf_from_ifnet(ifp, m); 411105577Srwatson#endif 412105577Srwatson 41393379Smdodd /* 414112287Smdodd * Update interface statistics. 415112287Smdodd */ 416112287Smdodd ifp->if_ibytes += m->m_pkthdr.len; 417112287Smdodd getmicrotime(&ifp->if_lastchange); 418112287Smdodd 419112287Smdodd /* 42093379Smdodd * Discard non local unicast packets when interface 42193379Smdodd * is in promiscuous mode. 42293379Smdodd */ 42393379Smdodd if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 424152315Sru (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost, 42593379Smdodd FDDI_ADDR_LEN) != 0)) 42693379Smdodd goto dropanyway; 42793379Smdodd 42893379Smdodd /* 42993379Smdodd * Set mbuf flags for bcast/mcast. 43093379Smdodd */ 43121830Sjoerg if (fh->fddi_dhost[0] & 1) { 432121436Simp if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost, 433121436Simp FDDI_ADDR_LEN) == 0) 43421830Sjoerg m->m_flags |= M_BCAST; 43521830Sjoerg else 43621830Sjoerg m->m_flags |= M_MCAST; 4377055Sdg ifp->if_imcasts++; 43821830Sjoerg } 4397055Sdg 44021830Sjoerg#ifdef M_LINK0 44121830Sjoerg /* 44221830Sjoerg * If this has a LLC priority of 0, then mark it so upper 44321830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 44421830Sjoerg * bridge. 44521830Sjoerg */ 44621830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 44721830Sjoerg m->m_flags |= M_LINK0; 44821830Sjoerg#endif 44921830Sjoerg 450106939Ssam /* Strip off FDDI header. */ 451111790Smdodd m_adj(m, FDDI_HDR_LEN); 452106939Ssam 453111790Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 45493379Smdodd if (m == 0) { 45593379Smdodd ifp->if_ierrors++; 45693379Smdodd goto dropanyway; 45793379Smdodd } 4587055Sdg l = mtod(m, struct llc *); 45993377Smdodd 4607055Sdg switch (l->llc_dsap) { 4617055Sdg case LLC_SNAP_LSAP: 4627055Sdg { 46321830Sjoerg u_int16_t type; 464112266Smdodd if ((l->llc_control != LLC_UI) || 465112266Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 46693379Smdodd ifp->if_noproto++; 4677055Sdg goto dropanyway; 46893379Smdodd } 46921830Sjoerg#ifdef NETATALK 470128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], at_org_code, 471111888Sjlemon sizeof(at_org_code)) == 0 && 472111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 473111888Sjlemon isr = NETISR_ATALK2; 474111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 475111888Sjlemon break; 47621830Sjoerg } 47721830Sjoerg 478128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 479111888Sjlemon sizeof(aarp_org_code)) == 0 && 480111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 481111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 482111888Sjlemon isr = NETISR_AARP; 483111888Sjlemon break; 48421830Sjoerg } 48521830Sjoerg#endif /* NETATALK */ 48693377Smdodd if (l->llc_snap.org_code[0] != 0 || 48793377Smdodd l->llc_snap.org_code[1] != 0 || 48893379Smdodd l->llc_snap.org_code[2] != 0) { 48993379Smdodd ifp->if_noproto++; 4907055Sdg goto dropanyway; 49193379Smdodd } 49293377Smdodd 49321830Sjoerg type = ntohs(l->llc_snap.ether_type); 49493377Smdodd m_adj(m, LLC_SNAPFRAMELEN); 49593377Smdodd 49621830Sjoerg switch (type) { 4977055Sdg#ifdef INET 4987055Sdg case ETHERTYPE_IP: 499154518Sandre if ((m = ip_fastforward(m)) == NULL) 50036192Sdg return; 501111888Sjlemon isr = NETISR_IP; 5027055Sdg break; 5037055Sdg 5047055Sdg case ETHERTYPE_ARP: 50578295Sjlemon if (ifp->if_flags & IFF_NOARP) 50678295Sjlemon goto dropanyway; 507111888Sjlemon isr = NETISR_ARP; 5087055Sdg break; 5097055Sdg#endif 51054263Sshin#ifdef INET6 51154263Sshin case ETHERTYPE_IPV6: 512111888Sjlemon isr = NETISR_IPV6; 51354263Sshin break; 51454263Sshin#endif 51521830Sjoerg#ifdef IPX 51621830Sjoerg case ETHERTYPE_IPX: 517111888Sjlemon isr = NETISR_IPX; 51821830Sjoerg break; 51921830Sjoerg#endif 5207055Sdg#ifdef DECNET 52121830Sjoerg case ETHERTYPE_DECNET: 522111888Sjlemon isr = NETISR_DECNET; 5237055Sdg break; 5247055Sdg#endif 52521830Sjoerg#ifdef NETATALK 52621830Sjoerg case ETHERTYPE_AT: 527111888Sjlemon isr = NETISR_ATALK1; 52821830Sjoerg break; 52921830Sjoerg case ETHERTYPE_AARP: 530111888Sjlemon isr = NETISR_AARP; 531111888Sjlemon break; 53221830Sjoerg#endif /* NETATALK */ 5337055Sdg default: 53421830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 5357055Sdg ifp->if_noproto++; 5367055Sdg goto dropanyway; 5377055Sdg } 5387055Sdg break; 5397055Sdg } 54021830Sjoerg 5417055Sdg default: 54221830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 5437055Sdg ifp->if_noproto++; 54493377Smdodd goto dropanyway; 5457055Sdg } 546111888Sjlemon netisr_dispatch(isr, m); 54793377Smdodd return; 54893377Smdodd 54993377Smdodddropanyway: 55093377Smdodd ifp->if_iqdrops++; 55193377Smdodd if (m) 55293377Smdodd m_freem(m); 55393377Smdodd return; 5547055Sdg} 55593380Smdodd 5567055Sdg/* 5577055Sdg * Perform common duties while attaching to interface list 5587055Sdg */ 5597055Sdgvoid 560152296Srufddi_ifattach(ifp, lla, bpf) 56193367Smdodd struct ifnet *ifp; 562152296Sru const u_int8_t *lla; 56393383Smdodd int bpf; 5647055Sdg{ 56593367Smdodd struct ifaddr *ifa; 56693367Smdodd struct sockaddr_dl *sdl; 5677055Sdg 5687055Sdg ifp->if_type = IFT_FDDI; 56993373Smdodd ifp->if_addrlen = FDDI_ADDR_LEN; 5707055Sdg ifp->if_hdrlen = 21; 57193379Smdodd 57293379Smdodd if_attach(ifp); /* Must be called before additional assignments */ 57393379Smdodd 5747055Sdg ifp->if_mtu = FDDIMTU; 57593379Smdodd ifp->if_output = fddi_output; 576106939Ssam ifp->if_input = fddi_input; 57768180Sume ifp->if_resolvemulti = fddi_resolvemulti; 57893379Smdodd ifp->if_broadcastaddr = fddibroadcastaddr; 57916063Sgpalmer ifp->if_baudrate = 100000000; 58021830Sjoerg#ifdef IFF_NOTRAILERS 58121830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 58221830Sjoerg#endif 583152315Sru ifa = ifp->if_addr; 584152315Sru KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 58593379Smdodd 58621831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 58721831Sjoerg sdl->sdl_type = IFT_FDDI; 58821831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 589152296Sru bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 59093379Smdodd 59193383Smdodd if (bpf) 59293383Smdodd bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); 59393383Smdodd 59493379Smdodd return; 5957055Sdg} 59668180Sume 59793382Smdoddvoid 59893382Smdoddfddi_ifdetach(ifp, bpf) 59993382Smdodd struct ifnet *ifp; 60093382Smdodd int bpf; 60193382Smdodd{ 60293382Smdodd 60393382Smdodd if (bpf) 60493382Smdodd bpfdetach(ifp); 60593382Smdodd 60693382Smdodd if_detach(ifp); 60793382Smdodd 60893382Smdodd return; 60993382Smdodd} 61093382Smdodd 61193382Smdoddint 61293382Smdoddfddi_ioctl (ifp, command, data) 61393382Smdodd struct ifnet *ifp; 61493382Smdodd int command; 61593382Smdodd caddr_t data; 61693382Smdodd{ 61793382Smdodd struct ifaddr *ifa; 61893382Smdodd struct ifreq *ifr; 61993382Smdodd int error; 62093382Smdodd 62193382Smdodd ifa = (struct ifaddr *) data; 62293382Smdodd ifr = (struct ifreq *) data; 62393382Smdodd error = 0; 62493382Smdodd 62593382Smdodd switch (command) { 62693382Smdodd case SIOCSIFADDR: 62793382Smdodd ifp->if_flags |= IFF_UP; 62893382Smdodd 62993382Smdodd switch (ifa->ifa_addr->sa_family) { 63093382Smdodd#ifdef INET 63193382Smdodd case AF_INET: /* before arpwhohas */ 63293382Smdodd ifp->if_init(ifp->if_softc); 63393382Smdodd arp_ifinit(ifp, ifa); 63493382Smdodd break; 63593382Smdodd#endif 63693382Smdodd#ifdef IPX 63793382Smdodd /* 63893382Smdodd * XXX - This code is probably wrong 63993382Smdodd */ 64093382Smdodd case AF_IPX: { 64193382Smdodd struct ipx_addr *ina; 64293382Smdodd 64393382Smdodd ina = &(IA_SIPX(ifa)->sipx_addr); 64493382Smdodd 64593382Smdodd if (ipx_nullhost(*ina)) { 64693382Smdodd ina->x_host = *(union ipx_host *) 647152315Sru IF_LLADDR(ifp); 64893382Smdodd } else { 64993382Smdodd bcopy((caddr_t) ina->x_host.c_host, 650152315Sru (caddr_t) IF_LLADDR(ifp), 651147256Sbrooks ETHER_ADDR_LEN); 65293382Smdodd } 65393382Smdodd 65493382Smdodd /* 65593382Smdodd * Set new address 65693382Smdodd */ 65793382Smdodd ifp->if_init(ifp->if_softc); 65893382Smdodd } 65993382Smdodd break; 66093382Smdodd#endif 66193382Smdodd default: 66293382Smdodd ifp->if_init(ifp->if_softc); 66393382Smdodd break; 664104302Sphk } 665144045Smdodd break; 66693382Smdodd case SIOCGIFADDR: { 66793382Smdodd struct sockaddr *sa; 66893382Smdodd 66993382Smdodd sa = (struct sockaddr *) & ifr->ifr_data; 670152315Sru bcopy(IF_LLADDR(ifp), 67193382Smdodd (caddr_t) sa->sa_data, FDDI_ADDR_LEN); 67293382Smdodd 67393382Smdodd } 67493382Smdodd break; 67593382Smdodd case SIOCSIFMTU: 67693382Smdodd /* 67793382Smdodd * Set the interface MTU. 67893382Smdodd */ 67993382Smdodd if (ifr->ifr_mtu > FDDIMTU) { 68093382Smdodd error = EINVAL; 68193382Smdodd } else { 68293382Smdodd ifp->if_mtu = ifr->ifr_mtu; 68393382Smdodd } 68493382Smdodd break; 68593382Smdodd default: 686144045Smdodd error = EINVAL; 68793382Smdodd break; 68893382Smdodd } 68993382Smdodd 69093382Smdodd return (error); 69193382Smdodd} 69293382Smdodd 69368180Sumestatic int 69468180Sumefddi_resolvemulti(ifp, llsa, sa) 69568180Sume struct ifnet *ifp; 69668180Sume struct sockaddr **llsa; 69768180Sume struct sockaddr *sa; 69868180Sume{ 69968180Sume struct sockaddr_dl *sdl; 70068180Sume struct sockaddr_in *sin; 70168180Sume#ifdef INET6 70268180Sume struct sockaddr_in6 *sin6; 70368180Sume#endif 70468180Sume u_char *e_addr; 70568180Sume 70668180Sume switch(sa->sa_family) { 70768180Sume case AF_LINK: 70868180Sume /* 70968180Sume * No mapping needed. Just check that it's a valid MC address. 71068180Sume */ 71168180Sume sdl = (struct sockaddr_dl *)sa; 71268180Sume e_addr = LLADDR(sdl); 71368180Sume if ((e_addr[0] & 1) != 1) 71493369Smdodd return (EADDRNOTAVAIL); 71568180Sume *llsa = 0; 71693369Smdodd return (0); 71768180Sume 71868180Sume#ifdef INET 71968180Sume case AF_INET: 72068180Sume sin = (struct sockaddr_in *)sa; 72168180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 72293369Smdodd return (EADDRNOTAVAIL); 72368180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 724148641Srwatson M_NOWAIT | M_ZERO); 725148641Srwatson if (sdl == NULL) 726148641Srwatson return (ENOMEM); 72768180Sume sdl->sdl_len = sizeof *sdl; 72868180Sume sdl->sdl_family = AF_LINK; 72968180Sume sdl->sdl_index = ifp->if_index; 73068180Sume sdl->sdl_type = IFT_FDDI; 73168180Sume sdl->sdl_nlen = 0; 73293375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 73368180Sume sdl->sdl_slen = 0; 73468180Sume e_addr = LLADDR(sdl); 73568180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 73668180Sume *llsa = (struct sockaddr *)sdl; 73793369Smdodd return (0); 73868180Sume#endif 73968180Sume#ifdef INET6 74068180Sume case AF_INET6: 74168180Sume sin6 = (struct sockaddr_in6 *)sa; 74268180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 74368180Sume /* 74468180Sume * An IP6 address of 0 means listen to all 74568180Sume * of the Ethernet multicast address used for IP6. 74668180Sume * (This is used for multicast routers.) 74768180Sume */ 74868180Sume ifp->if_flags |= IFF_ALLMULTI; 74968180Sume *llsa = 0; 75093369Smdodd return (0); 75168180Sume } 75268180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 75393369Smdodd return (EADDRNOTAVAIL); 75468180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 755148641Srwatson M_NOWAIT | M_ZERO); 756148641Srwatson if (sdl == NULL) 757148641Srwatson return (ENOMEM); 75868180Sume sdl->sdl_len = sizeof *sdl; 75968180Sume sdl->sdl_family = AF_LINK; 76068180Sume sdl->sdl_index = ifp->if_index; 76168180Sume sdl->sdl_type = IFT_FDDI; 76268180Sume sdl->sdl_nlen = 0; 76393375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 76468180Sume sdl->sdl_slen = 0; 76568180Sume e_addr = LLADDR(sdl); 76668180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 76768180Sume *llsa = (struct sockaddr *)sdl; 76893369Smdodd return (0); 76968180Sume#endif 77068180Sume 77168180Sume default: 77268180Sume /* 77368180Sume * Well, the text isn't quite right, but it's the name 77468180Sume * that counts... 77568180Sume */ 77693369Smdodd return (EAFNOSUPPORT); 77768180Sume } 77893375Smdodd 77993375Smdodd return (0); 78068180Sume} 78193375Smdodd 78293375Smdoddstatic moduledata_t fddi_mod = { 78393375Smdodd "fddi", /* module name */ 78493375Smdodd NULL, /* event handler */ 78593375Smdodd 0 /* extra data */ 78693375Smdodd}; 78793375Smdodd 78893375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 78993375SmdoddMODULE_VERSION(fddi, 1); 790