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_ieee1394subr.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_ieee1394subr.c,v 1.32 2006/06/07 22:33:42 kardel Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Atsushi Onoe.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: if_ieee1394subr.c,v 1.32 2006/06/07 22:33:42 kardel Exp $");
   41 
   42 #include "opt_inet.h"
   43 #include "bpfilter.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/socket.h>
   48 #include <sys/sockio.h>
   49 #include <sys/kernel.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/device.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_dl.h>
   55 #include <net/if_ieee1394.h>
   56 #include <net/if_types.h>
   57 #include <net/if_media.h>
   58 #include <net/ethertypes.h>
   59 #include <net/netisr.h>
   60 #include <net/route.h>
   61 
   62 #if NBPFILTER > 0
   63 #include <net/bpf.h>
   64 #endif
   65 
   66 #ifdef INET
   67 #include <netinet/in.h>
   68 #include <netinet/in_var.h>
   69 #include <netinet/if_inarp.h>
   70 #endif /* INET */
   71 #ifdef INET6
   72 #include <netinet/in.h>
   73 #include <netinet6/in6_var.h>
   74 #include <netinet6/nd6.h>
   75 #endif /* INET6 */
   76 
   77 #include <dev/ieee1394/fw_port.h>
   78 #include <dev/ieee1394/firewire.h>
   79 
   80 #include <dev/ieee1394/firewirereg.h>
   81 #include <dev/ieee1394/iec13213.h>
   82 #include <dev/ieee1394/if_fwipvar.h>
   83 
   84 #define IEEE1394_REASS_TIMEOUT  3       /* 3 sec */
   85 
   86 #define senderr(e)      do { error = (e); goto bad; } while(0/*CONSTCOND*/)
   87 
   88 static int  ieee1394_output(struct ifnet *, struct mbuf *, struct sockaddr *,
   89                 struct rtentry *);
   90 static struct mbuf *ieee1394_reass(struct ifnet *, struct mbuf *, u_int16_t);
   91 
   92 static int
   93 ieee1394_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
   94     struct rtentry *rt0)
   95 {
   96         u_int16_t etype = 0;
   97         struct mbuf *m;
   98         int s, hdrlen, error = 0;
   99         struct rtentry *rt;
  100         struct mbuf *mcopy = NULL;
  101         struct ieee1394_hwaddr *hwdst, *myaddr, baddr;
  102         ALTQ_DECL(struct altq_pktattr pktattr;)
  103 #ifdef INET
  104         struct arphdr *ah;
  105 #endif /* INET */
  106         struct m_tag *mtag;
  107         int unicast;
  108 
  109         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  110                 senderr(ENETDOWN);
  111         if ((rt = rt0) != NULL) {
  112                 if ((rt->rt_flags & RTF_UP) == 0) {
  113                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
  114                                 rt->rt_refcnt--;
  115                                 if (rt->rt_ifp != ifp)
  116                                         return (*rt->rt_ifp->if_output)
  117                                                         (ifp, m0, dst, rt);
  118                         } else
  119                                 senderr(EHOSTUNREACH);
  120                 }
  121                 if (rt->rt_flags & RTF_GATEWAY) {
  122                         if (rt->rt_gwroute == NULL)
  123                                 goto lookup;
  124                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  125                                 rtfree(rt);
  126                                 rt = rt0;
  127   lookup:
  128                                 rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
  129                                 if ((rt = rt->rt_gwroute) == NULL)
  130                                         senderr(EHOSTUNREACH);
  131                                 /* the "G" test below also prevents rt == rt0 */
  132                                 if ((rt->rt_flags & RTF_GATEWAY) ||
  133                                     (rt->rt_ifp != ifp)) {
  134                                         rt->rt_refcnt--;
  135                                         rt0->rt_gwroute = NULL;
  136                                         senderr(EHOSTUNREACH);
  137                                 }
  138                         }
  139                 }
  140                 if (rt->rt_flags & RTF_REJECT)
  141                         if (rt->rt_rmx.rmx_expire == 0 ||
  142                             time_second < rt->rt_rmx.rmx_expire)
  143                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  144         }
  145 
  146         /*
  147          * If the queueing discipline needs packet classification,
  148          * do it before prepending link headers.
  149          */
  150         IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family, &pktattr);
  151 
  152         /*
  153          * For unicast, we make a tag to store the lladdr of the
  154          * destination. This might not be the first time we have seen
  155          * the packet (for instance, the arp code might be trying to
  156          * re-send it after receiving an arp reply) so we only
  157          * allocate a tag if there isn't one there already. For
  158          * multicast, we will eventually use a different tag to store
  159          * the channel number.
  160          */
  161         unicast = !(m0->m_flags & (M_BCAST | M_MCAST));
  162         if (unicast) {
  163                 mtag =
  164                     m_tag_locate(m0, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL);
  165                 if (!mtag) {
  166                         mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR,
  167                             sizeof (struct ieee1394_hwaddr), M_NOWAIT);
  168                         if (!mtag) {
  169                                 error = ENOMEM;
  170                                 goto bad;
  171                         }
  172                         m_tag_prepend(m0, mtag);
  173                 }
  174                 hwdst = (struct ieee1394_hwaddr *)(mtag + 1);
  175         } else {
  176                 hwdst = &baddr;
  177         }
  178 
  179         switch (dst->sa_family) {
  180 #ifdef INET
  181         case AF_INET:
  182                 if (unicast && (!arpresolve(ifp, rt, m0, dst, (u_char *)hwdst)))
  183                         return 0;       /* if not yet resolved */
  184                 /* if broadcasting on a simplex interface, loopback a copy */
  185                 if ((m0->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
  186                         mcopy = m_copy(m0, 0, M_COPYALL);
  187                 etype = htons(ETHERTYPE_IP);
  188                 break;
  189         case AF_ARP:
  190                 ah = mtod(m0, struct arphdr *);
  191                 ah->ar_hrd = htons(ARPHRD_IEEE1394);
  192                 etype = htons(ETHERTYPE_ARP);
  193                 break;
  194 #endif /* INET */
  195 #ifdef INET6
  196         case AF_INET6:
  197                 if (unicast &&
  198                     (!nd6_storelladdr(ifp, rt, m0, dst, (u_char *)hwdst))) {
  199                         /* something bad happened */
  200                         return 0;
  201                 }
  202                 etype = htons(ETHERTYPE_IPV6);
  203                 break;
  204 #endif /* INET6 */
  205 
  206         case pseudo_AF_HDRCMPLT:
  207         case AF_UNSPEC:
  208                 /* TODO? */
  209         default:
  210                 printf("%s: can't handle af%d\n", ifp->if_xname,
  211                     dst->sa_family);
  212                 senderr(EAFNOSUPPORT);
  213                 break;
  214         }
  215 
  216         if (mcopy)
  217                 looutput(ifp, mcopy, dst, rt);
  218         myaddr = (struct ieee1394_hwaddr *)LLADDR(ifp->if_sadl);
  219 #if NBPFILTER > 0
  220         if (ifp->if_bpf) {
  221                 struct ieee1394_bpfhdr h;
  222                 if (unicast)
  223                         memcpy(h.ibh_dhost, hwdst->iha_uid, 8);
  224                 else
  225                         memcpy(h.ibh_dhost,
  226                             ((const struct ieee1394_hwaddr *)
  227                             ifp->if_broadcastaddr)->iha_uid, 8);
  228                 memcpy(h.ibh_shost, myaddr->iha_uid, 8);
  229                 h.ibh_type = etype;
  230                 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m0);
  231         }
  232 #endif
  233         if ((ifp->if_flags & IFF_SIMPLEX) &&
  234             unicast &&
  235             memcmp(hwdst, myaddr, IEEE1394_ADDR_LEN) == 0)
  236                 return looutput(ifp, m0, dst, rt);
  237 
  238         /*
  239          * XXX:
  240          * The maximum possible rate depends on the topology.
  241          * So the determination of maxrec and fragmentation should be
  242          * called from the driver after probing the topology map.
  243          */
  244         if (unicast) {
  245                 hdrlen = IEEE1394_GASP_LEN;
  246                 hwdst->iha_speed = 0;   /* XXX */
  247         } else
  248                 hdrlen = 0;
  249 
  250         if (hwdst->iha_speed > myaddr->iha_speed)
  251                 hwdst->iha_speed = myaddr->iha_speed;
  252         if (hwdst->iha_maxrec > myaddr->iha_maxrec)
  253                 hwdst->iha_maxrec = myaddr->iha_maxrec;
  254         if (hwdst->iha_maxrec > (8 + hwdst->iha_speed))
  255                 hwdst->iha_maxrec = 8 + hwdst->iha_speed;
  256         if (hwdst->iha_maxrec < 8)
  257                         hwdst->iha_maxrec = 8;
  258 
  259         m0 = ieee1394_fragment(ifp, m0, (2<<hwdst->iha_maxrec) - hdrlen, etype);
  260         if (m0 == NULL)
  261                 senderr(ENOBUFS);
  262 
  263         s = splnet();
  264         ifp->if_obytes += m0->m_pkthdr.len;
  265         if (m0->m_flags & M_MCAST)
  266                 ifp->if_omcasts++;
  267         while ((m = m0) != NULL) {
  268                 m0 = m->m_nextpkt;
  269                 if (m == NULL) {
  270                         splx(s);
  271                         senderr(ENOBUFS);
  272                 }
  273                 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
  274                 if (error) {
  275                         /* mbuf is already freed */
  276                         splx(s);
  277                         goto bad;
  278                 }
  279         }
  280         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  281                 (*ifp->if_start)(ifp);
  282         splx(s);
  283         return 0;
  284 
  285   bad:
  286         while (m0 != NULL) {
  287                 m = m0->m_nextpkt;
  288                 m_freem(m0);
  289                 m0 = m;
  290         }
  291 
  292         return error;
  293 }
  294 
  295 struct mbuf *
  296 ieee1394_fragment(struct ifnet *ifp, struct mbuf *m0, int maxsize,
  297     u_int16_t etype)
  298 {
  299         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  300         int totlen, fraglen, off;
  301         struct mbuf *m, **mp;
  302         struct ieee1394_fraghdr *ifh;
  303         struct ieee1394_unfraghdr *iuh;
  304 
  305         totlen = m0->m_pkthdr.len;
  306         if (totlen + sizeof(struct ieee1394_unfraghdr) <= maxsize) {
  307                 M_PREPEND(m0, sizeof(struct ieee1394_unfraghdr), M_DONTWAIT);
  308                 if (m0 == NULL)
  309                         goto bad;
  310                 iuh = mtod(m0, struct ieee1394_unfraghdr *);
  311                 iuh->iuh_ft = 0;
  312                 iuh->iuh_etype = etype;
  313                 return m0;
  314         }
  315 
  316         fraglen = maxsize - sizeof(struct ieee1394_fraghdr);
  317 
  318         M_PREPEND(m0, sizeof(struct ieee1394_fraghdr), M_DONTWAIT);
  319         if (m0 == NULL)
  320                 goto bad;
  321         ifh = mtod(m0, struct ieee1394_fraghdr *);
  322         ifh->ifh_ft_size = htons(IEEE1394_FT_MORE | (totlen - 1));
  323         ifh->ifh_etype_off = etype;
  324         ifh->ifh_dgl = htons(ic->ic_dgl);
  325         ifh->ifh_reserved = 0;
  326         off = fraglen;
  327         mp = &m0->m_nextpkt;
  328         while (off < totlen) {
  329                 if (off + fraglen > totlen)
  330                         fraglen = totlen - off;
  331                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
  332                 if (m == NULL)
  333                         goto bad;
  334                 m->m_flags |= m0->m_flags & (M_BCAST|M_MCAST);  /* copy bcast */
  335                 MH_ALIGN(m, sizeof(struct ieee1394_fraghdr));
  336                 m->m_len = sizeof(struct ieee1394_fraghdr);
  337                 ifh = mtod(m, struct ieee1394_fraghdr *);
  338                 ifh->ifh_ft_size =
  339                     htons(IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE | (totlen - 1));
  340                 ifh->ifh_etype_off = htons(off);
  341                 ifh->ifh_dgl = htons(ic->ic_dgl);
  342                 ifh->ifh_reserved = 0;
  343                 m->m_next = m_copy(m0, sizeof(*ifh) + off, fraglen);
  344                 if (m->m_next == NULL)
  345                         goto bad;
  346                 m->m_pkthdr.len = sizeof(*ifh) + fraglen;
  347                 off += fraglen;
  348                 *mp = m;
  349                 mp = &m->m_nextpkt;
  350         }
  351         ifh->ifh_ft_size &= ~htons(IEEE1394_FT_MORE);   /* last fragment */
  352         m_adj(m0, -(m0->m_pkthdr.len - maxsize));
  353 
  354         ic->ic_dgl++;
  355         return m0;
  356 
  357   bad:
  358         while ((m = m0) != NULL) {
  359                 m0 = m->m_nextpkt;
  360                 m->m_nextpkt = NULL;
  361                 m_freem(m);
  362         }
  363         return NULL;
  364 }
  365 
  366 void
  367 ieee1394_input(struct ifnet *ifp, struct mbuf *m, u_int16_t src)
  368 {
  369         struct ifqueue *inq;
  370         u_int16_t etype;
  371         int s;
  372         struct ieee1394_unfraghdr *iuh;
  373 
  374         if ((ifp->if_flags & IFF_UP) == 0) {
  375                 m_freem(m);
  376                 return;
  377         }
  378         if (m->m_len < sizeof(*iuh)) {
  379                 if ((m = m_pullup(m, sizeof(*iuh))) == NULL)
  380                         return;
  381         }
  382 
  383         iuh = mtod(m, struct ieee1394_unfraghdr *);
  384 
  385         if (ntohs(iuh->iuh_ft) & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE)) {
  386                 if ((m = ieee1394_reass(ifp, m, src)) == NULL)
  387                         return;
  388                 iuh = mtod(m, struct ieee1394_unfraghdr *);
  389         }
  390         etype = ntohs(iuh->iuh_etype);
  391 
  392         /* strip off the ieee1394 header */
  393         m_adj(m, sizeof(*iuh));
  394 #if NBPFILTER > 0
  395         if (ifp->if_bpf) {
  396                 struct ieee1394_bpfhdr h;
  397                 struct m_tag *mtag;
  398                 struct ieee1394_hwaddr *myaddr;
  399 
  400                 mtag = m_tag_locate(m,
  401                     MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0);
  402                 if (mtag)
  403                         memcpy(h.ibh_shost, mtag + 1, 8);
  404                 else
  405                         memset(h.ibh_shost, 0, 8);
  406                 if (m->m_flags & M_BCAST)
  407                         memcpy(h.ibh_dhost,
  408                             ((const struct ieee1394_hwaddr *)
  409                             ifp->if_broadcastaddr)->iha_uid, 8);
  410                 else {
  411                         myaddr = (struct ieee1394_hwaddr *)LLADDR(ifp->if_sadl);
  412                         memcpy(h.ibh_dhost, myaddr->iha_uid, 8);
  413                 }
  414                 h.ibh_type = htons(etype);
  415                 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m);
  416         }
  417 #endif
  418 
  419         switch (etype) {
  420 #ifdef INET
  421         case ETHERTYPE_IP:
  422                 schednetisr(NETISR_IP);
  423                 inq = &ipintrq;
  424                 break;
  425 
  426         case ETHERTYPE_ARP:
  427                 schednetisr(NETISR_ARP);
  428                 inq = &arpintrq;
  429                 break;
  430 #endif /* INET */
  431 
  432 #ifdef INET6
  433         case ETHERTYPE_IPV6:
  434                 schednetisr(NETISR_IPV6);
  435                 inq = &ip6intrq;
  436                 break;
  437 #endif /* INET6 */
  438 
  439         default:
  440                 m_freem(m);
  441                 return;
  442         }
  443 
  444         s = splnet();
  445         if (IF_QFULL(inq)) {
  446                 IF_DROP(inq);
  447                 m_freem(m);
  448         } else
  449                 IF_ENQUEUE(inq, m);
  450         splx(s);
  451 }
  452 
  453 static struct mbuf *
  454 ieee1394_reass(struct ifnet *ifp, struct mbuf *m0, u_int16_t src)
  455 {
  456         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  457         struct ieee1394_fraghdr *ifh;
  458         struct ieee1394_unfraghdr *iuh;
  459         struct ieee1394_reassq *rq;
  460         struct ieee1394_reass_pkt *rp, *trp, *nrp = NULL;
  461         int len;
  462         u_int16_t etype, off, ftype, size, dgl;
  463         u_int32_t id;
  464 
  465         if (m0->m_len < sizeof(*ifh)) {
  466                 if ((m0 = m_pullup(m0, sizeof(*ifh))) == NULL)
  467                         return NULL;
  468         }
  469         ifh = mtod(m0, struct ieee1394_fraghdr *);
  470         m_adj(m0, sizeof(*ifh));
  471         size = ntohs(ifh->ifh_ft_size);
  472         ftype = size & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE);
  473         size = (size & ~ftype) + 1;
  474         dgl = ntohs(ifh->ifh_dgl);
  475         len = m0->m_pkthdr.len;
  476         id = dgl | (src << 16);
  477         if (ftype & IEEE1394_FT_SUBSEQ) {
  478                 m_tag_delete_chain(m0, NULL);
  479                 m0->m_flags &= ~M_PKTHDR;
  480                 etype = 0;
  481                 off = ntohs(ifh->ifh_etype_off);
  482         } else {
  483                 etype = ifh->ifh_etype_off;
  484                 off = 0;
  485         }
  486 
  487         for (rq = LIST_FIRST(&ic->ic_reassq); ; rq = LIST_NEXT(rq, rq_node)) {
  488                 if (rq == NULL) {
  489                         /*
  490                          * Create a new reassemble queue head for the node.
  491                          */
  492                         rq = malloc(sizeof(*rq), M_FTABLE, M_NOWAIT);
  493                         if (rq == NULL) {
  494                                 m_freem(m0);
  495                                 return NULL;
  496                         }
  497                         rq->fr_id = id;
  498                         LIST_INIT(&rq->rq_pkt);
  499                         LIST_INSERT_HEAD(&ic->ic_reassq, rq, rq_node);
  500                         break;
  501                 }
  502                 if (rq->fr_id == id)
  503                         break;
  504         }
  505         for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
  506                 nrp = LIST_NEXT(rp, rp_next);
  507                 if (rp->rp_dgl != dgl)
  508                         continue;
  509                 /*
  510                  * sanity check:
  511                  * datagram size must be same for all fragments, and
  512                  * no overlap is allowed.
  513                  */
  514                 if (rp->rp_size != size ||
  515                     (off < rp->rp_off + rp->rp_len && off + len > rp->rp_off)) {
  516                         /*
  517                          * This happens probably due to wrapping dgl value.
  518                          * Destroy all previously received fragment and
  519                          * enqueue current fragment.
  520                          */
  521                         for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL;
  522                             rp = nrp) {
  523                                 nrp = LIST_NEXT(rp, rp_next);
  524                                 if (rp->rp_dgl == dgl) {
  525                                         LIST_REMOVE(rp, rp_next);
  526                                         m_freem(rp->rp_m);
  527                                         free(rp, M_FTABLE);
  528                                 }
  529                         }
  530                         break;
  531                 }
  532                 if (rp->rp_off + rp->rp_len == off) {
  533                         /*
  534                          * All the subsequent fragments received in sequence
  535                          * come here.
  536                          * Concatinate mbuf to previous one instead of
  537                          * allocating new reassemble queue structure,
  538                          * and try to merge more with the subsequent fragment
  539                          * in the queue.
  540                          */
  541                         m_cat(rp->rp_m, m0);
  542                         rp->rp_len += len;
  543                         while (rp->rp_off + rp->rp_len < size &&
  544                             nrp != NULL && nrp->rp_dgl == dgl &&
  545                             nrp->rp_off == rp->rp_off + rp->rp_len) {
  546                                 LIST_REMOVE(nrp, rp_next);
  547                                 m_cat(rp->rp_m, nrp->rp_m);
  548                                 rp->rp_len += nrp->rp_len;
  549                                 free(nrp, M_FTABLE);
  550                                 nrp = LIST_NEXT(rp, rp_next);
  551                         }
  552                         m0 = NULL;      /* mark merged */
  553                         break;
  554                 }
  555                 if (off + m0->m_pkthdr.len == rp->rp_off) {
  556                         m_cat(m0, rp->rp_m);
  557                         rp->rp_m = m0;
  558                         rp->rp_off = off;
  559                         rp->rp_etype = etype;    /* over writing trust etype */
  560                         rp->rp_len += len;
  561                         m0 = NULL;      /* mark merged */
  562                         break;
  563                 }
  564                 if (rp->rp_off > off) {
  565                         /* insert before rp */
  566                         nrp = rp;
  567                         break;
  568                 }
  569                 if (nrp == NULL || nrp->rp_dgl != dgl) {
  570                         /* insert after rp */
  571                         nrp = NULL;
  572                         break;
  573                 }
  574         }
  575         if (m0 == NULL) {
  576                 if (rp->rp_off != 0 || rp->rp_len != size)
  577                         return NULL;
  578                 /* fragment done */
  579                 LIST_REMOVE(rp, rp_next);
  580                 m0 = rp->rp_m;
  581                 m0->m_pkthdr.len = rp->rp_len;
  582                 M_PREPEND(m0, sizeof(*iuh), M_DONTWAIT);
  583                 if (m0 != NULL) {
  584                         iuh = mtod(m0, struct ieee1394_unfraghdr *);
  585                         iuh->iuh_ft = 0;
  586                         iuh->iuh_etype = rp->rp_etype;
  587                 }
  588                 free(rp, M_FTABLE);
  589                 return m0;
  590         }
  591 
  592         /*
  593          * New fragment received.  Allocate reassemble queue structure.
  594          */
  595         trp = malloc(sizeof(*trp), M_FTABLE, M_NOWAIT);
  596         if (trp == NULL) {
  597                 m_freem(m0);
  598                 return NULL;
  599         }
  600         trp->rp_m = m0;
  601         trp->rp_size = size;
  602         trp->rp_etype = etype;           /* valid only if off==0 */
  603         trp->rp_off = off;
  604         trp->rp_dgl = dgl;
  605         trp->rp_len = len;
  606         trp->rp_ttl = IEEE1394_REASS_TIMEOUT;
  607         if (trp->rp_ttl <= ifp->if_timer)
  608                 trp->rp_ttl = ifp->if_timer + 1;
  609 
  610         if (rp == NULL) {
  611                 /* first fragment for the dgl */
  612                 LIST_INSERT_HEAD(&rq->rq_pkt, trp, rp_next);
  613         } else if (nrp == NULL) {
  614                 /* no next fragment for the dgl */
  615                 LIST_INSERT_AFTER(rp, trp, rp_next);
  616         } else {
  617                 /* there is a hole */
  618                 LIST_INSERT_BEFORE(nrp, trp, rp_next);
  619         }
  620         return NULL;
  621 }
  622 
  623 void
  624 ieee1394_drain(struct ifnet *ifp)
  625 {
  626         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  627         struct ieee1394_reassq *rq;
  628         struct ieee1394_reass_pkt *rp;
  629 
  630         while ((rq = LIST_FIRST(&ic->ic_reassq)) != NULL) {
  631                 LIST_REMOVE(rq, rq_node);
  632                 while ((rp = LIST_FIRST(&rq->rq_pkt)) != NULL) {
  633                         LIST_REMOVE(rp, rp_next);
  634                         m_freem(rp->rp_m);
  635                         free(rp, M_FTABLE);
  636                 }
  637                 free(rq, M_FTABLE);
  638         }
  639 }
  640 
  641 void
  642 ieee1394_watchdog(struct ifnet *ifp)
  643 {
  644         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  645         struct ieee1394_reassq *rq;
  646         struct ieee1394_reass_pkt *rp, *nrp;
  647         int dec;
  648 
  649         dec = (ifp->if_timer > 0) ? ifp->if_timer : 1;
  650         for (rq = LIST_FIRST(&ic->ic_reassq); rq != NULL;
  651             rq = LIST_NEXT(rq, rq_node)) {
  652                 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
  653                         nrp = LIST_NEXT(rp, rp_next);
  654                         if (rp->rp_ttl >= dec)
  655                                 rp->rp_ttl -= dec;
  656                         else {
  657                                 LIST_REMOVE(rp, rp_next);
  658                                 m_freem(rp->rp_m);
  659                                 free(rp, M_FTABLE);
  660                         }
  661                 }
  662         }
  663 }
  664 
  665 const char *
  666 ieee1394_sprintf(const u_int8_t *laddr)
  667 {
  668         static char buf[3*8];
  669 
  670         snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
  671             laddr[0], laddr[1], laddr[2], laddr[3],
  672             laddr[4], laddr[5], laddr[6], laddr[7]);
  673         return buf;
  674 }
  675 
  676 void
  677 ieee1394_ifattach(struct ifnet *ifp, const struct ieee1394_hwaddr *hwaddr)
  678 {
  679         struct ieee1394_hwaddr *baddr;
  680         struct ieee1394com *ic = (struct ieee1394com *)ifp;
  681 
  682         ifp->if_type = IFT_IEEE1394;
  683         ifp->if_addrlen = sizeof(struct ieee1394_hwaddr);
  684         ifp->if_hdrlen = sizeof(struct ieee1394_header);
  685         ifp->if_dlt = DLT_EN10MB;       /* XXX */
  686         ifp->if_mtu = IEEE1394MTU;
  687         ifp->if_output = ieee1394_output;
  688         ifp->if_drain = ieee1394_drain;
  689         ifp->if_watchdog = ieee1394_watchdog;
  690         ifp->if_timer = 1;
  691         if (ifp->if_baudrate == 0)
  692                 ifp->if_baudrate = IF_Mbps(100);
  693 
  694         if_alloc_sadl(ifp);
  695         memcpy(LLADDR(ifp->if_sadl), hwaddr, ifp->if_addrlen);
  696 
  697         baddr = malloc(ifp->if_addrlen, M_DEVBUF, M_WAITOK);
  698         memset(baddr->iha_uid, 0xff, IEEE1394_ADDR_LEN);
  699         baddr->iha_speed = 0;   /*XXX: how to determine the speed for bcast? */
  700         baddr->iha_maxrec = 512 << baddr->iha_speed;
  701         memset(baddr->iha_offset, 0, sizeof(baddr->iha_offset));
  702         ifp->if_broadcastaddr = (uint8_t *)baddr;
  703         LIST_INIT(&ic->ic_reassq);
  704 #if NBPFILTER > 0
  705         bpfattach(ifp,
  706             DLT_APPLE_IP_OVER_IEEE1394, sizeof(struct ieee1394_hwaddr));
  707 #endif
  708 }
  709 
  710 void
  711 ieee1394_ifdetach(struct ifnet *ifp)
  712 {
  713         ieee1394_drain(ifp);
  714 #if NBPFILTER > 0
  715         bpfdetach(ifp);
  716 #endif
  717         free(__UNCONST(ifp->if_broadcastaddr), M_DEVBUF);
  718         ifp->if_broadcastaddr = NULL;
  719 #if 0   /* done in if_detach() */
  720         if_free_sadl(ifp);
  721 #endif
  722 }
  723 
  724 int
  725 ieee1394_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  726 {
  727         struct ifreq *ifr = (struct ifreq *)data;
  728         struct ifaddr *ifa = (struct ifaddr *)data;
  729         int error = 0;
  730 #if __NetBSD_Version__ < 105080000
  731         int fw_init(struct ifnet *);
  732         void fw_stop(struct ifnet *, int);
  733 #endif
  734 
  735         switch (cmd) {
  736         case SIOCSIFADDR:
  737                 ifp->if_flags |= IFF_UP;
  738                 switch (ifa->ifa_addr->sa_family) {
  739 #ifdef INET
  740                 case AF_INET:
  741 #if __NetBSD_Version__ >= 105080000
  742                         if ((error = (*ifp->if_init)(ifp)) != 0)
  743 #else
  744                         if ((error = fw_init(ifp)) != 0)
  745 #endif
  746                                 break;
  747                         arp_ifinit(ifp, ifa);
  748                         break;
  749 #endif /* INET */
  750                 default:
  751 #if __NetBSD_Version__ >= 105080000
  752                         error = (*ifp->if_init)(ifp);
  753 #else
  754                         error = fw_init(ifp);
  755 #endif
  756                         break;
  757                 }
  758                 break;
  759 
  760         case SIOCGIFADDR:
  761                 memcpy(((struct sockaddr *)&ifr->ifr_data)->sa_data,
  762                     LLADDR(ifp->if_sadl), IEEE1394_ADDR_LEN);
  763                     break;
  764 
  765         case SIOCSIFMTU:
  766                 if (ifr->ifr_mtu > IEEE1394MTU)
  767                         error = EINVAL;
  768                 else
  769                         ifp->if_mtu = ifr->ifr_mtu;
  770                 break;
  771 
  772         default:
  773                 error = ENOTTY;
  774                 break;
  775         }
  776 
  777         return error;
  778 }

Cache object: 9f53494e62c2c57e49cba9b08e27795f


[ 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.