if_fddisubr.c revision 184709
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 184709 2008-11-06 09:07:56Z bz $ 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 59184709Sbz#include <net/ethernet.h> 6093375Smdodd#include <net/netisr.h> 6193375Smdodd#include <net/route.h> 6293375Smdodd#include <net/bpf.h> 6393373Smdodd#include <net/fddi.h> 647055Sdg 6554263Sshin#if defined(INET) || defined(INET6) 667055Sdg#include <netinet/in.h> 677055Sdg#include <netinet/in_var.h> 6832350Seivind#include <netinet/if_ether.h> 697055Sdg#endif 7054263Sshin#ifdef INET6 7154263Sshin#include <netinet6/nd6.h> 7254263Sshin#endif 737055Sdg 7411819Sjulian#ifdef IPX 7521830Sjoerg#include <netipx/ipx.h> 7611819Sjulian#include <netipx/ipx_if.h> 7711819Sjulian#endif 7811819Sjulian 797055Sdg#ifdef DECNET 807055Sdg#include <netdnet/dn.h> 817055Sdg#endif 827055Sdg 8321830Sjoerg#ifdef NETATALK 8421830Sjoerg#include <netatalk/at.h> 8521830Sjoerg#include <netatalk/at_var.h> 8621830Sjoerg#include <netatalk/at_extern.h> 8721830Sjoerg 8821830Sjoergextern u_char at_org_code[ 3 ]; 8921830Sjoergextern u_char aarp_org_code[ 3 ]; 9021830Sjoerg#endif /* NETATALK */ 9121830Sjoerg 92163606Srwatson#include <security/mac/mac_framework.h> 93163606Srwatson 94126788Srwatsonstatic const u_char fddibroadcastaddr[FDDI_ADDR_LEN] = 9593382Smdodd { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 9693382Smdodd 9793383Smdoddstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 9893084Sbde struct sockaddr *); 9993383Smdoddstatic int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *, 10093383Smdodd struct rtentry *); 101106939Ssamstatic void fddi_input(struct ifnet *ifp, struct mbuf *m); 10268180Sume 103112276Smdodd#define senderr(e) do { error = (e); goto bad; } while (0) 10493369Smdodd 1057055Sdg/* 1067055Sdg * FDDI output routine. 1077055Sdg * Encapsulate a packet of type family for the local net. 1087055Sdg * Use trailer local net encapsulation if enough data in first 1097055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1107055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1117055Sdg */ 11293383Smdoddstatic int 11354799Sgreenfddi_output(ifp, m, dst, rt0) 11493367Smdodd struct ifnet *ifp; 11554799Sgreen struct mbuf *m; 1167055Sdg struct sockaddr *dst; 1177055Sdg struct rtentry *rt0; 1187055Sdg{ 11921830Sjoerg u_int16_t type; 12069152Sjlemon int loop_copy = 0, error = 0, hdrcmplt = 0; 12193373Smdodd u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 12293367Smdodd struct fddi_header *fh; 1237055Sdg 124105577Srwatson#ifdef MAC 125172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 126105577Srwatson if (error) 127105577Srwatson senderr(error); 128105577Srwatson#endif 129105577Srwatson 130112308Smdodd if (ifp->if_flags & IFF_MONITOR) 131112308Smdodd senderr(ENETDOWN); 132148887Srwatson if (!((ifp->if_flags & IFF_UP) && 133148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 1347055Sdg senderr(ENETDOWN); 13534961Sphk getmicrotime(&ifp->if_lastchange); 136111767Smdodd 1377055Sdg switch (dst->sa_family) { 1387055Sdg#ifdef INET 13921830Sjoerg case AF_INET: { 140128636Sluigi error = arpresolve(ifp, rt0, m, dst, edst); 141128636Sluigi if (error) 142128636Sluigi return (error == EWOULDBLOCK ? 0 : error); 14321830Sjoerg type = htons(ETHERTYPE_IP); 1447055Sdg break; 14521830Sjoerg } 146126951Smdodd case AF_ARP: 147126951Smdodd { 148126951Smdodd struct arphdr *ah; 149126951Smdodd ah = mtod(m, struct arphdr *); 150126951Smdodd ah->ar_hrd = htons(ARPHRD_ETHER); 151126951Smdodd 152126951Smdodd loop_copy = -1; /* if this is for us, don't do it */ 153126951Smdodd 154126951Smdodd switch (ntohs(ah->ar_op)) { 155126951Smdodd case ARPOP_REVREQUEST: 156126951Smdodd case ARPOP_REVREPLY: 157126951Smdodd type = htons(ETHERTYPE_REVARP); 158126951Smdodd break; 159126951Smdodd case ARPOP_REQUEST: 160126951Smdodd case ARPOP_REPLY: 161126951Smdodd default: 162126951Smdodd type = htons(ETHERTYPE_ARP); 163126951Smdodd break; 164126951Smdodd } 165126951Smdodd 166126951Smdodd if (m->m_flags & M_BCAST) 167126951Smdodd bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN); 168126951Smdodd else 169126951Smdodd bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN); 170126951Smdodd 171126951Smdodd } 172126951Smdodd break; 173112266Smdodd#endif /* INET */ 17454263Sshin#ifdef INET6 17554263Sshin case AF_INET6: 176128636Sluigi error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); 177128636Sluigi if (error) 178128636Sluigi return (error); /* Something bad happened */ 17954263Sshin type = htons(ETHERTYPE_IPV6); 18054263Sshin break; 181112266Smdodd#endif /* INET6 */ 18211819Sjulian#ifdef IPX 18311819Sjulian case AF_IPX: 18421830Sjoerg type = htons(ETHERTYPE_IPX); 18511819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 18693373Smdodd (caddr_t)edst, FDDI_ADDR_LEN); 18711819Sjulian break; 188112266Smdodd#endif /* IPX */ 18921830Sjoerg#ifdef NETATALK 19021830Sjoerg case AF_APPLETALK: { 19121830Sjoerg struct at_ifaddr *aa; 192128636Sluigi if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst)) 19321830Sjoerg return (0); 19421830Sjoerg /* 19521830Sjoerg * ifaddr is the first thing in at_ifaddr 19621830Sjoerg */ 19730834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 19821830Sjoerg goto bad; 19921830Sjoerg 20021830Sjoerg /* 20121830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 20221830Sjoerg * Since we must preserve the value of m, which is passed to us by 20321830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 20421830Sjoerg */ 20521830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 20621830Sjoerg struct llc llc; 20721830Sjoerg 208177599Sru M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAIT); 20921830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 21021830Sjoerg llc.llc_control = LLC_UI; 21193371Smdodd bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 21293371Smdodd llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 21393373Smdodd bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 21421830Sjoerg type = 0; 21521830Sjoerg } else { 21621830Sjoerg type = htons(ETHERTYPE_AT); 21721830Sjoerg } 21821830Sjoerg break; 21921830Sjoerg } 22021830Sjoerg#endif /* NETATALK */ 2217055Sdg 22252248Smsmith case pseudo_AF_HDRCMPLT: 22352248Smsmith { 22493376Smdodd struct ether_header *eh; 22552248Smsmith hdrcmplt = 1; 22693376Smdodd eh = (struct ether_header *)dst->sa_data; 22793376Smdodd bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 22852248Smsmith /* FALLTHROUGH */ 22952248Smsmith } 23052248Smsmith 2317055Sdg case AF_UNSPEC: 2327055Sdg { 2337055Sdg struct ether_header *eh; 23436992Sjulian loop_copy = -1; 2357055Sdg eh = (struct ether_header *)dst->sa_data; 23693375Smdodd bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 2377055Sdg if (*edst & 1) 2387055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2397055Sdg type = eh->ether_type; 2407055Sdg break; 2417055Sdg } 2427055Sdg 2437055Sdg case AF_IMPLINK: 2447055Sdg { 2457055Sdg fh = mtod(m, struct fddi_header *); 2467055Sdg error = EPROTONOSUPPORT; 2477055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2487055Sdg case FDDIFC_LLC_ASYNC: { 2497055Sdg /* legal priorities are 0 through 7 */ 2507055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2517055Sdg goto bad; 2527055Sdg break; 2537055Sdg } 2547055Sdg case FDDIFC_LLC_SYNC: { 2557055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2567055Sdg if (fh->fddi_fc & FDDIFC_Z) 2577055Sdg goto bad; 2587055Sdg break; 2597055Sdg } 2607055Sdg case FDDIFC_SMT: { 2617055Sdg /* FDDIFC_Z bits must be non zero */ 2627055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2637055Sdg goto bad; 2647055Sdg break; 2657055Sdg } 2667055Sdg default: { 2677055Sdg /* anything else is too dangerous */ 2687055Sdg goto bad; 2697055Sdg } 2707055Sdg } 2717055Sdg error = 0; 2727055Sdg if (fh->fddi_dhost[0] & 1) 2737055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2747055Sdg goto queue_it; 2757055Sdg } 2767055Sdg default: 277105598Sbrooks if_printf(ifp, "can't handle af%d\n", dst->sa_family); 2787055Sdg senderr(EAFNOSUPPORT); 2797055Sdg } 2807055Sdg 28193380Smdodd /* 28293380Smdodd * Add LLC header. 28393380Smdodd */ 2847055Sdg if (type != 0) { 28593367Smdodd struct llc *l; 286111119Simp M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 2877055Sdg if (m == 0) 2887055Sdg senderr(ENOBUFS); 2897055Sdg l = mtod(m, struct llc *); 2907055Sdg l->llc_control = LLC_UI; 2917055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 292112266Smdodd l->llc_snap.org_code[0] = 293112266Smdodd l->llc_snap.org_code[1] = 294112266Smdodd l->llc_snap.org_code[2] = 0; 295112266Smdodd l->llc_snap.ether_type = htons(type); 2967055Sdg } 29736908Sjulian 2987055Sdg /* 2997055Sdg * Add local net header. If no space in first mbuf, 3007055Sdg * allocate another. 3017055Sdg */ 302111119Simp M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 3037055Sdg if (m == 0) 3047055Sdg senderr(ENOBUFS); 3057055Sdg fh = mtod(m, struct fddi_header *); 3067055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 30793375Smdodd bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 3087055Sdg queue_it: 30952248Smsmith if (hdrcmplt) 31093375Smdodd bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 31152248Smsmith else 312152315Sru bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost, 31393373Smdodd FDDI_ADDR_LEN); 31493377Smdodd 31536908Sjulian /* 31636908Sjulian * If a simplex interface, and the packet is being sent to our 31736908Sjulian * Ethernet address or a broadcast address, loopback a copy. 31836908Sjulian * XXX To make a simplex device behave exactly like a duplex 31936908Sjulian * device, we should copy in the case of sending to our own 32036908Sjulian * ethernet address (thus letting the original actually appear 32136908Sjulian * on the wire). However, we don't do that here for security 32236908Sjulian * reasons and compatibility with the original behavior. 32336908Sjulian */ 32493377Smdodd if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 325112279Smdodd if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 326112279Smdodd struct mbuf *n; 327112279Smdodd n = m_copy(m, 0, (int)M_COPYALL); 328112279Smdodd (void) if_simloop(ifp, n, dst->sa_family, 329112279Smdodd FDDI_HDR_LEN); 330112279Smdodd } else if (bcmp(fh->fddi_dhost, fh->fddi_shost, 331112279Smdodd FDDI_ADDR_LEN) == 0) { 332112279Smdodd (void) if_simloop(ifp, m, dst->sa_family, 333112279Smdodd FDDI_HDR_LEN); 33493369Smdodd return (0); /* XXX */ 33536908Sjulian } 33636908Sjulian } 33736908Sjulian 338130549Smlaier IFQ_HANDOFF(ifp, m, error); 339130549Smlaier if (error) 340130549Smlaier ifp->if_oerrors++; 341130549Smlaier 3427055Sdg return (error); 3437055Sdg 3447055Sdgbad: 34593379Smdodd ifp->if_oerrors++; 3467055Sdg if (m) 3477055Sdg m_freem(m); 3487055Sdg return (error); 3497055Sdg} 3507055Sdg 3517055Sdg/* 352112308Smdodd * Process a received FDDI packet. 3537055Sdg */ 354106939Ssamstatic void 355106939Ssamfddi_input(ifp, m) 3567055Sdg struct ifnet *ifp; 3577055Sdg struct mbuf *m; 3587055Sdg{ 359111888Sjlemon int isr; 36093367Smdodd struct llc *l; 361106939Ssam struct fddi_header *fh; 3627055Sdg 363112308Smdodd /* 364112308Smdodd * Do consistency checks to verify assumptions 365112308Smdodd * made by code past this point. 366112308Smdodd */ 367112308Smdodd if ((m->m_flags & M_PKTHDR) == 0) { 368112308Smdodd if_printf(ifp, "discard frame w/o packet header\n"); 369112308Smdodd ifp->if_ierrors++; 370112308Smdodd m_freem(m); 371112308Smdodd return; 372112308Smdodd } 373112308Smdodd if (m->m_pkthdr.rcvif == NULL) { 374112308Smdodd if_printf(ifp, "discard frame w/o interface pointer\n"); 375112308Smdodd ifp->if_ierrors++; 376112308Smdodd m_freem(m); 377112308Smdodd return; 378112308Smdodd } 379112308Smdodd 380112308Smdodd m = m_pullup(m, FDDI_HDR_LEN); 381112308Smdodd if (m == NULL) { 382112308Smdodd ifp->if_ierrors++; 383112308Smdodd goto dropanyway; 384112308Smdodd } 385106939Ssam fh = mtod(m, struct fddi_header *); 386112308Smdodd m->m_pkthdr.header = (void *)fh; 387106939Ssam 38893379Smdodd /* 38993379Smdodd * Discard packet if interface is not up. 39093379Smdodd */ 391148887Srwatson if (!((ifp->if_flags & IFF_UP) && 392148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) 39393379Smdodd goto dropanyway; 39493379Smdodd 395112308Smdodd /* 396112308Smdodd * Give bpf a chance at the packet. 397112308Smdodd */ 398112308Smdodd BPF_MTAP(ifp, m); 399112308Smdodd 400112308Smdodd /* 401112308Smdodd * Interface marked for monitoring; discard packet. 402112308Smdodd */ 403112308Smdodd if (ifp->if_flags & IFF_MONITOR) { 404112308Smdodd m_freem(m); 405112308Smdodd return; 406112308Smdodd } 407112308Smdodd 408105577Srwatson#ifdef MAC 409172930Srwatson mac_ifnet_create_mbuf(ifp, m); 410105577Srwatson#endif 411105577Srwatson 41293379Smdodd /* 413112287Smdodd * Update interface statistics. 414112287Smdodd */ 415112287Smdodd ifp->if_ibytes += m->m_pkthdr.len; 416112287Smdodd getmicrotime(&ifp->if_lastchange); 417112287Smdodd 418112287Smdodd /* 41993379Smdodd * Discard non local unicast packets when interface 42093379Smdodd * is in promiscuous mode. 42193379Smdodd */ 42293379Smdodd if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 423152315Sru (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost, 42493379Smdodd FDDI_ADDR_LEN) != 0)) 42593379Smdodd goto dropanyway; 42693379Smdodd 42793379Smdodd /* 42893379Smdodd * Set mbuf flags for bcast/mcast. 42993379Smdodd */ 43021830Sjoerg if (fh->fddi_dhost[0] & 1) { 431121436Simp if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost, 432121436Simp FDDI_ADDR_LEN) == 0) 43321830Sjoerg m->m_flags |= M_BCAST; 43421830Sjoerg else 43521830Sjoerg m->m_flags |= M_MCAST; 4367055Sdg ifp->if_imcasts++; 43721830Sjoerg } 4387055Sdg 43921830Sjoerg#ifdef M_LINK0 44021830Sjoerg /* 44121830Sjoerg * If this has a LLC priority of 0, then mark it so upper 44221830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 44321830Sjoerg * bridge. 44421830Sjoerg */ 44521830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 44621830Sjoerg m->m_flags |= M_LINK0; 44721830Sjoerg#endif 44821830Sjoerg 449106939Ssam /* Strip off FDDI header. */ 450111790Smdodd m_adj(m, FDDI_HDR_LEN); 451106939Ssam 452111790Smdodd m = m_pullup(m, LLC_SNAPFRAMELEN); 45393379Smdodd if (m == 0) { 45493379Smdodd ifp->if_ierrors++; 45593379Smdodd goto dropanyway; 45693379Smdodd } 4577055Sdg l = mtod(m, struct llc *); 45893377Smdodd 4597055Sdg switch (l->llc_dsap) { 4607055Sdg case LLC_SNAP_LSAP: 4617055Sdg { 46221830Sjoerg u_int16_t type; 463112266Smdodd if ((l->llc_control != LLC_UI) || 464112266Smdodd (l->llc_ssap != LLC_SNAP_LSAP)) { 46593379Smdodd ifp->if_noproto++; 4667055Sdg goto dropanyway; 46793379Smdodd } 46821830Sjoerg#ifdef NETATALK 469128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], at_org_code, 470111888Sjlemon sizeof(at_org_code)) == 0 && 471111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 472111888Sjlemon isr = NETISR_ATALK2; 473111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 474111888Sjlemon break; 47521830Sjoerg } 47621830Sjoerg 477128396Sluigi if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 478111888Sjlemon sizeof(aarp_org_code)) == 0 && 479111888Sjlemon ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 480111888Sjlemon m_adj(m, LLC_SNAPFRAMELEN); 481111888Sjlemon isr = NETISR_AARP; 482111888Sjlemon break; 48321830Sjoerg } 48421830Sjoerg#endif /* NETATALK */ 48593377Smdodd if (l->llc_snap.org_code[0] != 0 || 48693377Smdodd l->llc_snap.org_code[1] != 0 || 48793379Smdodd l->llc_snap.org_code[2] != 0) { 48893379Smdodd ifp->if_noproto++; 4897055Sdg goto dropanyway; 49093379Smdodd } 49193377Smdodd 49221830Sjoerg type = ntohs(l->llc_snap.ether_type); 49393377Smdodd m_adj(m, LLC_SNAPFRAMELEN); 49493377Smdodd 49521830Sjoerg switch (type) { 4967055Sdg#ifdef INET 4977055Sdg case ETHERTYPE_IP: 498154518Sandre if ((m = ip_fastforward(m)) == NULL) 49936192Sdg return; 500111888Sjlemon isr = NETISR_IP; 5017055Sdg break; 5027055Sdg 5037055Sdg case ETHERTYPE_ARP: 50478295Sjlemon if (ifp->if_flags & IFF_NOARP) 50578295Sjlemon goto dropanyway; 506111888Sjlemon isr = NETISR_ARP; 5077055Sdg break; 5087055Sdg#endif 50954263Sshin#ifdef INET6 51054263Sshin case ETHERTYPE_IPV6: 511111888Sjlemon isr = NETISR_IPV6; 51254263Sshin break; 51354263Sshin#endif 51421830Sjoerg#ifdef IPX 51521830Sjoerg case ETHERTYPE_IPX: 516111888Sjlemon isr = NETISR_IPX; 51721830Sjoerg break; 51821830Sjoerg#endif 5197055Sdg#ifdef DECNET 52021830Sjoerg case ETHERTYPE_DECNET: 521111888Sjlemon isr = NETISR_DECNET; 5227055Sdg break; 5237055Sdg#endif 52421830Sjoerg#ifdef NETATALK 52521830Sjoerg case ETHERTYPE_AT: 526111888Sjlemon isr = NETISR_ATALK1; 52721830Sjoerg break; 52821830Sjoerg case ETHERTYPE_AARP: 529111888Sjlemon isr = NETISR_AARP; 530111888Sjlemon break; 53121830Sjoerg#endif /* NETATALK */ 5327055Sdg default: 53321830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 5347055Sdg ifp->if_noproto++; 5357055Sdg goto dropanyway; 5367055Sdg } 5377055Sdg break; 5387055Sdg } 53921830Sjoerg 5407055Sdg default: 54121830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 5427055Sdg ifp->if_noproto++; 54393377Smdodd goto dropanyway; 5447055Sdg } 545111888Sjlemon netisr_dispatch(isr, m); 54693377Smdodd return; 54793377Smdodd 54893377Smdodddropanyway: 54993377Smdodd ifp->if_iqdrops++; 55093377Smdodd if (m) 55193377Smdodd m_freem(m); 55293377Smdodd return; 5537055Sdg} 55493380Smdodd 5557055Sdg/* 5567055Sdg * Perform common duties while attaching to interface list 5577055Sdg */ 5587055Sdgvoid 559152296Srufddi_ifattach(ifp, lla, bpf) 56093367Smdodd struct ifnet *ifp; 561152296Sru const u_int8_t *lla; 56293383Smdodd int bpf; 5637055Sdg{ 56493367Smdodd struct ifaddr *ifa; 56593367Smdodd struct sockaddr_dl *sdl; 5667055Sdg 5677055Sdg ifp->if_type = IFT_FDDI; 56893373Smdodd ifp->if_addrlen = FDDI_ADDR_LEN; 5697055Sdg ifp->if_hdrlen = 21; 57093379Smdodd 57193379Smdodd if_attach(ifp); /* Must be called before additional assignments */ 57293379Smdodd 5737055Sdg ifp->if_mtu = FDDIMTU; 57493379Smdodd ifp->if_output = fddi_output; 575106939Ssam ifp->if_input = fddi_input; 57668180Sume ifp->if_resolvemulti = fddi_resolvemulti; 57793379Smdodd ifp->if_broadcastaddr = fddibroadcastaddr; 57816063Sgpalmer ifp->if_baudrate = 100000000; 57921830Sjoerg#ifdef IFF_NOTRAILERS 58021830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 58121830Sjoerg#endif 582152315Sru ifa = ifp->if_addr; 583152315Sru KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 58493379Smdodd 58521831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 58621831Sjoerg sdl->sdl_type = IFT_FDDI; 58721831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 588152296Sru bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 58993379Smdodd 59093383Smdodd if (bpf) 59193383Smdodd bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); 59293383Smdodd 59393379Smdodd return; 5947055Sdg} 59568180Sume 59693382Smdoddvoid 59793382Smdoddfddi_ifdetach(ifp, bpf) 59893382Smdodd struct ifnet *ifp; 59993382Smdodd int bpf; 60093382Smdodd{ 60193382Smdodd 60293382Smdodd if (bpf) 60393382Smdodd bpfdetach(ifp); 60493382Smdodd 60593382Smdodd if_detach(ifp); 60693382Smdodd 60793382Smdodd return; 60893382Smdodd} 60993382Smdodd 61093382Smdoddint 61193382Smdoddfddi_ioctl (ifp, command, data) 61293382Smdodd struct ifnet *ifp; 61393382Smdodd int command; 61493382Smdodd caddr_t data; 61593382Smdodd{ 61693382Smdodd struct ifaddr *ifa; 61793382Smdodd struct ifreq *ifr; 61893382Smdodd int error; 61993382Smdodd 62093382Smdodd ifa = (struct ifaddr *) data; 62193382Smdodd ifr = (struct ifreq *) data; 62293382Smdodd error = 0; 62393382Smdodd 62493382Smdodd switch (command) { 62593382Smdodd case SIOCSIFADDR: 62693382Smdodd ifp->if_flags |= IFF_UP; 62793382Smdodd 62893382Smdodd switch (ifa->ifa_addr->sa_family) { 62993382Smdodd#ifdef INET 63093382Smdodd case AF_INET: /* before arpwhohas */ 63193382Smdodd ifp->if_init(ifp->if_softc); 63293382Smdodd arp_ifinit(ifp, ifa); 63393382Smdodd break; 63493382Smdodd#endif 63593382Smdodd#ifdef IPX 63693382Smdodd /* 63793382Smdodd * XXX - This code is probably wrong 63893382Smdodd */ 63993382Smdodd case AF_IPX: { 64093382Smdodd struct ipx_addr *ina; 64193382Smdodd 64293382Smdodd ina = &(IA_SIPX(ifa)->sipx_addr); 64393382Smdodd 64493382Smdodd if (ipx_nullhost(*ina)) { 64593382Smdodd ina->x_host = *(union ipx_host *) 646152315Sru IF_LLADDR(ifp); 64793382Smdodd } else { 64893382Smdodd bcopy((caddr_t) ina->x_host.c_host, 649152315Sru (caddr_t) IF_LLADDR(ifp), 650147256Sbrooks ETHER_ADDR_LEN); 65193382Smdodd } 65293382Smdodd 65393382Smdodd /* 65493382Smdodd * Set new address 65593382Smdodd */ 65693382Smdodd ifp->if_init(ifp->if_softc); 65793382Smdodd } 65893382Smdodd break; 65993382Smdodd#endif 66093382Smdodd default: 66193382Smdodd ifp->if_init(ifp->if_softc); 66293382Smdodd break; 663104302Sphk } 664144045Smdodd break; 66593382Smdodd case SIOCGIFADDR: { 66693382Smdodd struct sockaddr *sa; 66793382Smdodd 66893382Smdodd sa = (struct sockaddr *) & ifr->ifr_data; 669152315Sru bcopy(IF_LLADDR(ifp), 67093382Smdodd (caddr_t) sa->sa_data, FDDI_ADDR_LEN); 67193382Smdodd 67293382Smdodd } 67393382Smdodd break; 67493382Smdodd case SIOCSIFMTU: 67593382Smdodd /* 67693382Smdodd * Set the interface MTU. 67793382Smdodd */ 67893382Smdodd if (ifr->ifr_mtu > FDDIMTU) { 67993382Smdodd error = EINVAL; 68093382Smdodd } else { 68193382Smdodd ifp->if_mtu = ifr->ifr_mtu; 68293382Smdodd } 68393382Smdodd break; 68493382Smdodd default: 685144045Smdodd error = EINVAL; 68693382Smdodd break; 68793382Smdodd } 68893382Smdodd 68993382Smdodd return (error); 69093382Smdodd} 69193382Smdodd 69268180Sumestatic int 69368180Sumefddi_resolvemulti(ifp, llsa, sa) 69468180Sume struct ifnet *ifp; 69568180Sume struct sockaddr **llsa; 69668180Sume struct sockaddr *sa; 69768180Sume{ 69868180Sume struct sockaddr_dl *sdl; 699184709Sbz#ifdef INET 70068180Sume struct sockaddr_in *sin; 701184709Sbz#endif 70268180Sume#ifdef INET6 70368180Sume struct sockaddr_in6 *sin6; 70468180Sume#endif 70568180Sume u_char *e_addr; 70668180Sume 70768180Sume switch(sa->sa_family) { 70868180Sume case AF_LINK: 70968180Sume /* 71068180Sume * No mapping needed. Just check that it's a valid MC address. 71168180Sume */ 71268180Sume sdl = (struct sockaddr_dl *)sa; 71368180Sume e_addr = LLADDR(sdl); 71468180Sume if ((e_addr[0] & 1) != 1) 71593369Smdodd return (EADDRNOTAVAIL); 71668180Sume *llsa = 0; 71793369Smdodd return (0); 71868180Sume 71968180Sume#ifdef INET 72068180Sume case AF_INET: 72168180Sume sin = (struct sockaddr_in *)sa; 72268180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 72393369Smdodd return (EADDRNOTAVAIL); 724184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 725148641Srwatson M_NOWAIT | M_ZERO); 726148641Srwatson if (sdl == NULL) 727148641Srwatson return (ENOMEM); 72868180Sume sdl->sdl_len = sizeof *sdl; 72968180Sume sdl->sdl_family = AF_LINK; 73068180Sume sdl->sdl_index = ifp->if_index; 73168180Sume sdl->sdl_type = IFT_FDDI; 73268180Sume sdl->sdl_nlen = 0; 73393375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 73468180Sume sdl->sdl_slen = 0; 73568180Sume e_addr = LLADDR(sdl); 73668180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 73768180Sume *llsa = (struct sockaddr *)sdl; 73893369Smdodd return (0); 73968180Sume#endif 74068180Sume#ifdef INET6 74168180Sume case AF_INET6: 74268180Sume sin6 = (struct sockaddr_in6 *)sa; 74368180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 74468180Sume /* 74568180Sume * An IP6 address of 0 means listen to all 74668180Sume * of the Ethernet multicast address used for IP6. 74768180Sume * (This is used for multicast routers.) 74868180Sume */ 74968180Sume ifp->if_flags |= IFF_ALLMULTI; 75068180Sume *llsa = 0; 75193369Smdodd return (0); 75268180Sume } 75368180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 75493369Smdodd return (EADDRNOTAVAIL); 755184205Sdes sdl = malloc(sizeof *sdl, M_IFMADDR, 756148641Srwatson M_NOWAIT | M_ZERO); 757148641Srwatson if (sdl == NULL) 758148641Srwatson return (ENOMEM); 75968180Sume sdl->sdl_len = sizeof *sdl; 76068180Sume sdl->sdl_family = AF_LINK; 76168180Sume sdl->sdl_index = ifp->if_index; 76268180Sume sdl->sdl_type = IFT_FDDI; 76368180Sume sdl->sdl_nlen = 0; 76493375Smdodd sdl->sdl_alen = FDDI_ADDR_LEN; 76568180Sume sdl->sdl_slen = 0; 76668180Sume e_addr = LLADDR(sdl); 76768180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 76868180Sume *llsa = (struct sockaddr *)sdl; 76993369Smdodd return (0); 77068180Sume#endif 77168180Sume 77268180Sume default: 77368180Sume /* 77468180Sume * Well, the text isn't quite right, but it's the name 77568180Sume * that counts... 77668180Sume */ 77793369Smdodd return (EAFNOSUPPORT); 77868180Sume } 77993375Smdodd 78093375Smdodd return (0); 78168180Sume} 78293375Smdodd 78393375Smdoddstatic moduledata_t fddi_mod = { 78493375Smdodd "fddi", /* module name */ 78593375Smdodd NULL, /* event handler */ 78693375Smdodd 0 /* extra data */ 78793375Smdodd}; 78893375Smdodd 78993375SmdoddDECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 79093375SmdoddMODULE_VERSION(fddi, 1); 791