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/netccitt/llc_input.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: llc_input.c,v 1.14 2005/02/26 22:45:10 perry Exp $     */
    2 
    3 /*
    4  * Copyright (c) 1992, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Dirk Husemann and the Computer Science Department (IV) of
    9  * the University of Erlangen-Nuremberg, Germany.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      @(#)llc_input.c 8.1 (Berkeley) 6/10/93
   36  */
   37 
   38 /*
   39  * Copyright (c) 1990, 1991, 1992
   40  *              Dirk Husemann, Computer Science Department IV,
   41  *              University of Erlangen-Nuremberg, Germany.
   42  *
   43  * This code is derived from software contributed to Berkeley by
   44  * Dirk Husemann and the Computer Science Department (IV) of
   45  * the University of Erlangen-Nuremberg, Germany.
   46  *
   47  * Redistribution and use in source and binary forms, with or without
   48  * modification, are permitted provided that the following conditions
   49  * are met:
   50  * 1. Redistributions of source code must retain the above copyright
   51  *    notice, this list of conditions and the following disclaimer.
   52  * 2. Redistributions in binary form must reproduce the above copyright
   53  *    notice, this list of conditions and the following disclaimer in the
   54  *    documentation and/or other materials provided with the distribution.
   55  * 3. All advertising materials mentioning features or use of this software
   56  *    must display the following acknowledgement:
   57  *      This product includes software developed by the University of
   58  *      California, Berkeley and its contributors.
   59  * 4. Neither the name of the University nor the names of its contributors
   60  *    may be used to endorse or promote products derived from this software
   61  *    without specific prior written permission.
   62  *
   63  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   64  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   65  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   66  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   67  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   68  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   69  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   70  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   71  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   72  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   73  * SUCH DAMAGE.
   74  *
   75  *      @(#)llc_input.c 8.1 (Berkeley) 6/10/93
   76  */
   77 
   78 #include <sys/cdefs.h>
   79 __KERNEL_RCSID(0, "$NetBSD: llc_input.c,v 1.14 2005/02/26 22:45:10 perry Exp $");
   80 
   81 #include <sys/param.h>
   82 #include <sys/systm.h>
   83 #include <sys/mbuf.h>
   84 #include <sys/domain.h>
   85 #include <sys/socket.h>
   86 #include <sys/protosw.h>
   87 #include <sys/errno.h>
   88 #include <sys/time.h>
   89 #include <sys/kernel.h>
   90 
   91 #include <net/if.h>
   92 #include <net/if_dl.h>
   93 #include <net/if_llc.h>
   94 #include <net/route.h>
   95 
   96 #include <netccitt/dll.h>
   97 #include <netccitt/llc_var.h>
   98 
   99 #include <machine/stdarg.h>
  100 
  101 struct ifqueue llcintrq;
  102 
  103 /*
  104  * This module implements LLC as specified by ISO 8802-2.
  105  */
  106 
  107 
  108 /*
  109  * llcintr() handles all LLC frames (except ISO CLNS ones for the time being)
  110  *           and tries to pass them on to the appropriate network layer entity.
  111  */
  112 void
  113 llcintr()
  114 {
  115         struct mbuf *m;
  116         int i;
  117         int frame_kind;
  118         u_char cmdrsp;
  119         struct llc_linkcb *linkp;
  120         struct npaidbentry *sapinfo = NULL;
  121         struct sdl_hdr *sdlhdr;
  122         struct llc *frame;
  123         long expected_len;
  124 
  125         struct ifnet   *ifp;
  126         struct rtentry *llrt;
  127         struct rtentry *nlrt;
  128 
  129         for (;;) {
  130                 i = splnet();
  131                 IF_DEQUEUE(&llcintrq, m);
  132                 splx(i);
  133                 if (m == 0)
  134                         break;
  135 #ifdef          DIAGNOSTIC
  136                 if ((m->m_flags & M_PKTHDR) == 0)
  137                         panic("llcintr no HDR");
  138 #endif
  139                 /*
  140                  * Get ifp this packet was received on
  141                  */
  142                 ifp = m->m_pkthdr.rcvif;
  143 
  144                 sdlhdr = mtod(m, struct sdl_hdr *);
  145 
  146                 /*
  147                  * [Copied from net/ip_input.c]
  148                  *
  149                  * Check that the amount of data in the buffers is
  150                  * at least as much as the LLC header tells us.
  151                  * Trim mbufs if longer than expected.
  152                  * Drop packets if shorter than we think they are.
  153                  *
  154                  * Layout of mbuf chain at this point:
  155                  *
  156                  *  +-------------------------------+----+      -\
  157                  *  |  sockaddr_dl src - sdlhdr_src | 20 |        \
  158                  *  +-------------------------------+----+         |
  159                  *  |  sockaddr_dl dst - sdlhdr_dst | 20 |          > sizeof(struct sdl_hdr) == 44
  160                  *  +-------------------------------+----+         |
  161                  *  |  LLC frame len - sdlhdr_len   | 04 |        /
  162                  *  +-------------------------------+----+      -/
  163                  * /
  164                  * | m_next
  165                  * \
  166                  *  +----------------------------+----+  -\
  167                  *  |  llc DSAP                  | 01 |    \
  168                  *  +----------------------------+----+     |
  169                  *  |  llc SSAP                  | 01 |     |
  170                  *  +----------------------------+----+      > sdlhdr_len
  171                  *  |  llc control               | 01 |     |
  172                  *  +----------------------------+----+     |
  173                  *  |  ...                       |    |    /
  174                  *                                       -/
  175                  *
  176                  * Thus the we expect to have exactly
  177                  * (sdlhdr->sdlhdr_len+sizeof(struct sdl_hdr)) in the mbuf chain
  178                  */
  179                 expected_len = sdlhdr->sdlhdr_len + sizeof(struct sdl_hdr);
  180 
  181                 if (m->m_pkthdr.len < expected_len) {
  182                         m_freem(m);
  183                         continue;
  184                 }
  185                 if (m->m_pkthdr.len > expected_len) {
  186                         if (m->m_len == m->m_pkthdr.len) {
  187                                 m->m_len = expected_len;
  188                                 m->m_pkthdr.len = expected_len;
  189                         } else
  190                                 m_adj(m, expected_len - m->m_pkthdr.len);
  191                 }
  192 
  193                 /*
  194                  * Get llc header
  195                  */
  196                 if (m->m_len > sizeof(struct sdl_hdr))
  197                         frame = mtod((struct mbuf *)((struct sdl_hdr*)(m+1)),
  198                                      struct llc *);
  199                 else frame = mtod(m->m_next, struct llc *);
  200                 if (frame == (struct llc *) NULL)
  201                         panic("llcintr no llc header");
  202 
  203                 /*
  204                  * Now check for bogus I/S frame, i.e. those with a control
  205                  * field telling us they're an I/S frame yet their length
  206                  * is less than the established I/S frame length (DSAP + SSAP +
  207                  * control + N(R)&P/F = 4) --- we drop those suckers
  208                  */
  209                 if (((frame->llc_control & 0x03) != 0x03)
  210                     && ((expected_len - sizeof(struct sdl_hdr)) < LLC_ISFRAMELEN)) {
  211                         m_freem(m);
  212                         printf("llc: hurz error\n");
  213                         continue;
  214                 }
  215 
  216                 /*
  217                  * Get link control block for the addressed link connection.
  218                  * If there is none we take care of it later on.
  219                  */
  220                 cmdrsp = (frame->llc_ssap & 0x01);
  221                 frame->llc_ssap &= ~0x01;
  222                 llrt = rtalloc1((struct sockaddr *)&sdlhdr->sdlhdr_src, 0);
  223                 if (llrt)
  224                         llrt->rt_refcnt--;
  225 #ifdef notyet
  226                 else
  227                         llrt = npaidb_enter(&sdlhdr->sdlhdr_src, 0, 0, 0);
  228 #endif /* notyet */
  229                 else {
  230                         /*
  231                          * We cannot do anything currently here as we
  232                          * don't `know' this link --- drop it
  233                          */
  234                         m_freem(m);
  235                         continue;
  236                 }
  237                 linkp = ((struct npaidbentry *)(llrt->rt_llinfo))->np_link;
  238                 nlrt = ((struct npaidbentry *)(llrt->rt_llinfo))->np_rt;
  239 
  240                 /*
  241                  * If the link is not existing right now, we can try and look up
  242                  * the SAP info block.
  243                  */
  244                 if ((linkp == 0) && frame->llc_ssap)
  245                         sapinfo = llc_getsapinfo(frame->llc_dsap, ifp);
  246 
  247                 /*
  248                  * Handle XID and TEST frames
  249                  * XID:         if DLSAP == 0, return   type-of-services
  250                  *                                      window-0
  251                  *                                      DLSAP-0
  252                  *                                      format-identifier-?
  253                  *              if DLSAP != 0, locate sapcb and return
  254                  *                                      type-of-services
  255                  *                                      SAP-window
  256                  *                                      format-identifier-?
  257                  * TEST:        swap (snpah_dst, snpah_src) and return frame
  258                  *
  259                  * Also toggle the CMD/RESP bit
  260                  *
  261                  * Is this behaviour correct? Check ISO 8802-2 (90)!
  262                  */
  263                 frame_kind = llc_decode(frame, (struct llc_linkcb *)0);
  264                 switch(frame_kind) {
  265                 case LLCFT_XID:
  266                         if (linkp || sapinfo) {
  267                                 if (linkp)
  268                                         frame->llc_window = linkp->llcl_window;
  269                                 else frame->llc_window = sapinfo->si_window;
  270                                 frame->llc_fid = 9;                     /* XXX */
  271                                 frame->llc_class = sapinfo->si_class;
  272                                 frame->llc_ssap = frame->llc_dsap;
  273                         } else {
  274                                 frame->llc_window = 0;
  275                                 frame->llc_fid = 9;
  276                                 frame->llc_class = 1;
  277                                 frame->llc_dsap = frame->llc_ssap = 0;
  278                         }
  279 
  280                         /* fall thru to */
  281                 case LLCFT_TEST:
  282                         sdl_swapaddr(&(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
  283                                      &(mtod(m, struct sdl_hdr *)->sdlhdr_src));
  284 
  285                         /* Now set the CMD/RESP bit */
  286                         frame->llc_ssap |= (cmdrsp == 0x0 ? 0x1 : 0x0);
  287 
  288                         /* Ship it out again */
  289                         (*ifp->if_output)(ifp, m,
  290                                           (struct sockaddr *) &(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
  291                                           (struct rtentry *) 0);
  292                         continue;
  293                 }
  294 
  295                 /*
  296                  * Create link control block in case it is not existing
  297                  */
  298                 if (linkp == 0 && sapinfo) {
  299                         if ((linkp = llc_newlink(&sdlhdr->sdlhdr_src, ifp, nlrt,
  300                                                      (nlrt == 0) ? 0 : nlrt->rt_llinfo,
  301                                                      llrt)) == 0) {
  302                                 printf("llcintr: couldn't create new link\n");
  303                                 m_freem(m);
  304                                 continue;
  305                         }
  306                         ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
  307                 } else if (linkp == 0) {
  308                         /* The link is not known to us, drop the frame and continue */
  309                         m_freem(m);
  310                         continue;
  311                 }
  312 
  313                 /*
  314                  * Drop SNPA header and get rid of empty mbuf at the
  315                  * front of the mbuf chain (I don't like 'em)
  316                  */
  317                 m_adj(m, sizeof(struct sdl_hdr));
  318                 /*
  319                  * LLC_UFRAMELEN is sufficient, m_pullup() will pull up
  320                  * the min(m->m_len, maxprotohdr_len [=40]) thus doing
  321                  * the trick ...
  322                  */
  323                 if ((m = m_pullup(m, LLC_UFRAMELEN)))
  324                         /*
  325                          * Pass it on thru the elements of procedure
  326                          */
  327                         llc_input(m, linkp, cmdrsp);
  328         }
  329         return;
  330 }
  331 
  332 /*
  333  * llc_input() --- We deal with the various incoming frames here.
  334  *                 Basically we (indirectly) call the appropriate
  335  *                 state handler function that's pointed to by
  336  *                 llcl_statehandler.
  337  *
  338  *                 The statehandler returns an action code ---
  339  *                 further actions like
  340  *                         o notify network layer
  341  *                         o block further sending
  342  *                         o deblock link
  343  *                         o ...
  344  *                 are then enacted accordingly.
  345  */
  346 int
  347 llc_input(struct mbuf *m, ...)
  348 {
  349         int frame_kind;
  350         int pollfinal;
  351         int action = 0;
  352         struct llc *frame;
  353         struct llc_linkcb *linkp;
  354         u_int cmdrsp;
  355         va_list ap;
  356 
  357         va_start(ap, m);
  358         linkp = va_arg(ap, struct llc_linkcb *);
  359         cmdrsp = va_arg(ap, u_int);
  360         va_end(ap);
  361 
  362 
  363         if ((frame = mtod(m, struct llc *)) == (struct llc *) 0) {
  364                 m_freem(m);
  365                 return 0;
  366         }
  367         pollfinal = ((frame->llc_control & 0x03) == 0x03) ?
  368                 LLCGBITS(frame->llc_control, u_pf) :
  369                         LLCGBITS(frame->llc_control_ext, s_pf);
  370 
  371         /*
  372          * first decode the frame
  373          */
  374         frame_kind = llc_decode(frame, linkp);
  375 
  376         switch (action = llc_statehandler(linkp, frame, frame_kind, cmdrsp,
  377                                           pollfinal)) {
  378         case LLC_DATA_INDICATION:
  379                 m_adj(m, LLC_ISFRAMELEN);
  380                 if ((m = m_pullup(m, NLHDRSIZEGUESS)) != NULL) {
  381                         m->m_pkthdr.rcvif = (struct ifnet *)linkp->llcl_nlnext;
  382                         (*linkp->llcl_sapinfo->si_input)(m, NULL, NULL, NULL);
  383                 }
  384                 break;
  385         }
  386 
  387         /* release mbuf if not an info frame */
  388         if (action != LLC_DATA_INDICATION && m)
  389                 m_freem(m);
  390 
  391         /* try to get frames out ... */
  392         llc_start(linkp);
  393 
  394         return 0;
  395 }
  396 
  397 /*
  398  * This routine is called by configuration setup. It sets up a station control
  399  * block and notifies all registered upper level protocols.
  400  */
  401 void *
  402 llc_ctlinput(prc, addr, info)
  403         int prc;
  404         struct sockaddr *addr;
  405         void *info;
  406 {
  407         struct ifnet *ifp = NULL;
  408         struct ifaddr *ifa;
  409         struct dll_ctlinfo *ctlinfo = (struct dll_ctlinfo *)info;
  410         u_char sap;
  411         struct dllconfig *config;
  412         caddr_t pcb;
  413         struct rtentry *nlrt;
  414         struct rtentry *llrt = NULL;
  415         struct llc_linkcb *linkp = NULL;
  416         int i;
  417 
  418         /* info must point to something valid at all times */
  419         if (info == 0)
  420                 return 0;
  421 
  422         if (prc == PRC_IFUP || prc == PRC_IFDOWN) {
  423                 /* we use either this set ... */
  424                 ifa = ifa_ifwithaddr(addr);
  425                 if (ifa == NULL)
  426                         return (0);
  427                 ifp = ifa->ifa_ifp;
  428                 if (ifp == NULL)
  429                         return (0);
  430 
  431                 sap = ctlinfo->dlcti_lsap;
  432                 config = ctlinfo->dlcti_cfg;
  433                 pcb = (caddr_t) 0;
  434                 nlrt = (struct rtentry *) 0;
  435         } else {
  436                 /* or this one */
  437                 sap = 0;
  438                 config = (struct dllconfig *) 0;
  439                 pcb = ctlinfo->dlcti_pcb;
  440                 nlrt = ctlinfo->dlcti_rt;
  441 
  442                 if ((llrt = rtalloc1(nlrt->rt_gateway, 0)))
  443                         llrt->rt_refcnt--;
  444                 else return 0;
  445 
  446                 linkp = ((struct npaidbentry *)llrt->rt_llinfo)->np_link;
  447         }
  448 
  449         switch (prc) {
  450         case PRC_IFUP:
  451                 (void) llc_setsapinfo(ifp, addr->sa_family, sap, config);
  452                 return 0;
  453 
  454         case PRC_IFDOWN: {
  455                 struct llc_linkcb *linkp;
  456                 struct llc_linkcb *nlinkp;
  457                 int i;
  458 
  459                 /*
  460                  * All links are accessible over the doubly linked list llccb_q
  461                  */
  462                 if (!LQEMPTY) {
  463                         /*
  464                          * A for-loop is not that great an idea as the linkp
  465                          * will get deleted by llc_timer()
  466                          */
  467                         linkp = LQFIRST;
  468                         while (LQVALID(linkp)) {
  469                                 nlinkp = LQNEXT(linkp);
  470                                 if ((linkp->llcl_if = ifp) != NULL) {
  471                                         i = splnet();
  472                                         (void)llc_statehandler(linkp, (struct llc *)0,
  473                                                                NL_DISCONNECT_REQUEST,
  474                                                                0, 1);
  475                                         splx(i);
  476                                 }
  477                                 linkp = nlinkp;
  478                         }
  479                 }
  480         }
  481 
  482         case PRC_CONNECT_REQUEST:
  483                 if (linkp == 0) {
  484                         if ((linkp = llc_newlink((struct sockaddr_dl *) nlrt->rt_gateway,
  485                                                  nlrt->rt_ifp, nlrt,
  486                                                  pcb, llrt)) == 0)
  487                                 return (0);
  488                         ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
  489                         i = splnet();
  490                         (void)llc_statehandler(linkp, (struct llc *) 0,
  491                                                 NL_CONNECT_REQUEST, 0, 1);
  492                         splx(i);
  493                 }
  494                 return ((caddr_t)linkp);
  495 
  496         case PRC_DISCONNECT_REQUEST:
  497                 if (linkp == 0)
  498                         panic("no link control block!");
  499 
  500                 i = splnet();
  501                 (void)llc_statehandler(linkp, (struct llc *) 0,
  502                                        NL_DISCONNECT_REQUEST, 0, 1);
  503                 splx(i);
  504 
  505                 /*
  506                  * The actual removal of the link control block is done by the
  507                  * cleaning neutrum (i.e. llc_timer()).
  508                  */
  509                 break;
  510 
  511         case PRC_RESET_REQUEST:
  512                 if (linkp == 0)
  513                         panic("no link control block!");
  514 
  515                 i = splnet();
  516                 (void)llc_statehandler(linkp, (struct llc *) 0,
  517                                        NL_RESET_REQUEST, 0, 1);
  518                 splx(i);
  519 
  520                 break;
  521 
  522         }
  523 
  524         return 0;
  525 }

Cache object: 03f3e2747d686b7704a2cdd84c946310


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