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_ecosubr.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_ecosubr.c,v 1.15 2005/02/26 22:45:09 perry Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 2001 Ben Harris
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 /*
   30  * Copyright (c) 1982, 1989, 1993
   31  *      The Regents of the University of California.  All rights reserved.
   32  *
   33  * Redistribution and use in source and binary forms, with or without
   34  * modification, are permitted provided that the following conditions
   35  * are met:
   36  * 1. Redistributions of source code must retain the above copyright
   37  *    notice, this list of conditions and the following disclaimer.
   38  * 2. Redistributions in binary form must reproduce the above copyright
   39  *    notice, this list of conditions and the following disclaimer in the
   40  *    documentation and/or other materials provided with the distribution.
   41  * 3. Neither the name of the University nor the names of its contributors
   42  *    may be used to endorse or promote products derived from this software
   43  *    without specific prior written permission.
   44  *
   45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55  * SUCH DAMAGE.
   56  *
   57  *      @(#)if_ethersubr.c      8.2 (Berkeley) 4/4/96
   58  */
   59 
   60 #include <sys/cdefs.h>
   61 __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.15 2005/02/26 22:45:09 perry Exp $");
   62 
   63 #include "bpfilter.h"
   64 #include "opt_inet.h"
   65 #include "opt_pfil_hooks.h"
   66 
   67 #include <sys/param.h>
   68 
   69 __KERNEL_RCSID(0, "$NetBSD: if_ecosubr.c,v 1.15 2005/02/26 22:45:09 perry Exp $");
   70 
   71 #include <sys/errno.h>
   72 #include <sys/kernel.h>
   73 #include <sys/socket.h>
   74 #include <sys/sockio.h>
   75 #include <sys/syslog.h>
   76 #include <sys/systm.h>
   77 
   78 #include <net/if.h>
   79 #include <net/if_dl.h>
   80 #include <net/if_eco.h>
   81 #include <net/if_types.h>
   82 #include <net/netisr.h>
   83 #include <net/route.h>
   84 
   85 #if NBPFILTER > 0
   86 #include <net/bpf.h>
   87 #endif
   88 
   89 #ifdef INET
   90 #include <net/ethertypes.h>
   91 #include <net/if_arp.h>
   92 #include <netinet/in.h>
   93 #include <netinet/in_var.h>
   94 #endif
   95 
   96 #define ECO_MAUX_RETRYPARMS 0
   97 
   98 struct eco_retryparms {
   99         int     erp_delay;
  100         int     erp_count;
  101 };
  102 
  103 /* Default broadcast address */
  104 static const u_int8_t eco_broadcastaddr[] = { 0xff, 0xff };
  105 
  106 static int eco_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  107     struct rtentry *);
  108 static void eco_input(struct ifnet *, struct mbuf *);
  109 static void eco_start(struct ifnet *);
  110 static int eco_ioctl(struct ifnet *, u_long, caddr_t);
  111 
  112 static int eco_interestingp(struct ifnet *ifp, struct mbuf *m);
  113 static struct mbuf *eco_immediate(struct ifnet *ifp, struct mbuf *m);
  114 static struct mbuf *eco_ack(struct ifnet *ifp, struct mbuf *m);
  115 
  116 static void eco_defer(struct ifnet *, struct mbuf *, int);
  117 static void eco_retry_free(struct eco_retry *er);
  118 static void eco_retry(void *);
  119 
  120 void
  121 eco_ifattach(struct ifnet *ifp, const u_int8_t *lla)
  122 {
  123         struct ecocom *ec = (void *)ifp;
  124 
  125         ifp->if_type = IFT_ECONET;
  126         ifp->if_addrlen = ECO_ADDR_LEN;
  127         ifp->if_hdrlen = ECO_HDR_LEN;
  128         ifp->if_dlt = DLT_ECONET;
  129         ifp->if_mtu = ECO_MTU;
  130 
  131         ifp->if_output   = eco_output;
  132         ifp->if_input    = eco_input;
  133         ifp->if_start    = eco_start;
  134         ifp->if_ioctl    = eco_ioctl;
  135 
  136 /*      ifp->if_baudrate...; */
  137         if_alloc_sadl(ifp);
  138         memcpy(LLADDR(ifp->if_sadl), lla, ifp->if_addrlen);
  139 
  140         /* XXX cast safe? */
  141         ifp->if_broadcastaddr = (u_int8_t *)eco_broadcastaddr;
  142 
  143         LIST_INIT(&ec->ec_retries);
  144 
  145 #if NBPFILTER > 0
  146         bpfattach(ifp, ifp->if_dlt, ECO_HDR_LEN);
  147 #endif
  148 }
  149 
  150 #define senderr(e) do {                                                 \
  151         error = (e);                                                    \
  152         goto bad;                                                       \
  153 } while (/*CONSTCOND*/0)
  154 
  155 int
  156 eco_init(struct ifnet *ifp) {
  157         struct ecocom *ec = (struct ecocom *)ifp;
  158 
  159         if ((ifp->if_flags & IFF_RUNNING) == 0)
  160                 ec->ec_state = ECO_UNKNOWN;
  161         return 0;
  162 }
  163 
  164 void
  165 eco_stop(struct ifnet *ifp, int disable)
  166 {
  167         struct ecocom *ec = (struct ecocom *)ifp;
  168 
  169         while (!LIST_EMPTY(&ec->ec_retries))
  170                 eco_retry_free(LIST_FIRST(&ec->ec_retries));
  171 }
  172 
  173 static int
  174 eco_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
  175     struct rtentry *rt0)
  176 {
  177         struct eco_header ehdr, *eh;
  178         int error, s;
  179         struct mbuf *m = m0, *mcopy = NULL;
  180         struct rtentry *rt;
  181         int hdrcmplt;
  182         size_t len;
  183         int delay, count;
  184         struct m_tag *mtag;
  185         struct eco_retryparms *erp;
  186 #ifdef INET
  187         struct mbuf *m1;
  188         struct arphdr *ah;
  189         struct eco_arp *ecah;
  190 #endif
  191         ALTQ_DECL(struct altq_pktattr pktattr;)
  192 
  193         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  194                 senderr(ENETDOWN);
  195         if ((rt = rt0) != NULL) {
  196                 if ((rt->rt_flags & RTF_UP) == 0) {
  197                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
  198                                 rt->rt_refcnt--;
  199                                 if (rt->rt_ifp != ifp)
  200                                         return (*rt->rt_ifp->if_output)
  201                                                         (ifp, m0, dst, rt);
  202                         } else
  203                                 senderr(EHOSTUNREACH);
  204                 }
  205                 if ((rt->rt_flags & RTF_GATEWAY) && dst->sa_family != AF_NS) {
  206                         if (rt->rt_gwroute == 0)
  207                                 goto lookup;
  208                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
  209                                 rtfree(rt); rt = rt0;
  210                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
  211                                 if ((rt = rt->rt_gwroute) == 0)
  212                                         senderr(EHOSTUNREACH);
  213                                 /* the "G" test below also prevents rt == rt0 */
  214                                 if ((rt->rt_flags & RTF_GATEWAY) ||
  215                                     (rt->rt_ifp != ifp)) {
  216                                         rt->rt_refcnt--;
  217                                         rt0->rt_gwroute = 0;
  218                                         senderr(EHOSTUNREACH);
  219                                 }
  220                         }
  221                 }
  222                 if (rt->rt_flags & RTF_REJECT)
  223                         if (rt->rt_rmx.rmx_expire == 0 ||
  224                             time.tv_sec < rt->rt_rmx.rmx_expire)
  225                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  226         }
  227         /*
  228          * If the queueing discipline needs packet classification,
  229          * do it before prepending link headers.
  230          */
  231         IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
  232 
  233         hdrcmplt = 0;
  234         delay = hz / 16;
  235         count = 16;
  236         switch (dst->sa_family) {
  237 #ifdef INET
  238         case AF_INET:
  239                 if (m->m_flags & M_BCAST)
  240                         memcpy(ehdr.eco_dhost, eco_broadcastaddr,
  241                             ECO_ADDR_LEN);
  242 
  243                 else if (!arpresolve(ifp, rt, m, dst, ehdr.eco_dhost))
  244                         return (0);     /* if not yet resolved */
  245                 /* If broadcasting on a simplex interface, loopback a copy */
  246                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
  247                         mcopy = m_copy(m, 0, (int)M_COPYALL);
  248                 ehdr.eco_port = ECO_PORT_IP;
  249                 ehdr.eco_control = ECO_CTL_IP;
  250                 break;
  251 
  252         case AF_ARP:
  253                 ah = mtod(m, struct arphdr *);
  254 
  255                 if (ntohs(ah->ar_pro) != ETHERTYPE_IP)
  256                         return EAFNOSUPPORT;
  257                 ehdr.eco_port = ECO_PORT_IP;
  258                 switch (ntohs(ah->ar_op)) {
  259                 case ARPOP_REQUEST:
  260                         ehdr.eco_control = ECO_CTL_ARP_REQUEST;
  261                         break;
  262                 case ARPOP_REPLY:
  263                         ehdr.eco_control = ECO_CTL_ARP_REPLY;
  264                         break;
  265                 default:
  266                         return EOPNOTSUPP;
  267                 }
  268 
  269                 if (m->m_flags & M_BCAST)
  270                         memcpy(ehdr.eco_dhost, eco_broadcastaddr,
  271                             ECO_ADDR_LEN);
  272                 else
  273                         memcpy(ehdr.eco_dhost, ar_tha(ah), ECO_ADDR_LEN);
  274 
  275                 MGETHDR(m1, M_DONTWAIT, MT_DATA);
  276                 if (m1 == NULL)
  277                         senderr(ENOBUFS);
  278                 M_COPY_PKTHDR(m1, m);
  279                 m1->m_len = sizeof(*ecah);
  280                 m1->m_pkthdr.len = m1->m_len;
  281                 MH_ALIGN(m1, m1->m_len);
  282                 ecah = mtod(m1, struct eco_arp *);
  283                 memset(ecah, 0, m1->m_len);
  284                 memcpy(ecah->ecar_spa, ar_spa(ah), ah->ar_pln);
  285                 memcpy(ecah->ecar_tpa, ar_tpa(ah), ah->ar_pln);
  286                 m_freem(m);
  287                 m = m1;
  288                 break;
  289 #endif
  290         case pseudo_AF_HDRCMPLT:
  291                 hdrcmplt = 1;
  292                 /* FALLTHROUGH */
  293         case AF_UNSPEC:
  294                 eh = (struct eco_header *)dst->sa_data;
  295                 ehdr = *eh;
  296                 break;
  297         default:
  298                 log(LOG_ERR, "%s: can't handle af%d\n", ifp->if_xname,
  299                     dst->sa_family);
  300                 senderr(EAFNOSUPPORT);
  301         }
  302 
  303         if (mcopy)
  304                 (void) looutput(ifp, mcopy, dst, rt);
  305 
  306         /*
  307          * Add local net header.  If no space in first mbuf,
  308          * allocate another.
  309          */
  310         M_PREPEND(m, sizeof (struct eco_header), M_DONTWAIT);
  311         if (m == 0)
  312                 senderr(ENOBUFS);
  313         eh = mtod(m, struct eco_header *);
  314         *eh = ehdr;
  315         if (!hdrcmplt)
  316                 memcpy(eh->eco_shost, LLADDR(ifp->if_sadl),
  317                     ECO_ADDR_LEN);
  318 
  319         if ((m->m_flags & M_BCAST) == 0) {
  320                 /* Attach retry info to packet. */
  321                 mtag = m_tag_get(PACKET_TAG_ECO_RETRYPARMS,
  322                     sizeof(struct eco_retryparms), M_NOWAIT);
  323                 if (mtag == NULL)
  324                         senderr(ENOBUFS);
  325                 erp = (struct eco_retryparms *)(mtag + 1);
  326                 erp->erp_delay = delay;
  327                 erp->erp_count = count;
  328         }
  329 
  330 #ifdef PFIL_HOOKS
  331         if ((error = pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0)
  332                 return (error);
  333         if (m == NULL)
  334                 return (0);
  335 #endif
  336 
  337         /*
  338          * Queue message on interface, and start output if interface
  339          * not yet active.
  340          */
  341 
  342         len = m->m_pkthdr.len;
  343         s = splnet();
  344         IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
  345         if (error) {
  346                 splx(s);
  347                 return (error);
  348         }
  349         ifp->if_obytes += len;
  350         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  351                 (*ifp->if_start)(ifp);
  352         splx(s);
  353         return (error);
  354 
  355 bad:
  356         if (m)
  357                 m_freem(m);
  358         return error;
  359 }
  360 
  361 /*
  362  * Given a scout, decide if we want the rest of the packet.
  363  */
  364 static int
  365 eco_interestingp(struct ifnet *ifp, struct mbuf *m)
  366 {
  367         struct eco_header *eh;
  368 
  369         eh = mtod(m, struct eco_header *);
  370         switch (eh->eco_port) {
  371 #ifdef INET
  372         case ECO_PORT_IP:
  373                 return 1;
  374 #endif
  375         }
  376         return 0;
  377 }
  378 
  379 static void
  380 eco_input(struct ifnet *ifp, struct mbuf *m)
  381 {
  382         struct ifqueue *inq;
  383         struct eco_header ehdr, *eh;
  384         int s, i;
  385 #ifdef INET
  386         struct arphdr *ah;
  387         struct eco_arp *ecah;
  388         struct mbuf *m1;
  389 #endif
  390 
  391 #ifdef PFIL_HOOKS
  392         if (pfil_run_hooks(&ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
  393                 return;
  394         if (m == NULL)
  395                 return;
  396 #endif
  397 
  398         /* Copy the mbuf header and trim it off. */
  399         /* XXX use m_split? */
  400         eh = &ehdr;
  401         m_copydata(m, 0, ECO_HDR_LEN, (caddr_t)eh);
  402         m_adj(m, ECO_HDR_LEN);
  403 
  404         switch (eh->eco_port) {
  405 #ifdef INET
  406         case ECO_PORT_IP:
  407                 switch (eh->eco_control) {
  408                 case ECO_CTL_IP:
  409                         schednetisr(NETISR_IP);
  410                         inq = &ipintrq;
  411                         break;
  412                 case ECO_CTL_ARP_REQUEST:
  413                 case ECO_CTL_ARP_REPLY:
  414                         /*
  415                          * ARP over Econet is strange, because Econet only
  416                          * supports 8 bytes of data in a broadcast packet.
  417                          * To cope with this, only the source and destination
  418                          * IP addresses are actually contained in the packet
  419                          * and we have to infer the rest and build a fake ARP
  420                          * packet to pass upwards.
  421                          */
  422                         if (m->m_pkthdr.len != sizeof(struct eco_arp))
  423                                 goto drop;
  424                         if (m->m_len < sizeof(struct eco_arp)) {
  425                                 m = m_pullup(m, sizeof(struct eco_arp));
  426                                 if (m == NULL) goto drop;
  427                         }
  428                         ecah = mtod(m, struct eco_arp *);
  429                         /* This code derived from arprequest() */
  430                         MGETHDR(m1, M_DONTWAIT, MT_DATA);
  431                         if (m1 == NULL)
  432                                 goto drop;
  433                         M_COPY_PKTHDR(m1, m);
  434                         m1->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
  435                             2*ifp->if_data.ifi_addrlen;
  436                         m1->m_pkthdr.len = m1->m_len;
  437                         MH_ALIGN(m1, m1->m_len);
  438                         ah = mtod(m1, struct arphdr *);
  439                         bzero((caddr_t)ah, m1->m_len);
  440                         ah->ar_pro = htons(ETHERTYPE_IP);
  441                         ah->ar_hln = ifp->if_data.ifi_addrlen;
  442                         ah->ar_pln = sizeof(struct in_addr);
  443                         if (eh->eco_control == ECO_CTL_ARP_REQUEST)
  444                                 ah->ar_op = htons(ARPOP_REQUEST);
  445                         else
  446                                 ah->ar_op = htons(ARPOP_REPLY);
  447                         memcpy(ar_sha(ah), eh->eco_shost, ah->ar_hln);
  448                         memcpy(ar_tha(ah), eh->eco_dhost, ah->ar_hln);
  449                         memcpy(ar_spa(ah), ecah->ecar_spa, ah->ar_pln);
  450                         memcpy(ar_tpa(ah), ecah->ecar_tpa, ah->ar_pln);
  451                         m_freem(m);
  452                         m = m1;
  453                         schednetisr(NETISR_ARP);
  454                         inq = &arpintrq;
  455                         break;
  456                 case ECO_CTL_IPBCAST_REQUEST:
  457                 {
  458                         struct sockaddr_storage dst_store;
  459                         struct sockaddr *dst = (struct sockaddr *)&dst_store;
  460 
  461                         /* Queue? */
  462                         memcpy(eh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
  463                         eh->eco_control = ECO_CTL_IPBCAST_REPLY;
  464                         /* dst->sa_len??? */
  465                         dst->sa_family = AF_UNSPEC;
  466                         memcpy(dst->sa_data, eh, ECO_HDR_LEN);
  467                         ifp->if_output(ifp, m, dst, NULL);
  468                         return;
  469                 }
  470                 default:
  471                         printf("%s: unknown IP stn %s ctl 0x%02x len %d:",
  472                             ifp->if_xname, eco_sprintf(eh->eco_shost),
  473                             eh->eco_control, m->m_pkthdr.len);
  474                         if (m->m_len == 0) {
  475                                 m = m_pullup(m, 1);
  476                                 if (m == 0) {
  477                                         printf("\n");
  478                                         goto drop;
  479                                 }
  480                         }
  481                         for (i = 0; i < m->m_len; i++)
  482                                 printf(" %02x", mtod(m, u_int8_t *)[i]);
  483                         printf("\n");
  484                         goto drop;
  485                 }
  486                 break;
  487 #endif
  488         default:
  489                 printf("%s: unknown port stn %s port 0x%02x ctl 0x%02x\n",
  490                     ifp->if_xname, eco_sprintf(eh->eco_shost),
  491                     eh->eco_port, eh->eco_control);
  492         drop:
  493                 m_freem(m);
  494                 return;
  495         }
  496 
  497         s = splnet();
  498         if (IF_QFULL(inq)) {
  499                 IF_DROP(inq);
  500                 m_freem(m);
  501         } else
  502                 IF_ENQUEUE(inq, m);
  503         splx(s);
  504 }
  505 
  506 static void
  507 eco_start(struct ifnet *ifp)
  508 {
  509         struct ecocom *ec = (void *)ifp;
  510         struct mbuf *m;
  511         struct eco_header *eh;
  512 
  513         if (ec->ec_state != ECO_IDLE) return;
  514         IFQ_DEQUEUE(&ifp->if_snd, m);
  515         if (m == NULL) return;
  516         if (ec->ec_claimwire(ifp) == 0) {
  517                 eh = mtod(m, struct eco_header *);
  518                 if (eh->eco_port == ECO_PORT_IMMEDIATE) {
  519                         ec->ec_txframe(ifp, m);
  520                         ec->ec_state = ECO_IMMED_SENT;
  521                 } else if (eh->eco_dhost[0] == 255) {
  522                         ec->ec_txframe(ifp, m);
  523                         ec->ec_state = ECO_DONE;
  524                 } else {
  525                         ec->ec_packet = m;
  526                         m = m_copym(m, 0, ECO_HDR_LEN, M_DONTWAIT);
  527                         if (m == NULL) {
  528                                 m_freem(ec->ec_packet);
  529                                 ec->ec_packet = NULL;
  530                                 return;
  531                         }
  532                         ec->ec_txframe(ifp, m);
  533                         ec->ec_state = ECO_SCOUT_SENT;
  534                 }
  535                 ifp->if_flags |= IFF_OACTIVE;
  536         } else {
  537                 log(LOG_ERR, "%s: line jammed\n", ifp->if_xname);
  538                 m_freem(m);
  539         }
  540 }
  541 
  542 static int
  543 eco_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  544 {
  545         struct ifreq *ifr = (struct ifreq *)data;
  546         struct ifaddr *ifa = (struct ifaddr *)data;
  547         int error = 0;
  548 
  549         switch (cmd) {
  550         case SIOCSIFADDR:
  551                 ifp->if_flags |= IFF_UP;
  552                 switch (ifa->ifa_addr->sa_family) {
  553 #ifdef INET
  554                 case AF_INET:
  555                         if ((ifp->if_flags & IFF_RUNNING) == 0 &&
  556                             (error = (*ifp->if_init)(ifp)) != 0)
  557                                 break;
  558                         arp_ifinit(ifp, ifa);
  559                         break;
  560 #endif
  561                 default:
  562                         if ((ifp->if_flags & IFF_RUNNING) == 0)
  563                                 error = (*ifp->if_init)(ifp);
  564                         break;
  565                 }
  566                 break;
  567         case SIOCSIFMTU:
  568                 ifp->if_mtu = ifr->ifr_mtu;
  569 
  570                 /* Make sure the device notices the MTU change. */
  571                 if (ifp->if_flags & IFF_UP)
  572                         error = (*ifp->if_init)(ifp);
  573                 break;
  574         case SIOCSIFFLAGS:
  575                 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) {
  576                         /*
  577                          * If interface is marked down and it is running,
  578                          * then stop and disable it.
  579                          */
  580                         (*ifp->if_stop)(ifp, 1);
  581                 } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) {
  582                         /*
  583                          * If interface is marked up and it is stopped, then
  584                          * start it.
  585                          */
  586                         error = (*ifp->if_init)(ifp);
  587                 } else if ((ifp->if_flags & IFF_UP) != 0) {
  588                         /*
  589                          * Reset the interface to pick up changes in any other
  590                          * flags that affect the hardware state.
  591                          */
  592                         error = (*ifp->if_init)(ifp);
  593                 }
  594                 break;
  595         default:
  596                 error = ENOTTY;
  597         }
  598 
  599         return error;
  600 }
  601 
  602 /*
  603  * Handle a raw Econet frame off the interface.  The interface may be
  604  * flag-filling for a response.
  605  *
  606  * May be called from IPL_NET or IPL_SOFTNET.
  607  */
  608 
  609 struct mbuf *
  610 eco_inputframe(struct ifnet *ifp, struct mbuf *m)
  611 {
  612         struct ecocom *ec = (void *)ifp;
  613         struct eco_header *eh, *eh0;
  614         struct mbuf *m0;
  615         struct mbuf *reply;
  616         int len;
  617 
  618         eh = mtod(m, struct eco_header *);
  619         switch (ec->ec_state) {
  620         case ECO_IDLE: /* Start of a packet (bcast, immed, scout) */
  621                 if (m->m_pkthdr.len < ECO_HDR_LEN) {
  622                         log(LOG_NOTICE, "%s: undersize scout\n",
  623                             ifp->if_xname);
  624                         goto drop;
  625                 }
  626                 if (memcmp(eh->eco_dhost, eco_broadcastaddr,
  627                     ECO_ADDR_LEN) == 0) {
  628                         /* Broadcast */
  629                         eco_input(ifp, m);
  630                 } else if (memcmp(eh->eco_dhost, LLADDR(ifp->if_sadl),
  631                     ECO_ADDR_LEN) == 0) {
  632                         /* Unicast for us */
  633                         if (eh->eco_port == ECO_PORT_IMMEDIATE)
  634                                 return eco_immediate(ifp, m);
  635                         else {
  636                                 if (eco_interestingp(ifp, m)) {
  637                                         reply = eco_ack(ifp, m);
  638                                         if (reply == NULL) {
  639                                                 m_freem(m);
  640                                                 return NULL;
  641                                         }
  642                                         ec->ec_state = ECO_SCOUT_RCVD;
  643                                         ec->ec_scout = m;
  644                                         return reply;
  645                                 } else {
  646                                         m_freem(m);
  647                                         return NULL;
  648                                 }
  649                         }
  650                 } else
  651                         /* Not for us.  Throw it away. */
  652                         m_freem(m);
  653                 break;
  654         case ECO_SCOUT_RCVD: /* Packet data */
  655                 KASSERT(ec->ec_scout != NULL);
  656                 m0 = ec->ec_scout;
  657                 eh0 = mtod(m0, struct eco_header *);
  658                 if (m->m_pkthdr.len < ECO_SHDR_LEN ||
  659                     memcmp(eh->eco_shost, eh0->eco_shost, ECO_ADDR_LEN) != 0 ||
  660                     memcmp(eh->eco_dhost, eh0->eco_dhost, ECO_ADDR_LEN) != 0) {
  661                         log(LOG_NOTICE, "%s: garbled data packet header\n",
  662                             ifp->if_xname);
  663                         goto drop;
  664                 }
  665                 reply = eco_ack(ifp, m);
  666                 /*
  667                  * Chop off the small header from this frame, and put
  668                  * the scout (which holds the control byte and port)
  669                  * in its place.
  670                  */
  671                 ec->ec_scout = NULL;
  672                 m_adj(m, ECO_SHDR_LEN);
  673                 len = m0->m_pkthdr.len + m->m_pkthdr.len;
  674                 m_cat(m0, m);
  675                 m0->m_pkthdr.len = len;
  676                 ec->ec_state = ECO_DONE;
  677                 eco_input(ifp, m0);
  678                 return reply;
  679         case ECO_SCOUT_SENT: /* Scout ack */
  680                 KASSERT(ec->ec_packet != NULL);
  681                 m0 = ec->ec_packet;
  682                 eh0 = mtod(m0, struct eco_header *);
  683                 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
  684                     memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
  685                     memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
  686                         log(LOG_NOTICE, "%s: garbled scout ack\n",
  687                             ifp->if_xname);
  688                         goto drop;
  689                 }
  690                 m_freem(m);
  691                 /* Chop out the control and port bytes. */
  692                 m0 = m_copym(ec->ec_packet, 0, ECO_SHDR_LEN, M_DONTWAIT);
  693                 if (m0 == NULL) {
  694                         m_freem(ec->ec_packet);
  695                         return NULL;
  696                 }
  697                 m = ec->ec_packet;
  698                 ec->ec_packet = m_copypacket(m, M_DONTWAIT);
  699                 if (ec->ec_packet == NULL) {
  700                         m_freem(m0);
  701                         m_freem(m);
  702                         return NULL;
  703                 }
  704                 m_adj(m, ECO_HDR_LEN);
  705                 len = m0->m_pkthdr.len + m->m_pkthdr.len;
  706                 m_cat(m0, m); /* Doesn't update packet header */
  707                 m0->m_pkthdr.len = len;
  708                 ec->ec_state = ECO_DATA_SENT;
  709                 return m0;
  710         case ECO_DATA_SENT: /* Data ack */
  711                 KASSERT(ec->ec_packet != NULL);
  712                 m0 = ec->ec_packet;
  713                 eh0 = mtod(m0, struct eco_header *);
  714                 if (m->m_pkthdr.len != ECO_SHDR_LEN ||
  715                     memcmp(eh->eco_shost, eh0->eco_dhost, ECO_ADDR_LEN) != 0 ||
  716                     memcmp(eh->eco_dhost, eh0->eco_shost, ECO_ADDR_LEN) != 0) {
  717                         log(LOG_NOTICE, "%s: garbled data ack\n",
  718                             ifp->if_xname);
  719                         goto drop;
  720                 }
  721                 m_freem(m);
  722                 m_freem(ec->ec_packet);
  723                 ec->ec_packet = NULL;
  724                 ec->ec_state = ECO_DONE;
  725                 return NULL;
  726         default:
  727         drop:
  728                 m_freem(m);
  729                 break;
  730         }
  731         return NULL;
  732 }
  733 
  734 /*
  735  * Handle an immediate operation, and return the reply, or NULL not to reply.
  736  * Frees the incoming mbuf.
  737  */
  738 
  739 static struct mbuf *
  740 eco_immediate(struct ifnet *ifp, struct mbuf *m)
  741 {
  742         struct eco_header *eh, *reh;
  743         struct mbuf *n;
  744         static const u_int8_t machinepeek_data[] = { 42, 0, 0, 1 };
  745 
  746         eh = mtod(m, struct eco_header *);
  747         switch (eh->eco_control) {
  748         case ECO_CTL_MACHINEPEEK:
  749                 MGETHDR(n, M_DONTWAIT, MT_DATA);
  750                 if (n == NULL)
  751                         goto bad;
  752                 n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN + 4;
  753                 reh = mtod(n, struct eco_header *);
  754                 memcpy(reh->eco_dhost, eh->eco_shost,
  755                     ECO_ADDR_LEN);
  756                 memcpy(reh->eco_shost, LLADDR(ifp->if_sadl),
  757                     ECO_ADDR_LEN);
  758                 memcpy(mtod(n, caddr_t) + ECO_SHDR_LEN, machinepeek_data,
  759                     sizeof(machinepeek_data));
  760                 m_freem(m);
  761                 return n;
  762         default:
  763         bad:
  764                 m_freem(m);
  765                 return NULL;
  766         }
  767 }
  768 
  769 /*
  770  * Generate (and return) an acknowledgement for a frame.  Doesn't free the
  771  * original frame, since it's probably needed elsewhere.
  772  */
  773 static struct mbuf *
  774 eco_ack(struct ifnet *ifp, struct mbuf *m)
  775 {
  776         struct eco_header *eh, *reh;
  777         struct mbuf *n;
  778 
  779         eh = mtod(m, struct eco_header *);
  780         MGETHDR(n, M_DONTWAIT, MT_DATA);
  781         if (n == NULL)
  782                 return NULL;
  783         n->m_len = n->m_pkthdr.len = ECO_SHDR_LEN;
  784         reh = mtod(n, struct eco_header *);
  785         memcpy(reh->eco_dhost, eh->eco_shost, ECO_ADDR_LEN);
  786         memcpy(reh->eco_shost, LLADDR(ifp->if_sadl), ECO_ADDR_LEN);
  787         return n;
  788 }
  789 
  790 void
  791 eco_inputidle(struct ifnet *ifp)
  792 {
  793         struct ecocom *ec = (void *)ifp;
  794         struct mbuf *m;
  795         struct m_tag *mtag;
  796         struct eco_retryparms *erp;
  797 
  798         switch (ec->ec_state) {
  799         case ECO_SCOUT_SENT:
  800         case ECO_DATA_SENT:
  801         case ECO_IMMED_SENT:
  802                 /* Outgoing packet failed.  Check if we should retry. */
  803                 m = ec->ec_packet;
  804                 ec->ec_packet = NULL;
  805                 mtag = m_tag_find(m, PACKET_TAG_ECO_RETRYPARMS, NULL);
  806                 if (mtag == NULL)
  807                         m_freem(m);
  808                 else {
  809                         erp = (struct eco_retryparms *)(mtag + 1);
  810                         if (--erp->erp_count > 0)
  811                                 eco_defer(ifp, m, erp->erp_delay);
  812                         else
  813                                 printf("%s: pkt failed\n", ifp->if_xname);
  814                 }
  815                 break;
  816         case ECO_SCOUT_RCVD:
  817                 m_freem(ec->ec_scout);
  818                 ec->ec_scout = NULL;
  819                 break;
  820         default:
  821                 break;
  822         }
  823         ec->ec_state = ECO_IDLE;
  824         ifp->if_start(ifp);
  825 }
  826 
  827 /*
  828  * Convert Econet address to printable (loggable) representation.
  829  */
  830 char *
  831 eco_sprintf(const u_int8_t *ea)
  832 {
  833         static char buf[8];
  834 
  835         if (ea[1] == 0)
  836                 snprintf(buf, sizeof(buf), "%d", ea[0]);
  837         else
  838                 snprintf(buf, sizeof(buf), "%d.%d", ea[1], ea[0]);
  839         return buf;
  840 }
  841 
  842 /*
  843  * Econet retry handling.
  844  */
  845 static void
  846 eco_defer(struct ifnet *ifp, struct mbuf *m, int delay)
  847 {
  848         struct ecocom *ec = (struct ecocom *)ifp;
  849         struct eco_retry *er;
  850         int s;
  851 
  852         MALLOC(er, struct eco_retry *, sizeof(*er), M_TEMP, M_NOWAIT);
  853         if (er == NULL) {
  854                 m_freem(m);
  855                 return;
  856         }
  857         callout_init(&er->er_callout);
  858         er->er_packet = m;
  859         er->er_ifp = ifp;
  860         s = splnet();
  861         LIST_INSERT_HEAD(&ec->ec_retries, er, er_link);
  862         splx(s);
  863         callout_reset(&er->er_callout, delay, eco_retry, er);
  864 }
  865 
  866 static void
  867 eco_retry_free(struct eco_retry *er)
  868 {
  869         int s;
  870 
  871         callout_stop(&er->er_callout);
  872         m_freem(er->er_packet);
  873         s = splnet();
  874         LIST_REMOVE(er, er_link);
  875         splx(s);
  876         FREE(er, M_TEMP);
  877 }
  878 
  879 static void
  880 eco_retry(void *arg)
  881 {
  882         struct eco_retry *er = arg;
  883         struct mbuf *m;
  884         struct ifnet *ifp;
  885         int s, error, len;
  886 
  887         ifp = er->er_ifp;
  888         m = er->er_packet;
  889         len = m->m_pkthdr.len;
  890         LIST_REMOVE(er, er_link);
  891         s = splnet();
  892         IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
  893         if (error) {
  894                 splx(s);
  895                 /* XXX should defer again? */
  896                 m_freem(m);
  897         }
  898         ifp->if_obytes += len;
  899         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  900                 (*ifp->if_start)(ifp);
  901         splx(s);
  902         FREE(er, M_TEMP);
  903 }

Cache object: dec4124ecda3c556dbc566130aaec397


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