if_fddisubr.c revision 177599
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 177599 2008-03-25 09:39:02Z ru $ 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 124172930Srwatson error = mac_ifnet_check_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 207177599Sru M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAIT); 20821830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 20921830Sjoerg llc.llc_control = LLC_UI; 21093371Smdodd bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 21193371Smdodd llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 21293373Smdodd bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 21321830Sjoerg type = 0; 21421830Sjoerg } else { 21521830Sjoerg type = htons(ETHERTYPE_AT); 21621830Sjoerg } 21721830Sjoerg break; 21821830Sjoerg } 21921830Sjoerg#endif /* NETATALK */ 2207055Sdg 22152248Smsmith case pseudo_AF_HDRCMPLT: 22252248Smsmith { 22393376Smdodd struct ether_header *eh; 22452248Smsmith hdrcmplt = 1; 22593376Smdodd eh = (struct ether_header *)dst->sa_data; 22693376Smdodd bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 22752248Smsmith /* FALLTHROUGH */ 22852248Smsmith } 22952248Smsmith 2307055Sdg case AF_UNSPEC: 2317055Sdg { 2327055Sdg struct ether_header *eh; 23336992Sjulian loop_copy = -1; 2347055Sdg eh = (struct ether_header *)dst->sa_data; 23593375Smdodd bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 2367055Sdg if (*edst & 1) 2377055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2387055Sdg type = eh->ether_type; 2397055Sdg break; 2407055Sdg } 2417055Sdg 2427055Sdg case AF_IMPLINK: 2437055Sdg { 2447055Sdg fh = mtod(m, struct fddi_header *); 2457055Sdg error = EPROTONOSUPPORT; 2467055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2477055Sdg case FDDIFC_LLC_ASYNC: { 2487055Sdg /* legal priorities are 0 through 7 */ 2497055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2507055Sdg goto bad; 2517055Sdg break; 2527055Sdg } 2537055Sdg case FDDIFC_LLC_SYNC: { 2547055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2557055Sdg if (fh->fddi_fc & FDDIFC_Z) 2567055Sdg goto bad; 2577055Sdg break; 2587055Sdg } 2597055Sdg case FDDIFC_SMT: { 2607055Sdg /* FDDIFC_Z bits must be non zero */ 2617055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2627055Sdg goto bad; 2637055Sdg break; 2647055Sdg } 2657055Sdg default: { 2667055Sdg /* anything else is too dangerous */ 2677055Sdg goto bad; 2687055Sdg } 2697055Sdg } 2707055Sdg error = 0; 2717055Sdg if (fh->fddi_dhost[0] & 1) 2727055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2737055Sdg goto queue_it; 2747055Sdg } 2757055Sdg default: 276105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 2777055Sdg senderr(EAFNOSUPPORT); 2787055Sdg } 2797055Sdg 28093380Smdodd /* 28193380Smdodd * Add LLC header. 28293380Smdodd */ 2837055Sdg if (type != 0) { 28493367Smdodd struct llc *l; 285111119Simp M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 2867055Sdg if (m == 0) 2877055Sdg senderr(ENOBUFS); 2887055Sdg l = mtod(m, struct llc *); 2897055Sdg l->llc_control = LLC_UI; 2907055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 291112266Smdodd l->llc_snap.org_code[0] = 292112266Smdodd l->llc_snap.org_code[1] = 293112266Smdodd l->llc_snap.org_code[2] = 0; 294112266Smdodd l->llc_snap.ether_type = htons(type); 2957055Sdg } 29636908Sjulian 2977055Sdg /* 2987055Sdg * Add local net header. If no space in first mbuf, 2997055Sdg * allocate another. 3007055Sdg */ 301111119Simp M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 3027055Sdg if (m == 0) 3037055Sdg senderr(ENOBUFS); 3047055Sdg fh = mtod(m, struct fddi_header *); 3057055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 30693375Smdodd bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 3077055Sdg queue_it: 30852248Smsmith if (hdrcmplt) 30993375Smdodd bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 31052248Smsmith else 311152315Sru bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost, 31293373Smdodd FDDI_ADDR_LEN); 31393377Smdodd 31436908Sjulian /* 31536908Sjulian * If a simplex interface, and the packet is being sent to our 31636908Sjulian * Ethernet address or a broadcast address, loopback a copy. 31736908Sjulian * XXX To make a simplex device behave exactly like a duplex 31836908Sjulian * device, we should copy in the case of sending to our own 31936908Sjulian * ethernet address (thus letting the original actually appear 32036908Sjulian * on the wire). However, we don't do that here for security 32136908Sjulian * reasons and compatibility with the original behavior. 32236908Sjulian */ 32393377Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 324112279Smdodd if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 325112279Smdodd struct mbuf *n; 326112279Smdodd n = m_copy(m, 0, (int)M_COPYALL); 327112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 328112279Smdodd FDDI_HDR_LEN); 329112279Smdodd } else if (bcmp(fh->fddi_dhost, fh->fddi_shost, 330112279Smdodd FDDI_ADDR_LEN) == 0) { 331112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 332112279Smdodd FDDI_HDR_LEN); 33393369Smdodd return (0); /* XXX */ 33436908Sjulian } 33536908Sjulian } 33636908Sjulian 337130549Smlaier IFQ_HANDOFF(ifp, m, error); 338130549Smlaier if (error) 339130549Smlaier ifp->if_oerrors++; 340130549Smlaier 3417055Sdg return (error); 3427055Sdg 3437055Sdgbad: 34493379Smdodd ifp->if_oerrors++; 3457055Sdg if (m) 3467055Sdg m_freem(m); 3477055Sdg return (error); 3487055Sdg} 3497055Sdg 3507055Sdg/* 351112308Smdodd * Process a received FDDI packet. 3527055Sdg */ 353106939Ssamstatic void 354106939Ssamfddi_input(ifp, m) 3557055Sdg struct ifnet *ifp; 3567055Sdg struct mbuf *m; 3577055Sdg{ 358111888Sjlemon int isr; 35993367Smdodd struct llc *l; 360106939Ssam struct fddi_header *fh; 3617055Sdg 362112308Smdodd /* 363112308Smdodd * Do consistency checks to verify assumptions 364112308Smdodd * made by code past this point. 365112308Smdodd */ 366112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 367112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 368112308Smdodd ifp->if_ierrors++; 369112308Smdodd m_freem(m); 370112308Smdodd return; 371112308Smdodd } 372112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 373112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 374112308Smdodd ifp->if_ierrors++; 375112308Smdodd m_freem(m); 376112308Smdodd return; 377112308Smdodd } 378112308Smdodd 379112308Smdodd m = m_pullup(m, FDDI_HDR_LEN); 380112308Smdodd if (m == NULL) { 381112308Smdodd ifp->if_ierrors++; 382112308Smdodd goto dropanyway; 383112308Smdodd } 384106939Ssam fh = mtod(m, struct fddi_header *); 385112308Smdodd m->m_pkthdr.header = (void *)fh; 386106939Ssam 38793379Smdodd /* 38893379Smdodd * Discard packet if interface is not up. 38993379Smdodd */ 390148887Srwatson if (!((ifp->if_flags & IFF_UP) && 391148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 39293379Smdodd goto dropanyway; 39393379Smdodd 394112308Smdodd /* 395112308Smdodd * Give bpf a chance at the packet. 396112308Smdodd */ 397112308Smdodd BPF_MTAP(ifp, m); 398112308Smdodd 399112308Smdodd /* 400112308Smdodd * Interface marked for monitoring; discard packet. 401112308Smdodd */ 402112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 403112308Smdodd m_freem(m); 404112308Smdodd return; 405112308Smdodd } 406112308Smdodd 407105577Srwatson#ifdef MAC 408172930Srwatson mac_ifnet_create_mbuf(ifp, m); 409105577Srwatson#endif 410105577Srwatson 41193379Smdodd /* 412112287Smdodd * Update interface statistics. 413112287Smdodd */ 414112287Smdodd ifp->if_ibytes += m->m_pkthdr.len; 415112287Smdodd getmicrotime(&ifp->if_lastchange); 416112287Smdodd 417112287Smdodd /* 41893379Smdodd * Discard non local unicast packets when interface 41993379Smdodd * is in promiscuous mode. 42093379Smdodd */ 42193379Smdodd if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 422152315Sru (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost, 42393379Smdodd FDDI_ADDR_LEN) != 0)) 42493379Smdodd goto dropanyway; 42593379Smdodd 42693379Smdodd /* 42793379Smdodd * Set mbuf flags for bcast/mcast. 42893379Smdodd */ 42921830Sjoerg if (fh->fddi_dhost[0] & 1) { 430121436Simp if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost, 431121436Simp FDDI_ADDR_LEN) == 0) 43221830Sjoerg m->m_flags |= M_BCAST; 43321830Sjoerg else 43421830Sjoerg m->m_flags |= M_MCAST; 4357055Sdg ifp->if_imcasts++; 43621830Sjoerg } 4377055Sdg 43821830Sjoerg#ifdef M_LINK0 43921830Sjoerg /* 44021830Sjoerg * If this has a LLC priority of 0, then mark it so upper 44121830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 44221830Sjoerg * bridge. 44321830Sjoerg */ 44421830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 44521830Sjoerg m->m_flags |= M_LINK0; 44621830Sjoerg#endif 44721830Sjoerg 448106939Ssam /* Strip off FDDI header. */ 449111790Smdodd m_adj(m, FDDI_HDR_LEN); 450106939Ssam 451111790Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 45293379Smdodd if (m == 0) { 45393379Smdodd ifp->if_ierrors++; 45493379Smdodd goto dropanyway; 45593379Smdodd } 4567055Sdg l = mtod(m, struct llc *); 45793377Smdodd 4587055Sdg switch (l->llc_dsap) { 4597055Sdg case LLC_SNAP_LSAP: 4607055Sdg { 46121830Sjoerg u_int16_t type; 462112266Smdodd if ((l->llc_control != LLC_UI) || 463112266Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 46493379Smdodd ifp->if_noproto++; 4657055Sdg goto dropanyway; 46693379Smdodd } 46721830Sjoerg#ifdef NETATALK 468128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], at_org_code, 469111888Sjlemon sizeof(at_org_code)) == 0 && 470111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 471111888Sjlemon isr = NETISR_ATALK2; 472111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 473111888Sjlemon break; 47421830Sjoerg } 47521830Sjoerg 476128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 477111888Sjlemon sizeof(aarp_org_code)) == 0 && 478111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 479111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 480111888Sjlemon isr = NETISR_AARP; 481111888Sjlemon break; 48221830Sjoerg } 48321830Sjoerg#endif /* NETATALK */ 48493377Smdodd if (l->llc_snap.org_code[0] != 0 || 48593377Smdodd l->llc_snap.org_code[1] != 0 || 48693379Smdodd l->llc_snap.org_code[2] != 0) { 48793379Smdodd ifp->if_noproto++; 4887055Sdg goto dropanyway; 48993379Smdodd } 49093377Smdodd 49121830Sjoerg type = ntohs(l->llc_snap.ether_type); 49293377Smdodd m_adj(m, LLC_SNAPFRAMELEN); 49393377Smdodd 49421830Sjoerg switch (type) { 4957055Sdg#ifdef INET 4967055Sdg case ETHERTYPE_IP: 497154518Sandre if ((m = ip_fastforward(m)) == NULL) 49836192Sdg return; 499111888Sjlemon isr = NETISR_IP; 5007055Sdg break; 5017055Sdg 5027055Sdg case ETHERTYPE_ARP: 50378295Sjlemon if (ifp->if_flags & IFF_NOARP) 50478295Sjlemon goto dropanyway; 505111888Sjlemon isr = NETISR_ARP; 5067055Sdg break; 5077055Sdg#endif 50854263Sshin#ifdef INET6 50954263Sshin case ETHERTYPE_IPV6: 510111888Sjlemon isr = NETISR_IPV6; 51154263Sshin break; 51254263Sshin#endif 51321830Sjoerg#ifdef IPX 51421830Sjoerg case ETHERTYPE_IPX: 515111888Sjlemon isr = NETISR_IPX; 51621830Sjoerg break; 51721830Sjoerg#endif 5187055Sdg#ifdef DECNET 51921830Sjoerg case ETHERTYPE_DECNET: 520111888Sjlemon isr = NETISR_DECNET; 5217055Sdg break; 5227055Sdg#endif 52321830Sjoerg#ifdef NETATALK 52421830Sjoerg case ETHERTYPE_AT: 525111888Sjlemon isr = NETISR_ATALK1; 52621830Sjoerg break; 52721830Sjoerg case ETHERTYPE_AARP: 528111888Sjlemon isr = NETISR_AARP; 529111888Sjlemon break; 53021830Sjoerg#endif /* NETATALK */ 5317055Sdg default: 53221830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 5337055Sdg ifp->if_noproto++; 5347055Sdg goto dropanyway; 5357055Sdg } 5367055Sdg break; 5377055Sdg } 53821830Sjoerg 5397055Sdg default: 54021830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 5417055Sdg ifp->if_noproto++; 54293377Smdodd goto dropanyway; 5437055Sdg } 544111888Sjlemon netisr_dispatch(isr, m); 54593377Smdodd return; 54693377Smdodd 54793377Smdodddropanyway: 54893377Smdodd ifp->if_iqdrops++; 54993377Smdodd if (m) 55093377Smdodd m_freem(m); 55193377Smdodd return; 5527055Sdg} 55393380Smdodd 5547055Sdg/* 5557055Sdg * Perform common duties while attaching to interface list 5567055Sdg */ 5577055Sdgvoid 558152296Srufddi_ifattach(ifp, lla, bpf) 55993367Smdodd struct ifnet *ifp; 560152296Sru const u_int8_t *lla; 56193383Smdodd int bpf; 5627055Sdg{ 56393367Smdodd struct ifaddr *ifa; 56493367Smdodd struct sockaddr_dl *sdl; 5657055Sdg 5667055Sdg ifp->if_type = IFT_FDDI; 56793373Smdodd ifp->if_addrlen = FDDI_ADDR_LEN; 5687055Sdg ifp->if_hdrlen = 21; 56993379Smdodd 57093379Smdodd if_attach(ifp); /* Must be called before additional assignments */ 57193379Smdodd 5727055Sdg ifp->if_mtu = FDDIMTU; 57393379Smdodd ifp->if_output = fddi_output; 574106939Ssam ifp->if_input = fddi_input; 57568180Sume ifp->if_resolvemulti = fddi_resolvemulti; 57693379Smdodd ifp->if_broadcastaddr = fddibroadcastaddr; 57716063Sgpalmer ifp->if_baudrate = 100000000; 57821830Sjoerg#ifdef IFF_NOTRAILERS 57921830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 58021830Sjoerg#endif 581152315Sru ifa = ifp->if_addr; 582152315Sru KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 58393379Smdodd 58421831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 58521831Sjoerg sdl->sdl_type = IFT_FDDI; 58621831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 587152296Sru bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 58893379Smdodd 58993383Smdodd if (bpf) 59093383Smdodd bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); 59193383Smdodd 59293379Smdodd return; 5937055Sdg} 59468180Sume 59593382Smdoddvoid 59693382Smdoddfddi_ifdetach(ifp, bpf) 59793382Smdodd struct ifnet *ifp; 59893382Smdodd int bpf; 59993382Smdodd{ 60093382Smdodd 60193382Smdodd if (bpf) 60293382Smdodd bpfdetach(ifp); 60393382Smdodd 60493382Smdodd if_detach(ifp); 60593382Smdodd 60693382Smdodd return; 60793382Smdodd} 60893382Smdodd 60993382Smdoddint 61093382Smdoddfddi_ioctl (ifp, command, data) 61193382Smdodd struct ifnet *ifp; 61293382Smdodd int command; 61393382Smdodd caddr_t data; 61493382Smdodd{ 61593382Smdodd struct ifaddr *ifa; 61693382Smdodd struct ifreq *ifr; 61793382Smdodd int error; 61893382Smdodd 61993382Smdodd ifa = (struct ifaddr *) data; 62093382Smdodd ifr = (struct ifreq *) data; 62193382Smdodd error = 0; 62293382Smdodd 62393382Smdodd switch (command) { 62493382Smdodd case SIOCSIFADDR: 62593382Smdodd ifp->if_flags |= IFF_UP; 62693382Smdodd 62793382Smdodd switch (ifa->ifa_addr->sa_family) { 62893382Smdodd#ifdef INET 62993382Smdodd case AF_INET: /* before arpwhohas */ 63093382Smdodd ifp->if_init(ifp->if_softc); 63193382Smdodd arp_ifinit(ifp, ifa); 63293382Smdodd break; 63393382Smdodd#endif 63493382Smdodd#ifdef IPX 63593382Smdodd /* 63693382Smdodd * XXX - This code is probably wrong 63793382Smdodd */ 63893382Smdodd case AF_IPX: { 63993382Smdodd struct ipx_addr *ina; 64093382Smdodd 64193382Smdodd ina = &(IA_SIPX(ifa)->sipx_addr); 64293382Smdodd 64393382Smdodd if (ipx_nullhost(*ina)) { 64493382Smdodd ina->x_host = *(union ipx_host *) 645152315Sru IF_LLADDR(ifp); 64693382Smdodd } else { 64793382Smdodd bcopy((caddr_t) ina->x_host.c_host, 648152315Sru (caddr_t) IF_LLADDR(ifp), 649147256Sbrooks ETHER_ADDR_LEN); 65093382Smdodd } 65193382Smdodd 65293382Smdodd /* 65393382Smdodd * Set new address 65493382Smdodd */ 65593382Smdodd ifp->if_init(ifp->if_softc); 65693382Smdodd } 65793382Smdodd break; 65893382Smdodd#endif 65993382Smdodd default: 66093382Smdodd ifp->if_init(ifp->if_softc); 66193382Smdodd break; 662104302Sphk } 663144045Smdodd break; 66493382Smdodd case SIOCGIFADDR: { 66593382Smdodd struct sockaddr *sa; 66693382Smdodd 66793382Smdodd sa = (struct sockaddr *) & ifr->ifr_data; 668152315Sru bcopy(IF_LLADDR(ifp), 66993382Smdodd (caddr_t) sa->sa_data, FDDI_ADDR_LEN); 67093382Smdodd 67193382Smdodd } 67293382Smdodd break; 67393382Smdodd case SIOCSIFMTU: 67493382Smdodd /* 67593382Smdodd * Set the interface MTU. 67693382Smdodd */ 67793382Smdodd if (ifr->ifr_mtu > FDDIMTU) { 67893382Smdodd error = EINVAL; 67993382Smdodd } else { 68093382Smdodd ifp->if_mtu = ifr->ifr_mtu; 68193382Smdodd } 68293382Smdodd break; 68393382Smdodd default: 684144045Smdodd error = EINVAL; 68593382Smdodd break; 68693382Smdodd } 68793382Smdodd 68893382Smdodd return (error); 68993382Smdodd} 69093382Smdodd 69168180Sumestatic int 69268180Sumefddi_resolvemulti(ifp, llsa, sa) 69368180Sume struct ifnet *ifp; 69468180Sume struct sockaddr **llsa; 69568180Sume struct sockaddr *sa; 69668180Sume{ 69768180Sume struct sockaddr_dl *sdl; 69868180Sume struct sockaddr_in *sin; 69968180Sume#ifdef INET6 70068180Sume struct sockaddr_in6 *sin6; 70168180Sume#endif 70268180Sume u_char *e_addr; 70368180Sume 70468180Sume switch(sa->sa_family) { 70568180Sume case AF_LINK: 70668180Sume /* 70768180Sume * No mapping needed. Just check that it's a valid MC address. 70868180Sume */ 70968180Sume sdl = (struct sockaddr_dl *)sa; 71068180Sume e_addr = LLADDR(sdl); 71168180Sume if ((e_addr[0] & 1) != 1) 71293369Smdodd return (EADDRNOTAVAIL); 71368180Sume *llsa = 0; 71493369Smdodd return (0); 71568180Sume 71668180Sume#ifdef INET 71768180Sume case AF_INET: 71868180Sume sin = (struct sockaddr_in *)sa; 71968180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 72093369Smdodd return (EADDRNOTAVAIL); 72168180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 722148641Srwatson M_NOWAIT | M_ZERO); 723148641Srwatson if (sdl == NULL) 724148641Srwatson return (ENOMEM); 72568180Sume sdl->sdl_len = sizeof *sdl; 72668180Sume sdl->sdl_family = AF_LINK; 72768180Sume sdl->sdl_index = ifp->if_index; 72868180Sume sdl->sdl_type = IFT_FDDI; 72968180Sume sdl->sdl_nlen = 0; 73093375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 73168180Sume sdl->sdl_slen = 0; 73268180Sume e_addr = LLADDR(sdl); 73368180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 73468180Sume *llsa = (struct sockaddr *)sdl; 73593369Smdodd return (0); 73668180Sume#endif 73768180Sume#ifdef INET6 73868180Sume case AF_INET6: 73968180Sume sin6 = (struct sockaddr_in6 *)sa; 74068180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 74168180Sume /* 74268180Sume * An IP6 address of 0 means listen to all 74368180Sume * of the Ethernet multicast address used for IP6. 74468180Sume * (This is used for multicast routers.) 74568180Sume */ 74668180Sume ifp->if_flags |= IFF_ALLMULTI; 74768180Sume *llsa = 0; 74893369Smdodd return (0); 74968180Sume } 75068180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 75193369Smdodd return (EADDRNOTAVAIL); 75268180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 753148641Srwatson M_NOWAIT | M_ZERO); 754148641Srwatson if (sdl == NULL) 755148641Srwatson return (ENOMEM); 75668180Sume sdl->sdl_len = sizeof *sdl; 75768180Sume sdl->sdl_family = AF_LINK; 75868180Sume sdl->sdl_index = ifp->if_index; 75968180Sume sdl->sdl_type = IFT_FDDI; 76068180Sume sdl->sdl_nlen = 0; 76193375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 76268180Sume sdl->sdl_slen = 0; 76368180Sume e_addr = LLADDR(sdl); 76468180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 76568180Sume *llsa = (struct sockaddr *)sdl; 76693369Smdodd return (0); 76768180Sume#endif 76868180Sume 76968180Sume default: 77068180Sume /* 77168180Sume * Well, the text isn't quite right, but it's the name 77268180Sume * that counts... 77368180Sume */ 77493369Smdodd return (EAFNOSUPPORT); 77568180Sume } 77693375Smdodd 77793375Smdodd return (0); 77868180Sume} 77993375Smdodd 78093375Smdoddstatic moduledata_t fddi_mod = { 78193375Smdodd "fddi", /* module name */ 78293375Smdodd NULL, /* event handler */ 78393375Smdodd 0 /* extra data */ 78493375Smdodd}; 78593375Smdodd 78693375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 78793375SmdoddMODULE_VERSION(fddi, 1); 788