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

Cache object: 9187bed812759fdfedb9bdfaf4e77718


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