The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_arcsubr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $   */
    2 /*      $FreeBSD: releng/6.1/sys/net/if_arcsubr.c 149443 2005-08-25 05:01:24Z rwatson $ */
    3 
    4 /*-
    5  * Copyright (c) 1994, 1995 Ignatios Souvatzis
    6  * Copyright (c) 1982, 1989, 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by the University of
   20  *      California, Berkeley and its contributors.
   21  * 4. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
   38  *       @(#)if_ethersubr.c     8.1 (Berkeley) 6/10/93
   39  *
   40  */
   41 #include "opt_inet.h"
   42 #include "opt_inet6.h"
   43 #include "opt_ipx.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/module.h>
   49 #include <sys/malloc.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/protosw.h>
   52 #include <sys/socket.h>
   53 #include <sys/sockio.h>
   54 #include <sys/errno.h>
   55 #include <sys/syslog.h>
   56 
   57 #include <machine/cpu.h>
   58 
   59 #include <net/if.h>
   60 #include <net/netisr.h>
   61 #include <net/route.h>
   62 #include <net/if_dl.h>
   63 #include <net/if_types.h>
   64 #include <net/if_arc.h>
   65 #include <net/if_arp.h>
   66 #include <net/bpf.h>
   67 
   68 #if defined(INET) || defined(INET6)
   69 #include <netinet/in.h>
   70 #include <netinet/in_var.h>
   71 #include <netinet/if_ether.h>
   72 #endif
   73 
   74 #ifdef INET6
   75 #include <netinet6/nd6.h>
   76 #endif
   77 
   78 #ifdef IPX
   79 #include <netipx/ipx.h>
   80 #include <netipx/ipx_if.h>
   81 #endif
   82 
   83 #define ARCNET_ALLOW_BROKEN_ARP
   84 
   85 static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
   86 static int arc_resolvemulti(struct ifnet *, struct sockaddr **,
   87                             struct sockaddr *);
   88 
   89 u_int8_t  arcbroadcastaddr = 0;
   90 
   91 #define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
   92 
   93 #define senderr(e) { error = (e); goto bad;}
   94 #define SIN(s)  ((struct sockaddr_in *)s)
   95 #define SIPX(s) ((struct sockaddr_ipx *)s)
   96 
   97 /*
   98  * ARCnet output routine.
   99  * Encapsulate a packet of type family for the local net.
  100  * Assumes that ifp is actually pointer to arccom structure.
  101  */
  102 int
  103 arc_output(ifp, m, dst, rt0)
  104         struct ifnet *ifp;
  105         struct mbuf *m;
  106         struct sockaddr *dst;
  107         struct rtentry *rt0;
  108 {
  109         struct arc_header       *ah;
  110         int                     error;
  111         u_int8_t                atype, adst;
  112         int                     loop_copy = 0;
  113         int                     isphds;
  114 
  115         if (!((ifp->if_flags & IFF_UP) &&
  116             (ifp->if_drv_flags & IFF_DRV_RUNNING)))
  117                 return(ENETDOWN); /* m, m1 aren't initialized yet */
  118 
  119         error = 0;
  120 
  121         switch (dst->sa_family) {
  122 #ifdef INET
  123         case AF_INET:
  124 
  125                 /*
  126                  * For now, use the simple IP addr -> ARCnet addr mapping
  127                  */
  128                 if (m->m_flags & (M_BCAST|M_MCAST))
  129                         adst = arcbroadcastaddr; /* ARCnet broadcast address */
  130                 else if (ifp->if_flags & IFF_NOARP)
  131                         adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
  132                 else {
  133                         error = arpresolve(ifp, rt0, m, dst, &adst);
  134                         if (error)
  135                                 return (error == EWOULDBLOCK ? 0 : error);
  136                 }
  137 
  138                 atype = (ifp->if_flags & IFF_LINK0) ?
  139                         ARCTYPE_IP_OLD : ARCTYPE_IP;
  140                 break;
  141         case AF_ARP:
  142         {
  143                 struct arphdr *ah;
  144                 ah = mtod(m, struct arphdr *);
  145                 ah->ar_hrd = htons(ARPHRD_ARCNET);
  146 
  147                 loop_copy = -1; /* if this is for us, don't do it */
  148 
  149                 switch(ntohs(ah->ar_op)) {
  150                 case ARPOP_REVREQUEST:
  151                 case ARPOP_REVREPLY:
  152                         atype = ARCTYPE_REVARP;
  153                         break;
  154                 case ARPOP_REQUEST:
  155                 case ARPOP_REPLY:
  156                 default:
  157                         atype = ARCTYPE_ARP;
  158                         break;
  159                 }
  160 
  161                 if (m->m_flags & M_BCAST)
  162                         bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN);
  163                 else
  164                         bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN);
  165         
  166         }
  167         break;
  168 #endif
  169 #ifdef INET6
  170         case AF_INET6:
  171                 error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)&adst);
  172                 if (error)
  173                         return (error);
  174                 atype = ARCTYPE_INET6;
  175                 break;
  176 #endif
  177 #ifdef IPX
  178         case AF_IPX:
  179                 adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
  180                 atype = ARCTYPE_IPX;
  181                 if (adst == 0xff)
  182                         adst = arcbroadcastaddr;
  183                 break;
  184 #endif
  185 
  186         case AF_UNSPEC:
  187                 loop_copy = -1;
  188                 ah = (struct arc_header *)dst->sa_data;
  189                 adst = ah->arc_dhost;
  190                 atype = ah->arc_type;
  191 
  192                 if (atype == ARCTYPE_ARP) {
  193                         atype = (ifp->if_flags & IFF_LINK0) ?
  194                             ARCTYPE_ARP_OLD: ARCTYPE_ARP;
  195 
  196 #ifdef ARCNET_ALLOW_BROKEN_ARP
  197                         /*
  198                          * XXX It's not clear per RFC826 if this is needed, but
  199                          * "assigned numbers" say this is wrong.
  200                          * However, e.g., AmiTCP 3.0Beta used it... we make this
  201                          * switchable for emergency cases. Not perfect, but...
  202                          */
  203                         if (ifp->if_flags & IFF_LINK2)
  204                                 mtod(m, struct arphdr *)->ar_pro = atype - 1;
  205 #endif
  206                 }
  207                 break;
  208 
  209         default:
  210                 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
  211                 senderr(EAFNOSUPPORT);
  212         }
  213 
  214         isphds = arc_isphds(atype);
  215         M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_DONTWAIT);
  216         if (m == 0)
  217                 senderr(ENOBUFS);
  218         ah = mtod(m, struct arc_header *);
  219         ah->arc_type = atype;
  220         ah->arc_dhost = adst;
  221         ah->arc_shost = ARC_LLADDR(ifp);
  222         if (isphds) {
  223                 ah->arc_flag = 0;
  224                 ah->arc_seqid = 0;
  225         }
  226 
  227         if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
  228                 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
  229                         struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
  230 
  231                         (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
  232                 } else if (ah->arc_dhost == ah->arc_shost) {
  233                         (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
  234                         return (0);     /* XXX */
  235                 }
  236         }
  237 
  238         BPF_MTAP(ifp, m);
  239 
  240         IFQ_HANDOFF(ifp, m, error);
  241 
  242         return (error);
  243 
  244 bad:
  245         if (m)
  246                 m_freem(m);
  247         return (error);
  248 }
  249 
  250 void
  251 arc_frag_init(ifp)
  252         struct ifnet *ifp;
  253 {
  254         struct arccom *ac;
  255 
  256         ac = (struct arccom *)ifp->if_l2com;
  257         ac->curr_frag = 0;
  258 }
  259 
  260 struct mbuf *
  261 arc_frag_next(ifp)
  262         struct ifnet *ifp;
  263 {
  264         struct arccom *ac;
  265         struct mbuf *m;
  266         struct arc_header *ah;
  267 
  268         ac = (struct arccom *)ifp->if_l2com;
  269         if ((m = ac->curr_frag) == 0) {
  270                 int tfrags;
  271 
  272                 /* dequeue new packet */
  273                 IF_DEQUEUE(&ifp->if_snd, m);
  274                 if (m == 0)
  275                         return 0;
  276 
  277                 ah = mtod(m, struct arc_header *);
  278                 if (!arc_isphds(ah->arc_type))
  279                         return m;
  280 
  281                 ++ac->ac_seqid;         /* make the seqid unique */
  282                 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
  283                 ac->fsflag = 2 * tfrags - 3;
  284                 ac->sflag = 0;
  285                 ac->rsflag = ac->fsflag;
  286                 ac->arc_dhost = ah->arc_dhost;
  287                 ac->arc_shost = ah->arc_shost;
  288                 ac->arc_type = ah->arc_type;
  289 
  290                 m_adj(m, ARC_HDRNEWLEN);
  291                 ac->curr_frag = m;
  292         }
  293 
  294         /* split out next fragment and return it */
  295         if (ac->sflag < ac->fsflag) {
  296                 /* we CAN'T have short packets here */
  297                 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_DONTWAIT);
  298                 if (ac->curr_frag == 0) {
  299                         m_freem(m);
  300                         return 0;
  301                 }
  302 
  303                 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
  304                 if (m == 0) {
  305                         m_freem(ac->curr_frag);
  306                         ac->curr_frag = 0;
  307                         return 0;
  308                 }
  309 
  310                 ah = mtod(m, struct arc_header *);
  311                 ah->arc_flag = ac->rsflag;
  312                 ah->arc_seqid = ac->ac_seqid;
  313 
  314                 ac->sflag += 2;
  315                 ac->rsflag = ac->sflag;
  316         } else if ((m->m_pkthdr.len >=
  317             ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
  318             (m->m_pkthdr.len <=
  319             ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
  320                 ac->curr_frag = 0;
  321 
  322                 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
  323                 if (m == 0)
  324                         return 0;
  325 
  326                 ah = mtod(m, struct arc_header *);
  327                 ah->arc_flag = 0xFF;
  328                 ah->arc_seqid = 0xFFFF;
  329                 ah->arc_type2 = ac->arc_type;
  330                 ah->arc_flag2 = ac->sflag;
  331                 ah->arc_seqid2 = ac->ac_seqid;
  332         } else {
  333                 ac->curr_frag = 0;
  334 
  335                 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
  336                 if (m == 0)
  337                         return 0;
  338 
  339                 ah = mtod(m, struct arc_header *);
  340                 ah->arc_flag = ac->sflag;
  341                 ah->arc_seqid = ac->ac_seqid;
  342         }
  343 
  344         ah->arc_dhost = ac->arc_dhost;
  345         ah->arc_shost = ac->arc_shost;
  346         ah->arc_type = ac->arc_type;
  347 
  348         return m;
  349 }
  350 
  351 /*
  352  * Defragmenter. Returns mbuf if last packet found, else
  353  * NULL. frees imcoming mbuf as necessary.
  354  */
  355 
  356 static __inline struct mbuf *
  357 arc_defrag(ifp, m)
  358         struct ifnet *ifp;
  359         struct mbuf *m;
  360 {
  361         struct arc_header *ah, *ah1;
  362         struct arccom *ac;
  363         struct ac_frag *af;
  364         struct mbuf *m1;
  365         char *s;
  366         int newflen;
  367         u_char src,dst,typ;
  368 
  369         ac = (struct arccom *)ifp->if_l2com;
  370 
  371         if (m->m_len < ARC_HDRNEWLEN) {
  372                 m = m_pullup(m, ARC_HDRNEWLEN);
  373                 if (m == NULL) {
  374                         ++ifp->if_ierrors;
  375                         return NULL;
  376                 }
  377         }
  378 
  379         ah = mtod(m, struct arc_header *);
  380         typ = ah->arc_type;
  381 
  382         if (!arc_isphds(typ))
  383                 return m;
  384 
  385         src = ah->arc_shost;
  386         dst = ah->arc_dhost;
  387 
  388         if (ah->arc_flag == 0xff) {
  389                 m_adj(m, 4);
  390 
  391                 if (m->m_len < ARC_HDRNEWLEN) {
  392                         m = m_pullup(m, ARC_HDRNEWLEN);
  393                         if (m == NULL) {
  394                                 ++ifp->if_ierrors;
  395                                 return NULL;
  396                         }
  397                 }
  398 
  399                 ah = mtod(m, struct arc_header *);
  400         }
  401 
  402         af = &ac->ac_fragtab[src];
  403         m1 = af->af_packet;
  404         s = "debug code error";
  405 
  406         if (ah->arc_flag & 1) {
  407                 /*
  408                  * first fragment. We always initialize, which is
  409                  * about the right thing to do, as we only want to
  410                  * accept one fragmented packet per src at a time.
  411                  */
  412                 if (m1 != NULL)
  413                         m_freem(m1);
  414 
  415                 af->af_packet = m;
  416                 m1 = m;
  417                 af->af_maxflag = ah->arc_flag;
  418                 af->af_lastseen = 0;
  419                 af->af_seqid = ah->arc_seqid;
  420 
  421                 return NULL;
  422                 /* notreached */
  423         } else {
  424                 /* check for unfragmented packet */
  425                 if (ah->arc_flag == 0)
  426                         return m;
  427 
  428                 /* do we have a first packet from that src? */
  429                 if (m1 == NULL) {
  430                         s = "no first frag";
  431                         goto outofseq;
  432                 }
  433 
  434                 ah1 = mtod(m1, struct arc_header *);
  435 
  436                 if (ah->arc_seqid != ah1->arc_seqid) {
  437                         s = "seqid differs";
  438                         goto outofseq;
  439                 }
  440 
  441                 if (typ != ah1->arc_type) {
  442                         s = "type differs";
  443                         goto outofseq;
  444                 }
  445 
  446                 if (dst != ah1->arc_dhost) {
  447                         s = "dest host differs";
  448                         goto outofseq;
  449                 }
  450 
  451                 /* typ, seqid and dst are ok here. */
  452 
  453                 if (ah->arc_flag == af->af_lastseen) {
  454                         m_freem(m);
  455                         return NULL;
  456                 }
  457 
  458                 if (ah->arc_flag == af->af_lastseen + 2) {
  459                         /* ok, this is next fragment */
  460                         af->af_lastseen = ah->arc_flag;
  461                         m_adj(m,ARC_HDRNEWLEN);
  462 
  463                         /*
  464                          * m_cat might free the first mbuf (with pkthdr)
  465                          * in 2nd chain; therefore:
  466                          */
  467 
  468                         newflen = m->m_pkthdr.len;
  469 
  470                         m_cat(m1,m);
  471 
  472                         m1->m_pkthdr.len += newflen;
  473 
  474                         /* is it the last one? */
  475                         if (af->af_lastseen > af->af_maxflag) {
  476                                 af->af_packet = NULL;
  477                                 return(m1);
  478                         } else
  479                                 return NULL;
  480                 }
  481                 s = "other reason";
  482                 /* if all else fails, it is out of sequence, too */
  483         }
  484 outofseq:
  485         if (m1) {
  486                 m_freem(m1);
  487                 af->af_packet = NULL;
  488         }
  489 
  490         if (m)
  491                 m_freem(m);
  492 
  493         log(LOG_INFO,"%s: got out of seq. packet: %s\n",
  494             ifp->if_xname, s);
  495 
  496         return NULL;
  497 }
  498 
  499 /*
  500  * return 1 if Packet Header Definition Standard, else 0.
  501  * For now: old IP, old ARP aren't obviously. Lacking correct information,
  502  * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
  503  * (Apple and Novell corporations were involved, among others, in PHDS work).
  504  * Easiest is to assume that everybody else uses that, too.
  505  */
  506 int
  507 arc_isphds(type)
  508         u_int8_t type;
  509 {
  510         return (type != ARCTYPE_IP_OLD &&
  511                 type != ARCTYPE_ARP_OLD &&
  512                 type != ARCTYPE_DIAGNOSE);
  513 }
  514 
  515 /*
  516  * Process a received Arcnet packet;
  517  * the packet is in the mbuf chain m with
  518  * the ARCnet header.
  519  */
  520 void
  521 arc_input(ifp, m)
  522         struct ifnet *ifp;
  523         struct mbuf *m;
  524 {
  525         struct arc_header *ah;
  526         int isr;
  527         u_int8_t atype;
  528 
  529         if ((ifp->if_flags & IFF_UP) == 0) {
  530                 m_freem(m);
  531                 return;
  532         }
  533 
  534         /* possibly defragment: */
  535         m = arc_defrag(ifp, m);
  536         if (m == NULL)
  537                 return;
  538 
  539         BPF_MTAP(ifp, m);
  540 
  541         ah = mtod(m, struct arc_header *);
  542         /* does this belong to us? */
  543         if ((ifp->if_flags & IFF_PROMISC) == 0
  544             && ah->arc_dhost != arcbroadcastaddr
  545             && ah->arc_dhost != ARC_LLADDR(ifp)) {
  546                 m_freem(m);
  547                 return;
  548         }
  549 
  550         ifp->if_ibytes += m->m_pkthdr.len;
  551 
  552         if (ah->arc_dhost == arcbroadcastaddr) {
  553                 m->m_flags |= M_BCAST|M_MCAST;
  554                 ifp->if_imcasts++;
  555         }
  556 
  557         atype = ah->arc_type;
  558         switch (atype) {
  559 #ifdef INET
  560         case ARCTYPE_IP:
  561                 m_adj(m, ARC_HDRNEWLEN);
  562                 if (ip_fastforward(m))
  563                         return;
  564                 isr = NETISR_IP;
  565                 break;
  566 
  567         case ARCTYPE_IP_OLD:
  568                 m_adj(m, ARC_HDRLEN);
  569                 if (ip_fastforward(m))
  570                         return;
  571                 isr = NETISR_IP;
  572                 break;
  573 
  574         case ARCTYPE_ARP:
  575                 if (ifp->if_flags & IFF_NOARP) {
  576                         /* Discard packet if ARP is disabled on interface */
  577                         m_freem(m);
  578                         return;
  579                 }
  580                 m_adj(m, ARC_HDRNEWLEN);
  581                 isr = NETISR_ARP;
  582 #ifdef ARCNET_ALLOW_BROKEN_ARP
  583                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
  584 #endif
  585                 break;
  586 
  587         case ARCTYPE_ARP_OLD:
  588                 if (ifp->if_flags & IFF_NOARP) {
  589                         /* Discard packet if ARP is disabled on interface */
  590                         m_freem(m);
  591                         return;
  592                 }
  593                 m_adj(m, ARC_HDRLEN);
  594                 isr = NETISR_ARP;
  595 #ifdef ARCNET_ALLOW_BROKEN_ARP
  596                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
  597 #endif
  598                 break;
  599 #endif
  600 #ifdef INET6
  601         case ARCTYPE_INET6:
  602                 m_adj(m, ARC_HDRNEWLEN);
  603                 isr = NETISR_IPV6;
  604                 break;
  605 #endif
  606 #ifdef IPX
  607         case ARCTYPE_IPX:
  608                 m_adj(m, ARC_HDRNEWLEN);
  609                 isr = NETISR_IPX;
  610                 break;
  611 #endif
  612         default:
  613                 m_freem(m);
  614                 return;
  615         }
  616         netisr_dispatch(isr, m);
  617 }
  618 
  619 /*
  620  * Register (new) link level address.
  621  */
  622 void
  623 arc_storelladdr(ifp, lla)
  624         struct ifnet *ifp;
  625         u_int8_t lla;
  626 {
  627         ARC_LLADDR(ifp) = lla;
  628 }
  629 
  630 /*
  631  * Perform common duties while attaching to interface list
  632  */
  633 void
  634 arc_ifattach(ifp, lla)
  635         struct ifnet *ifp;
  636         u_int8_t lla;
  637 {
  638         struct ifaddr *ifa;
  639         struct sockaddr_dl *sdl;
  640         struct arccom *ac;
  641 
  642         if_attach(ifp);
  643         ifp->if_addrlen = 1;
  644         ifp->if_hdrlen = ARC_HDRLEN;
  645         ifp->if_mtu = 1500;
  646         ifp->if_resolvemulti = arc_resolvemulti;
  647         if (ifp->if_baudrate == 0)
  648                 ifp->if_baudrate = 2500000;
  649 #if __FreeBSD_version < 500000
  650         ifa = ifnet_addrs[ifp->if_index - 1];
  651 #else
  652         ifa = ifaddr_byindex(ifp->if_index);
  653 #endif
  654         KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
  655         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  656         sdl->sdl_type = IFT_ARCNET;
  657         sdl->sdl_alen = ifp->if_addrlen;
  658 
  659         if (ifp->if_flags & IFF_BROADCAST)
  660                 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
  661 
  662         ac = (struct arccom *)ifp->if_l2com;
  663         ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
  664         if (lla == 0) {
  665                 /* XXX this message isn't entirely clear, to me -- cgd */
  666                 log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
  667                    ifp->if_xname, ifp->if_xname);
  668         }
  669         arc_storelladdr(ifp, lla);
  670 
  671         ifp->if_broadcastaddr = &arcbroadcastaddr;
  672 
  673         bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
  674 }
  675 
  676 void
  677 arc_ifdetach(ifp)
  678         struct ifnet *ifp;
  679 {
  680         bpfdetach(ifp);
  681         if_detach(ifp);
  682 }
  683 
  684 int
  685 arc_ioctl(ifp, command, data)
  686         struct ifnet *ifp;
  687         int command;
  688         caddr_t data;
  689 {
  690         struct ifaddr *ifa = (struct ifaddr *) data;
  691         struct ifreq *ifr = (struct ifreq *) data;
  692         int error = 0;
  693 
  694         switch (command) {
  695         case SIOCSIFADDR:
  696                 ifp->if_flags |= IFF_UP;
  697                 switch (ifa->ifa_addr->sa_family) {
  698 #ifdef INET
  699                 case AF_INET:
  700                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
  701                         arp_ifinit(ifp, ifa);
  702                         break;
  703 #endif
  704 #ifdef IPX
  705                 /*
  706                  * XXX This code is probably wrong
  707                  */
  708                 case AF_IPX:
  709                 {
  710                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
  711 
  712                         if (ipx_nullhost(*ina))
  713                                 ina->x_host.c_host[5] = ARC_LLADDR(ifp);
  714                         else
  715                                 arc_storelladdr(ifp, ina->x_host.c_host[5]);
  716 
  717                         /*
  718                          * Set new address
  719                          */
  720                         ifp->if_init(ifp->if_softc);
  721                         break;
  722                 }
  723 #endif
  724                 default:
  725                         ifp->if_init(ifp->if_softc);
  726                         break;
  727                 }
  728                 break;
  729 
  730         case SIOCGIFADDR:
  731                 {
  732                         struct sockaddr *sa;
  733 
  734                         sa = (struct sockaddr *) &ifr->ifr_data;
  735                         *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
  736                 }
  737                 break;
  738 
  739         case SIOCADDMULTI:
  740         case SIOCDELMULTI:
  741                 if (ifr == NULL)
  742                         error = EAFNOSUPPORT;
  743                 else {
  744                         switch (ifr->ifr_addr.sa_family) {
  745                         case AF_INET:
  746                         case AF_INET6:
  747                                 error = 0;
  748                                 break;
  749                         default:
  750                                 error = EAFNOSUPPORT;
  751                                 break;
  752                         }
  753                 }
  754                 break;
  755 
  756         case SIOCSIFMTU:
  757                 /*
  758                  * Set the interface MTU.
  759                  * mtu can't be larger than ARCMTU for RFC1051
  760                  * and can't be larger than ARC_PHDS_MTU
  761                  */
  762                 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
  763                     ifr->ifr_mtu > ARC_PHDS_MAXMTU)
  764                         error = EINVAL;
  765                 else
  766                         ifp->if_mtu = ifr->ifr_mtu;
  767                 break;
  768         }
  769 
  770         return (error);
  771 }
  772 
  773 /* based on ether_resolvemulti() */
  774 int
  775 arc_resolvemulti(ifp, llsa, sa)
  776         struct ifnet *ifp;
  777         struct sockaddr **llsa;
  778         struct sockaddr *sa;
  779 {
  780         struct sockaddr_dl *sdl;
  781         struct sockaddr_in *sin;
  782 #ifdef INET6
  783         struct sockaddr_in6 *sin6;
  784 #endif
  785 
  786         switch(sa->sa_family) {
  787         case AF_LINK:
  788                 /*
  789                 * No mapping needed. Just check that it's a valid MC address.
  790                 */
  791                 sdl = (struct sockaddr_dl *)sa;
  792                 if (*LLADDR(sdl) != arcbroadcastaddr)
  793                         return EADDRNOTAVAIL;
  794                 *llsa = 0;
  795                 return 0;
  796 #ifdef INET
  797         case AF_INET:
  798                 sin = (struct sockaddr_in *)sa;
  799                 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
  800                         return EADDRNOTAVAIL;
  801                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
  802                        M_NOWAIT | M_ZERO);
  803                 if (sdl == NULL)
  804                         return ENOMEM;
  805                 sdl->sdl_len = sizeof *sdl;
  806                 sdl->sdl_family = AF_LINK;
  807                 sdl->sdl_index = ifp->if_index;
  808                 sdl->sdl_type = IFT_ARCNET;
  809                 sdl->sdl_alen = ARC_ADDR_LEN;
  810                 *LLADDR(sdl) = 0;
  811                 *llsa = (struct sockaddr *)sdl;
  812                 return 0;
  813 #endif
  814 #ifdef INET6
  815         case AF_INET6:
  816                 sin6 = (struct sockaddr_in6 *)sa;
  817                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  818                         /*
  819                          * An IP6 address of 0 means listen to all
  820                          * of the Ethernet multicast address used for IP6.
  821                          * (This is used for multicast routers.)
  822                          */
  823                         ifp->if_flags |= IFF_ALLMULTI;
  824                         *llsa = 0;
  825                         return 0;
  826                 }
  827                 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
  828                         return EADDRNOTAVAIL;
  829                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
  830                        M_NOWAIT | M_ZERO);
  831                 if (sdl == NULL)
  832                         return ENOMEM;
  833                 sdl->sdl_len = sizeof *sdl;
  834                 sdl->sdl_family = AF_LINK;
  835                 sdl->sdl_index = ifp->if_index;
  836                 sdl->sdl_type = IFT_ARCNET;
  837                 sdl->sdl_alen = ARC_ADDR_LEN;
  838                 *LLADDR(sdl) = 0;
  839                 *llsa = (struct sockaddr *)sdl;
  840                 return 0;
  841 #endif
  842 
  843         default:
  844                 /*
  845                  * Well, the text isn't quite right, but it's the name
  846                  * that counts...
  847                  */
  848                 return EAFNOSUPPORT;
  849         }
  850 }
  851 
  852 MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals");
  853 
  854 static void*
  855 arc_alloc(u_char type, struct ifnet *ifp)
  856 {
  857         struct arccom   *ac;
  858         
  859         ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO);
  860         ac->ac_ifp = ifp;
  861 
  862         return (ac);
  863 }
  864 
  865 static void
  866 arc_free(void *com, u_char type)
  867 {
  868 
  869         free(com, M_ARCCOM);
  870 }
  871 
  872 static int
  873 arc_modevent(module_t mod, int type, void *data)
  874 {
  875 
  876         switch (type) {
  877         case MOD_LOAD:
  878                 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free);
  879                 break;
  880         case MOD_UNLOAD:
  881                 if_deregister_com_alloc(IFT_ARCNET);
  882                 break;
  883         default:
  884                 return EOPNOTSUPP;
  885         }
  886 
  887         return (0);
  888 }
  889 
  890 static moduledata_t arc_mod = {
  891         "arcnet",
  892         arc_modevent,
  893         0
  894 };
  895 
  896 DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
  897 MODULE_VERSION(arcnet, 1);

Cache object: 8620cefbdf26c99afe8dbb648426b779


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.