if_fddisubr.c revision 93084
17055Sdg/* 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 93084 2002-03-24 09:34:04Z bde $ 377055Sdg */ 387055Sdg 3932356Seivind#include "opt_atalk.h" 4032350Seivind#include "opt_inet.h" 4154263Sshin#include "opt_inet6.h" 4231742Seivind#include "opt_ipx.h" 4331742Seivind 447055Sdg#include <sys/param.h> 457055Sdg#include <sys/systm.h> 467055Sdg#include <sys/mbuf.h> 477055Sdg#include <sys/socket.h> 4868315Sume#include <sys/malloc.h> 497055Sdg 507055Sdg#include <net/if.h> 517055Sdg#include <net/netisr.h> 527055Sdg#include <net/route.h> 537055Sdg#include <net/if_llc.h> 547055Sdg#include <net/if_dl.h> 557055Sdg#include <net/if_types.h> 567055Sdg 5754263Sshin#if defined(INET) || defined(INET6) 587055Sdg#include <netinet/in.h> 597055Sdg#include <netinet/in_var.h> 6032350Seivind#include <netinet/if_ether.h> 617055Sdg#endif 6254263Sshin#ifdef INET6 6354263Sshin#include <netinet6/nd6.h> 6454263Sshin#endif 6521830Sjoerg#if defined(__FreeBSD__) 667055Sdg#include <netinet/if_fddi.h> 6721830Sjoerg#else 6821830Sjoerg#include <net/if_fddi.h> 6921830Sjoerg#endif 707055Sdg 7111819Sjulian#ifdef IPX 7221830Sjoerg#include <netipx/ipx.h> 7311819Sjulian#include <netipx/ipx_if.h> 7411819Sjulian#endif 7511819Sjulian 767055Sdg#ifdef NS 777055Sdg#include <netns/ns.h> 787055Sdg#include <netns/ns_if.h> 797055Sdg#endif 807055Sdg 817055Sdg#ifdef DECNET 827055Sdg#include <netdnet/dn.h> 837055Sdg#endif 847055Sdg 8521830Sjoerg#ifdef NETATALK 8621830Sjoerg#include <netatalk/at.h> 8721830Sjoerg#include <netatalk/at_var.h> 8821830Sjoerg#include <netatalk/at_extern.h> 8921830Sjoerg 9021830Sjoerg#define llc_snap_org_code llc_un.type_snap.org_code 9121830Sjoerg#define llc_snap_ether_type llc_un.type_snap.ether_type 9221830Sjoerg 9321830Sjoergextern u_char at_org_code[ 3 ]; 9421830Sjoergextern u_char aarp_org_code[ 3 ]; 9521830Sjoerg#endif /* NETATALK */ 9621830Sjoerg 9792725Salfredstatic int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 9893084Sbde struct sockaddr *); 9968180Sume 1007055Sdg#define senderr(e) { error = (e); goto bad;} 1017055Sdg 1027055Sdg/* 1037055Sdg * This really should be defined in if_llc.h but in case it isn't. 1047055Sdg */ 1057055Sdg#ifndef llc_snap 1067055Sdg#define llc_snap llc_un.type_snap 1077055Sdg#endif 1087055Sdg 10921830Sjoerg#if defined(__bsdi__) || defined(__NetBSD__) 11021830Sjoerg#define RTALLOC1(a, b) rtalloc1(a, b) 1117055Sdg#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e) 11221830Sjoerg#elif defined(__FreeBSD__) 11321830Sjoerg#define RTALLOC1(a, b) rtalloc1(a, b, 0UL) 1147055Sdg#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f) 1157055Sdg#endif 1167055Sdg/* 1177055Sdg * FDDI output routine. 1187055Sdg * Encapsulate a packet of type family for the local net. 1197055Sdg * Use trailer local net encapsulation if enough data in first 1207055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1217055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1227055Sdg */ 1237055Sdgint 12454799Sgreenfddi_output(ifp, m, dst, rt0) 1257055Sdg register struct ifnet *ifp; 12654799Sgreen struct mbuf *m; 1277055Sdg struct sockaddr *dst; 1287055Sdg struct rtentry *rt0; 1297055Sdg{ 13021830Sjoerg u_int16_t type; 13169152Sjlemon int loop_copy = 0, error = 0, hdrcmplt = 0; 13252248Smsmith u_char esrc[6], edst[6]; 1337055Sdg register struct rtentry *rt; 13421830Sjoerg register struct fddi_header *fh; 1357055Sdg struct arpcom *ac = (struct arpcom *)ifp; 1367055Sdg 1377055Sdg if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1387055Sdg senderr(ENETDOWN); 13934961Sphk getmicrotime(&ifp->if_lastchange); 14021830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 14143305Sdillon if ((rt = rt0) != NULL) { 1427055Sdg if ((rt->rt_flags & RTF_UP) == 0) { 14343305Sdillon if ((rt0 = rt = RTALLOC1(dst, 1)) != NULL) 1447055Sdg rt->rt_refcnt--; 14521830Sjoerg else 1467055Sdg senderr(EHOSTUNREACH); 1477055Sdg } 1487055Sdg if (rt->rt_flags & RTF_GATEWAY) { 1497055Sdg if (rt->rt_gwroute == 0) 1507055Sdg goto lookup; 1517055Sdg if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 1527055Sdg rtfree(rt); rt = rt0; 1537055Sdg lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1); 1547055Sdg if ((rt = rt->rt_gwroute) == 0) 1557055Sdg senderr(EHOSTUNREACH); 1567055Sdg } 1577055Sdg } 1587055Sdg if (rt->rt_flags & RTF_REJECT) 1597055Sdg if (rt->rt_rmx.rmx_expire == 0 || 16034961Sphk time_second < rt->rt_rmx.rmx_expire) 1617055Sdg senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 1627055Sdg } 16321830Sjoerg#endif 1647055Sdg switch (dst->sa_family) { 1657055Sdg 1667055Sdg#ifdef INET 16721830Sjoerg case AF_INET: { 16821830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 16984931Sfjoe if (!ARPRESOLVE(ifp, rt, m, dst, edst, rt0)) 1707055Sdg return (0); /* if not yet resolved */ 17121830Sjoerg#else 17221830Sjoerg int usetrailers; 17321830Sjoerg if (!arpresolve(ac, m, &((struct sockaddr_in *)dst)->sin_addr, edst, &usetrailers)) 17421830Sjoerg return (0); /* if not yet resolved */ 17521830Sjoerg#endif 17621830Sjoerg type = htons(ETHERTYPE_IP); 1777055Sdg break; 17821830Sjoerg } 1797055Sdg#endif 18054263Sshin#ifdef INET6 18154263Sshin case AF_INET6: 18254263Sshin if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 18374093Sbmilekic /* Something bad happened */ 18454263Sshin return(0); 18554263Sshin } 18654263Sshin type = htons(ETHERTYPE_IPV6); 18754263Sshin break; 18854263Sshin#endif 18911819Sjulian#ifdef IPX 19011819Sjulian case AF_IPX: 19121830Sjoerg type = htons(ETHERTYPE_IPX); 19211819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 19311819Sjulian (caddr_t)edst, sizeof (edst)); 19411819Sjulian break; 19511819Sjulian#endif 19621830Sjoerg#ifdef NETATALK 19721830Sjoerg case AF_APPLETALK: { 19821830Sjoerg struct at_ifaddr *aa; 19936908Sjulian if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 20021830Sjoerg return (0); 20121830Sjoerg /* 20221830Sjoerg * ifaddr is the first thing in at_ifaddr 20321830Sjoerg */ 20430834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 20521830Sjoerg goto bad; 20621830Sjoerg 20721830Sjoerg /* 20821830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 20921830Sjoerg * Since we must preserve the value of m, which is passed to us by 21021830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 21121830Sjoerg */ 21221830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 21321830Sjoerg struct llc llc; 21421830Sjoerg 21570254Sbmilekic M_PREPEND(m, sizeof(struct llc), M_TRYWAIT); 21621830Sjoerg if (m == 0) 21721830Sjoerg senderr(ENOBUFS); 21821830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 21921830Sjoerg llc.llc_control = LLC_UI; 22021830Sjoerg bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 22121830Sjoerg llc.llc_snap_ether_type = htons(ETHERTYPE_AT); 22221830Sjoerg bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 22321830Sjoerg type = 0; 22421830Sjoerg } else { 22521830Sjoerg type = htons(ETHERTYPE_AT); 22621830Sjoerg } 22721830Sjoerg break; 22821830Sjoerg } 22921830Sjoerg#endif /* NETATALK */ 2307055Sdg#ifdef NS 2317055Sdg case AF_NS: 23221830Sjoerg type = htons(ETHERTYPE_NS); 2337055Sdg bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 2347055Sdg (caddr_t)edst, sizeof (edst)); 2357055Sdg break; 2367055Sdg#endif 2377055Sdg 23852248Smsmith case pseudo_AF_HDRCMPLT: 23952248Smsmith { 24052248Smsmith struct ether_header *eh; 24152248Smsmith hdrcmplt = 1; 24252248Smsmith eh = (struct ether_header *)dst->sa_data; 24352248Smsmith (void)memcpy((caddr_t)esrc, (caddr_t)eh->ether_shost, sizeof (esrc)); 24452248Smsmith /* FALLTHROUGH */ 24552248Smsmith } 24652248Smsmith 2477055Sdg case AF_UNSPEC: 2487055Sdg { 2497055Sdg struct ether_header *eh; 25036992Sjulian loop_copy = -1; 2517055Sdg eh = (struct ether_header *)dst->sa_data; 2528384Sdg (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 2537055Sdg if (*edst & 1) 2547055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2557055Sdg type = eh->ether_type; 2567055Sdg break; 2577055Sdg } 2587055Sdg 2597055Sdg case AF_IMPLINK: 2607055Sdg { 2617055Sdg fh = mtod(m, struct fddi_header *); 2627055Sdg error = EPROTONOSUPPORT; 2637055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 2647055Sdg case FDDIFC_LLC_ASYNC: { 2657055Sdg /* legal priorities are 0 through 7 */ 2667055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 2677055Sdg goto bad; 2687055Sdg break; 2697055Sdg } 2707055Sdg case FDDIFC_LLC_SYNC: { 2717055Sdg /* FDDIFC_Z bits reserved, must be zero */ 2727055Sdg if (fh->fddi_fc & FDDIFC_Z) 2737055Sdg goto bad; 2747055Sdg break; 2757055Sdg } 2767055Sdg case FDDIFC_SMT: { 2777055Sdg /* FDDIFC_Z bits must be non zero */ 2787055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 2797055Sdg goto bad; 2807055Sdg break; 2817055Sdg } 2827055Sdg default: { 2837055Sdg /* anything else is too dangerous */ 2847055Sdg goto bad; 2857055Sdg } 2867055Sdg } 2877055Sdg error = 0; 2887055Sdg if (fh->fddi_dhost[0] & 1) 2897055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2907055Sdg goto queue_it; 2917055Sdg } 2927055Sdg default: 2937055Sdg printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 2947055Sdg dst->sa_family); 2957055Sdg senderr(EAFNOSUPPORT); 2967055Sdg } 2977055Sdg 2987055Sdg if (type != 0) { 2997055Sdg register struct llc *l; 3007055Sdg M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); 3017055Sdg if (m == 0) 3027055Sdg senderr(ENOBUFS); 3037055Sdg l = mtod(m, struct llc *); 3047055Sdg l->llc_control = LLC_UI; 3057055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 3067055Sdg l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 3078384Sdg (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type, 30821830Sjoerg sizeof(u_int16_t)); 3097055Sdg } 31036908Sjulian 3117055Sdg /* 3127055Sdg * Add local net header. If no space in first mbuf, 3137055Sdg * allocate another. 3147055Sdg */ 3157055Sdg M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT); 3167055Sdg if (m == 0) 3177055Sdg senderr(ENOBUFS); 3187055Sdg fh = mtod(m, struct fddi_header *); 3197055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 3208384Sdg (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst)); 3217055Sdg queue_it: 32252248Smsmith if (hdrcmplt) 32352248Smsmith (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)esrc, 32452248Smsmith sizeof(fh->fddi_shost)); 32552248Smsmith else 32652248Smsmith (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr, 32752248Smsmith sizeof(fh->fddi_shost)); 32836908Sjulian /* 32936908Sjulian * If a simplex interface, and the packet is being sent to our 33036908Sjulian * Ethernet address or a broadcast address, loopback a copy. 33136908Sjulian * XXX To make a simplex device behave exactly like a duplex 33236908Sjulian * device, we should copy in the case of sending to our own 33336908Sjulian * ethernet address (thus letting the original actually appear 33436908Sjulian * on the wire). However, we don't do that here for security 33536908Sjulian * reasons and compatibility with the original behavior. 33636908Sjulian */ 33736992Sjulian if ((ifp->if_flags & IFF_SIMPLEX) && 33836992Sjulian (loop_copy != -1)) { 33936908Sjulian if ((m->m_flags & M_BCAST) || loop_copy) { 34036908Sjulian struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 34136908Sjulian 34236908Sjulian (void) if_simloop(ifp, 34360889Sarchie n, dst->sa_family, sizeof(struct fddi_header)); 34436908Sjulian } else if (bcmp(fh->fddi_dhost, 34536908Sjulian fh->fddi_shost, sizeof(fh->fddi_shost)) == 0) { 34636908Sjulian (void) if_simloop(ifp, 34760889Sarchie m, dst->sa_family, sizeof(struct fddi_header)); 34836908Sjulian return(0); /* XXX */ 34936908Sjulian } 35036908Sjulian } 35136908Sjulian 35269152Sjlemon if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 3537055Sdg senderr(ENOBUFS); 3547055Sdg return (error); 3557055Sdg 3567055Sdgbad: 3577055Sdg if (m) 3587055Sdg m_freem(m); 3597055Sdg return (error); 3607055Sdg} 3617055Sdg 3627055Sdg/* 3637055Sdg * Process a received FDDI packet; 3647055Sdg * the packet is in the mbuf chain m without 3657055Sdg * the fddi header, which is provided separately. 3667055Sdg */ 3677055Sdgvoid 3687055Sdgfddi_input(ifp, fh, m) 3697055Sdg struct ifnet *ifp; 3707055Sdg register struct fddi_header *fh; 3717055Sdg struct mbuf *m; 3727055Sdg{ 3737055Sdg register struct ifqueue *inq; 3747055Sdg register struct llc *l; 3757055Sdg 3767055Sdg if ((ifp->if_flags & IFF_UP) == 0) { 3777055Sdg m_freem(m); 3787055Sdg return; 3797055Sdg } 38034961Sphk getmicrotime(&ifp->if_lastchange); 3817055Sdg ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 38221830Sjoerg if (fh->fddi_dhost[0] & 1) { 38321830Sjoerg if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 38421830Sjoerg sizeof(fddibroadcastaddr)) == 0) 38521830Sjoerg m->m_flags |= M_BCAST; 38621830Sjoerg else 38721830Sjoerg m->m_flags |= M_MCAST; 3887055Sdg ifp->if_imcasts++; 38923910Sjoerg } else if ((ifp->if_flags & IFF_PROMISC) 39023910Sjoerg && bcmp(((struct arpcom *)ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 39123910Sjoerg sizeof(fh->fddi_dhost)) != 0) { 39223910Sjoerg m_freem(m); 39323910Sjoerg return; 39421830Sjoerg } 3957055Sdg 39621830Sjoerg#ifdef M_LINK0 39721830Sjoerg /* 39821830Sjoerg * If this has a LLC priority of 0, then mark it so upper 39921830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 40021830Sjoerg * bridge. 40121830Sjoerg */ 40221830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 40321830Sjoerg m->m_flags |= M_LINK0; 40421830Sjoerg#endif 40521830Sjoerg 4067055Sdg l = mtod(m, struct llc *); 4077055Sdg switch (l->llc_dsap) { 40854263Sshin#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) 4097055Sdg case LLC_SNAP_LSAP: 4107055Sdg { 41121830Sjoerg u_int16_t type; 4127055Sdg if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 4137055Sdg goto dropanyway; 41421830Sjoerg#ifdef NETATALK 41521830Sjoerg if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 41621830Sjoerg sizeof(at_org_code)) == 0 && 41721830Sjoerg ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 41821830Sjoerg inq = &atintrq2; 41921830Sjoerg m_adj( m, sizeof( struct llc )); 42021830Sjoerg schednetisr(NETISR_ATALK); 42121830Sjoerg break; 42221830Sjoerg } 42321830Sjoerg 42421830Sjoerg if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 42521830Sjoerg sizeof(aarp_org_code)) == 0 && 42621830Sjoerg ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 42721830Sjoerg m_adj( m, sizeof( struct llc )); 42821830Sjoerg aarpinput((struct arpcom *)ifp, m); /* XXX */ 42921830Sjoerg return; 43021830Sjoerg } 43121830Sjoerg#endif /* NETATALK */ 4327055Sdg if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 4337055Sdg goto dropanyway; 43421830Sjoerg type = ntohs(l->llc_snap.ether_type); 4357055Sdg m_adj(m, 8); 43621830Sjoerg switch (type) { 4377055Sdg#ifdef INET 4387055Sdg case ETHERTYPE_IP: 43936265Sdg if (ipflow_fastforward(m)) 44036192Sdg return; 4417055Sdg schednetisr(NETISR_IP); 4427055Sdg inq = &ipintrq; 4437055Sdg break; 4447055Sdg 4457055Sdg case ETHERTYPE_ARP: 44678295Sjlemon if (ifp->if_flags & IFF_NOARP) 44778295Sjlemon goto dropanyway; 4487055Sdg schednetisr(NETISR_ARP); 4497055Sdg inq = &arpintrq; 4507055Sdg break; 4517055Sdg#endif 45254263Sshin#ifdef INET6 45354263Sshin case ETHERTYPE_IPV6: 45454263Sshin schednetisr(NETISR_IPV6); 45554263Sshin inq = &ip6intrq; 45654263Sshin break; 45754263Sshin#endif 45821830Sjoerg#ifdef IPX 45921830Sjoerg case ETHERTYPE_IPX: 46021830Sjoerg schednetisr(NETISR_IPX); 46121830Sjoerg inq = &ipxintrq; 46221830Sjoerg break; 46321830Sjoerg#endif 4647055Sdg#ifdef NS 4657055Sdg case ETHERTYPE_NS: 4667055Sdg schednetisr(NETISR_NS); 4677055Sdg inq = &nsintrq; 4687055Sdg break; 4697055Sdg#endif 4707055Sdg#ifdef DECNET 47121830Sjoerg case ETHERTYPE_DECNET: 4727055Sdg schednetisr(NETISR_DECNET); 4737055Sdg inq = &decnetintrq; 4747055Sdg break; 4757055Sdg#endif 47621830Sjoerg#ifdef NETATALK 47721830Sjoerg case ETHERTYPE_AT: 47821830Sjoerg schednetisr(NETISR_ATALK); 47921830Sjoerg inq = &atintrq1; 48021830Sjoerg break; 48121830Sjoerg case ETHERTYPE_AARP: 48221830Sjoerg /* probably this should be done with a NETISR as well */ 48321830Sjoerg aarpinput((struct arpcom *)ifp, m); /* XXX */ 48421830Sjoerg return; 48521830Sjoerg#endif /* NETATALK */ 4867055Sdg default: 48721830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 4887055Sdg ifp->if_noproto++; 4897055Sdg goto dropanyway; 4907055Sdg } 4917055Sdg break; 4927055Sdg } 4937055Sdg#endif /* INET || NS */ 49421830Sjoerg 4957055Sdg default: 49621830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 4977055Sdg ifp->if_noproto++; 4987055Sdg dropanyway: 4997055Sdg m_freem(m); 5007055Sdg return; 5017055Sdg } 5027055Sdg 50369152Sjlemon (void) IF_HANDOFF(inq, m, NULL); 5047055Sdg} 5057055Sdg/* 5067055Sdg * Perform common duties while attaching to interface list 5077055Sdg */ 50821830Sjoerg#ifdef __NetBSD__ 50921830Sjoerg#define ifa_next ifa_list.tqe_next 51021830Sjoerg#endif 51121830Sjoerg 5127055Sdgvoid 5137055Sdgfddi_ifattach(ifp) 5147055Sdg register struct ifnet *ifp; 5157055Sdg{ 5167055Sdg register struct ifaddr *ifa; 5177055Sdg register struct sockaddr_dl *sdl; 5187055Sdg 5197055Sdg ifp->if_type = IFT_FDDI; 5207055Sdg ifp->if_addrlen = 6; 5217055Sdg ifp->if_hdrlen = 21; 5227055Sdg ifp->if_mtu = FDDIMTU; 52368180Sume ifp->if_resolvemulti = fddi_resolvemulti; 52416063Sgpalmer ifp->if_baudrate = 100000000; 52521830Sjoerg#ifdef IFF_NOTRAILERS 52621830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 52721830Sjoerg#endif 52884931Sfjoe ifp->if_broadcastaddr = fddibroadcastaddr; 52921831Sjoerg#if defined(__FreeBSD__) 53083130Sjlemon ifa = ifaddr_byindex(ifp->if_index); 53121831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 53221831Sjoerg sdl->sdl_type = IFT_FDDI; 53321831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 53421831Sjoerg bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 53521831Sjoerg#elif defined(__NetBSD__) 53621830Sjoerg LIST_INIT(&((struct arpcom *)ifp)->ac_multiaddrs); 53771999Sphk TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 53821830Sjoerg#else 53921830Sjoerg for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) 54021830Sjoerg#endif 54121831Sjoerg#if !defined(__FreeBSD__) 54221830Sjoerg if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 54321830Sjoerg sdl->sdl_family == AF_LINK) { 54421830Sjoerg sdl->sdl_type = IFT_FDDI; 54521830Sjoerg sdl->sdl_alen = ifp->if_addrlen; 54621830Sjoerg bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, 54721830Sjoerg LLADDR(sdl), ifp->if_addrlen); 54821830Sjoerg break; 54921830Sjoerg } 55021831Sjoerg#endif 5517055Sdg} 55268180Sume 55368180Sumestatic int 55468180Sumefddi_resolvemulti(ifp, llsa, sa) 55568180Sume struct ifnet *ifp; 55668180Sume struct sockaddr **llsa; 55768180Sume struct sockaddr *sa; 55868180Sume{ 55968180Sume struct sockaddr_dl *sdl; 56068180Sume struct sockaddr_in *sin; 56168180Sume#ifdef INET6 56268180Sume struct sockaddr_in6 *sin6; 56368180Sume#endif 56468180Sume u_char *e_addr; 56568180Sume 56668180Sume switch(sa->sa_family) { 56768180Sume case AF_LINK: 56868180Sume /* 56968180Sume * No mapping needed. Just check that it's a valid MC address. 57068180Sume */ 57168180Sume sdl = (struct sockaddr_dl *)sa; 57268180Sume e_addr = LLADDR(sdl); 57368180Sume if ((e_addr[0] & 1) != 1) 57468180Sume return EADDRNOTAVAIL; 57568180Sume *llsa = 0; 57668180Sume return 0; 57768180Sume 57868180Sume#ifdef INET 57968180Sume case AF_INET: 58068180Sume sin = (struct sockaddr_in *)sa; 58168180Sume if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 58268180Sume return EADDRNOTAVAIL; 58368180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 58468180Sume M_WAITOK); 58568180Sume sdl->sdl_len = sizeof *sdl; 58668180Sume sdl->sdl_family = AF_LINK; 58768180Sume sdl->sdl_index = ifp->if_index; 58868180Sume sdl->sdl_type = IFT_FDDI; 58968180Sume sdl->sdl_nlen = 0; 59068180Sume sdl->sdl_alen = ETHER_ADDR_LEN; /* XXX */ 59168180Sume sdl->sdl_slen = 0; 59268180Sume e_addr = LLADDR(sdl); 59368180Sume ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 59468180Sume *llsa = (struct sockaddr *)sdl; 59568180Sume return 0; 59668180Sume#endif 59768180Sume#ifdef INET6 59868180Sume case AF_INET6: 59968180Sume sin6 = (struct sockaddr_in6 *)sa; 60068180Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 60168180Sume /* 60268180Sume * An IP6 address of 0 means listen to all 60368180Sume * of the Ethernet multicast address used for IP6. 60468180Sume * (This is used for multicast routers.) 60568180Sume */ 60668180Sume ifp->if_flags |= IFF_ALLMULTI; 60768180Sume *llsa = 0; 60868180Sume return 0; 60968180Sume } 61068180Sume if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 61168180Sume return EADDRNOTAVAIL; 61268180Sume MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 61368180Sume M_WAITOK); 61468180Sume sdl->sdl_len = sizeof *sdl; 61568180Sume sdl->sdl_family = AF_LINK; 61668180Sume sdl->sdl_index = ifp->if_index; 61768180Sume sdl->sdl_type = IFT_FDDI; 61868180Sume sdl->sdl_nlen = 0; 61968180Sume sdl->sdl_alen = ETHER_ADDR_LEN; /* XXX */ 62068180Sume sdl->sdl_slen = 0; 62168180Sume e_addr = LLADDR(sdl); 62268180Sume ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 62368180Sume *llsa = (struct sockaddr *)sdl; 62468180Sume return 0; 62568180Sume#endif 62668180Sume 62768180Sume default: 62868180Sume /* 62968180Sume * Well, the text isn't quite right, but it's the name 63068180Sume * that counts... 63168180Sume */ 63268180Sume return EAFNOSUPPORT; 63368180Sume } 63468180Sume} 635