date and time created 92/12/08 17:36:04 by sklower
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Wed, 9 Dec 1992 09:36:04 +0000 (01:36 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Wed, 9 Dec 1992 09:36:04 +0000 (01:36 -0800)
SCCS-vsn: sys/netccitt/llc_input.c 7.1

usr/src/sys/netccitt/llc_input.c [new file with mode: 0644]

diff --git a/usr/src/sys/netccitt/llc_input.c b/usr/src/sys/netccitt/llc_input.c
new file mode 100644 (file)
index 0000000..ffa70d6
--- /dev/null
@@ -0,0 +1,444 @@
+/* 
+ * Copyright (C) Dirk Husemann, Computer Science Department IV, 
+ *              University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
+ * Copyright (c) 1992   Regents of the University of California.
+ * All rights reserved.
+ * 
+ * This code is derived from software contributed to Berkeley by
+ * Dirk Husemann and the Computer Science Department (IV) of
+ * the University of Erlangen-Nuremberg, Germany.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)llc_input.c 7.1 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_llc.h>
+#include <net/route.h>
+
+#include <netccitt/dll.h>
+#include <netccitt/llc_var.h>
+
+/*
+ * This module implements LLC as specified by ISO 8802-2.
+ */
+
+
+/*
+ * llcintr() handles all LLC frames (except ISO CLNS ones for the time being)
+ *           and tries to pass them on to the appropriate network layer entity.
+ */
+void
+llcintr()
+{
+       register struct mbuf *m;
+       register int i;
+       register int frame_kind;
+       register u_char cmdrsp;
+       struct llc_linkcb *linkp;
+       struct rtentry *sirt;
+       struct npaidbentry *sapinfo;
+       struct sdl_hdr *sdlhdr;
+       struct llc *frame;
+       char *c;
+       long expected_len;
+
+       struct ifnet   *ifp;
+       struct rtentry *llrt;
+       struct rtentry *nlrt;
+
+       struct mbuf *m_adj();
+
+       for (;;) {
+               i = splimp();
+               IF_DEQUEUE(&llcintrq, m);
+               splx(i);
+               if (m == 0)
+                       break;
+#ifdef         DIAGNOSTIC
+               if ((m->m_flags & M_PKTHDR) == 0)
+                       panic("llcintr no HDR");
+#endif
+               /*
+                * Get ifp this packet was received on
+                */
+               ifp = m->m_pkthdr.rcvif;
+
+               sdlhdr = mtod(m, struct sdl_hdr *);
+
+               /*
+                * [Copied from net/ip_input.c]
+                *
+                * Check that the amount of data in the buffers is
+                * at least as much as the LLC header tells us.
+                * Trim mbufs if longer than expected.
+                * Drop packets if shorter than we think they are.
+                *
+                * Layout of mbuf chain at this point:
+                *
+                *  +-------------------------------+----+      -\
+                 *  |  sockaddr_dl src - sdlhdr_src | 20 |       \
+                 *  +-------------------------------+----+        |
+                *  |  sockaddr_dl dst - sdlhdr_dst | 20 |          > sizeof(struct sdl_hdr) == 44
+                *  +-------------------------------+----+         |
+                 *  |  LLC frame len - sdlhdr_len   | 04 |       /
+                *  +-------------------------------+----+      -/
+                * /
+                * | m_next
+                * \
+                 *  +----------------------------+----+         -\
+                 *  |  llc DSAP                 | 01 |    \
+                *  +----------------------------+----+     |
+                 *  |  llc SSAP                 | 01 |     |
+                *  +----------------------------+----+      > sdlhdr_len
+                 *  |  llc control              | 01 |     |
+                *  +----------------------------+----+     |
+                *  |  ...                       |    |    /
+                *                                       -/
+                *
+                * Thus the we expect to have exactly 
+                * (sdlhdr->sdlhdr_len+sizeof(struct sdl_hdr)) in the mbuf chain
+                */
+               expected_len = sdlhdr->sdlhdr_len + sizeof(struct sdl_hdr);
+
+               if (m->m_pkthdr.len < expected_len) {
+                       m_freem(m);
+                       continue;
+               }
+               if (m->m_pkthdr.len > expected_len) {
+                       if (m->m_len == m->m_pkthdr.len) {
+                               m->m_len = expected_len;
+                               m->m_pkthdr.len = expected_len;
+                       } else
+                               m_adj(m, expected_len - m->m_pkthdr.len);
+               }
+
+               /*
+                * Get llc header
+                */
+               if (m->m_len > sizeof(struct sdl_hdr))
+                       frame = mtod((struct mbuf *)((struct sdl_hdr*)(m+1)),
+                                    struct llc *);
+               else frame = mtod(m->m_next, struct llc *);
+               if (frame == (struct llc *) NULL)
+                       panic("llcintr no llc header");
+
+               /*
+                * Now check for bogus I/S frame, i.e. those with a control
+                * field telling us they're an I/S frame yet their length
+                * is less than the established I/S frame length (DSAP + SSAP +
+                * control + N(R)&P/F = 4) --- we drop those suckers
+                */
+               if (((frame->llc_control & 0x03) != 0x03) 
+                   && ((expected_len - sizeof(struct sdl_hdr)) < LLC_ISFRAMELEN)) {
+                       m_freem(m);
+                       printf("llc: hurz error\n");
+                       continue;
+               }
+
+               /*
+                * Get link control block for the addressed link connection.
+                * If there is none we take care of it later on.
+                */
+               cmdrsp = (frame->llc_ssap & 0x01);
+               frame->llc_ssap &= ~0x01;
+               if (llrt = rtalloc1(&sdlhdr->sdlhdr_src, 0))
+                       llrt->rt_refcnt--;
+#ifdef notyet
+               else llrt = npaidb_enter(&sdlhdr->sdlhdr_src, 0, 0, 0);
+#endif /* notyet */
+               else {
+                       /* 
+                        * We cannot do anything currently here as we
+                        * don't `know' this link --- drop it 
+                        */
+                       m_freem(m);
+                       continue;
+               }
+               linkp = ((struct npaidbentry *)(llrt->rt_llinfo))->np_link;
+               nlrt = ((struct npaidbentry *)(llrt->rt_llinfo))->np_rt;
+
+               /*
+                * If the link is not existing right now, we can try and look up
+                * the SAP info block.
+                */
+               if ((linkp == 0) && frame->llc_ssap) 
+                       sapinfo = llc_getsapinfo(frame->llc_dsap, ifp);
+
+               /*
+                * Handle XID and TEST frames
+                * XID:         if DLSAP == 0, return   type-of-services
+                *                                      window-0
+                *                                      DLSAP-0
+                *                                      format-identifier-?
+                *              if DLSAP != 0, locate sapcb and return
+                *                                      type-of-services
+                *                                      SAP-window
+                *                                      format-identifier-?
+                * TEST:        swap (snpah_dst, snpah_src) and return frame
+                *
+                * Also toggle the CMD/RESP bit
+                *
+                * Is this behaviour correct? Check ISO 8802-2 (90)!
+                */
+               frame_kind = llc_decode(frame, (struct llc_linkcb *)0);
+               switch(frame_kind) {
+               case LLCFT_XID:
+                       if (linkp || sapinfo) {
+                               if (linkp)
+                                       frame->llc_window = linkp->llcl_window;
+                               else frame->llc_window = sapinfo->si_window;
+                               frame->llc_fid = 9;                     /* XXX */
+                               frame->llc_class = sapinfo->si_class;
+                               frame->llc_ssap = frame->llc_dsap;
+                       } else {
+                               frame->llc_window = 0;
+                               frame->llc_fid = 9;
+                               frame->llc_class = 1;
+                               frame->llc_dsap = frame->llc_ssap = 0;
+                       }
+
+                       /* fall thru to */
+               case LLCFT_TEST:
+                       sdl_swapaddr(&(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
+                                    &(mtod(m, struct sdl_hdr *)->sdlhdr_src));
+
+                       /* Now set the CMD/RESP bit */
+                       frame->llc_ssap |= (cmdrsp == 0x0 ? 0x1 : 0x0);
+
+                       /* Ship it out again */
+                       (*ifp->if_output)(ifp, m,
+                                         (struct sockaddr *) &(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
+                                         (struct rtentry *) 0);
+                       continue;
+               }
+
+               /*
+                * Create link control block in case it is not existing
+                */
+               if (linkp == 0 && sapinfo) {
+                       if ((linkp = llc_newlink(&sdlhdr->sdlhdr_src, ifp, nlrt,
+                                                    (nlrt == 0) ? 0 : nlrt->rt_llinfo,
+                                                    llrt)) == 0) {
+                               printf("llcintr: couldn't create new link\n");
+                               m_freem(m);
+                               continue;
+                       }
+                       ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
+               } else if (linkp == 0) {
+                       /* The link is not known to us, drop the frame and continue */
+                       m_freem(m);
+                       continue;
+               }
+
+               /*
+                * Drop SNPA header and get rid of empty mbuf at the
+                * front of the mbuf chain (I don't like 'em)
+                */
+               m_adj(m, sizeof(struct sdl_hdr));
+               /* 
+                * LLC_UFRAMELEN is sufficient, m_pullup() will pull up
+                * the min(m->m_len, maxprotohdr_len [=40]) thus doing
+                * the trick ...
+                */
+               if ((m = m_pullup(m, LLC_UFRAMELEN)))
+                       /*
+                        * Pass it on thru the elements of procedure
+                        */
+                       llc_input(linkp, m, cmdrsp);
+       }
+       return;
+}
+
+/*
+ * llc_input() --- We deal with the various incoming frames here.
+ *                 Basically we (indirectly) call the appropriate
+ *                 state handler function that's pointed to by
+ *                 llcl_statehandler.
+ * 
+ *                 The statehandler returns an action code ---
+ *                 further actions like 
+ *                         o notify network layer
+ *                         o block further sending
+ *                         o deblock link
+ *                         o ...
+ *                 are then enacted accordingly.
+ */
+llc_input(struct llc_linkcb *linkp, struct mbuf *m, u_char cmdrsp)
+{
+       int frame_kind;
+       int pollfinal;
+       int action = 0;
+       struct llc *frame;
+       struct ifnet *ifp = linkp->llcl_if;
+
+       if ((frame = mtod(m, struct llc *)) == (struct llc *) 0) {
+               m_freem(m);
+               return 0;
+       }
+       pollfinal = ((frame->llc_control & 0x03) == 0x03) ? 
+               LLCGBITS(frame->llc_control, u_pf) :
+                       LLCGBITS(frame->llc_control_ext, s_pf);
+
+       /*
+        * first decode the frame
+        */
+       frame_kind = llc_decode(frame, linkp);
+
+       switch (action = llc_statehandler(linkp, frame, frame_kind, cmdrsp, 
+                                         pollfinal)) {
+       case LLC_DATA_INDICATION:
+               m_adj(m, LLC_ISFRAMELEN);
+               if (m = m_pullup(m, NLHDRSIZEGUESS)) {
+                       m->m_pkthdr.rcvif = (struct ifnet *)linkp->llcl_nlnext;
+                       (*linkp->llcl_sapinfo->si_input)(m);
+               }
+               break;
+       }
+
+       /* release mbuf if not an info frame */
+       if (action != LLC_DATA_INDICATION && m)
+               m_freem(m);
+
+       /* try to get frames out ... */
+       llc_start(linkp);
+
+       return 0;
+}
+
+/*
+ * This routine is called by configuration setup. It sets up a station control
+ * block and notifies all registered upper level protocols.
+ */
+caddr_t
+llc_ctlinput(int prc, struct sockaddr *addr, caddr_t info)
+{
+       struct ifnet *ifp;
+       struct ifaddr *ifa;
+       struct dll_ctlinfo *ctlinfo = (struct dll_ctlinfo *)info;
+       u_char sap;
+       struct dllconfig *config;
+       caddr_t pcb;
+       struct rtentry *nlrt;
+       struct rtentry *llrt;
+       struct llc_linkcb *linkp;
+       register int i;
+
+       /* info must point to something valid at all times */
+       if (info == 0)
+               return 0;
+
+       if (prc == PRC_IFUP || prc == PRC_IFDOWN) {
+               /* we use either this set ... */
+               ifa = ifa_ifwithaddr(addr);
+               ifp = ifa ? ifa->ifa_ifp : 0;
+               if (ifp == 0)
+                       return 0;
+
+               sap = ctlinfo->dlcti_lsap;
+               config = ctlinfo->dlcti_cfg;
+               pcb = (caddr_t) 0;
+               nlrt = (struct rtentry *) 0;
+       } else {
+               /* or this one */
+               sap = 0; 
+               config = (struct dllconfig *) 0;
+               pcb = ctlinfo->dlcti_pcb;
+               nlrt = ctlinfo->dlcti_rt;
+
+               if ((llrt = rtalloc1(nlrt->rt_gateway, 0)))
+                       llrt->rt_refcnt--;
+               else return 0;
+
+               linkp = ((struct npaidbentry *)llrt->rt_llinfo)->np_link;
+       }
+       
+       switch (prc) {
+       case PRC_IFUP:
+               (void) llc_setsapinfo(ifp, addr->sa_family, sap, config);
+               return 0;
+
+       case PRC_IFDOWN: {
+               register struct llc_linkcb *linkp;
+               register struct llc_linkcb *nlinkp;
+               register int i;
+
+               /*
+                * All links are accessible over the doubly linked list llccb_q
+                */
+               if (!LQEMPTY) {
+                       /*
+                        * A for-loop is not that great an idea as the linkp
+                        * will get deleted by llc_timer()
+                        */
+                       linkp = LQFIRST;
+                       while (LQVALID(linkp)) {
+                               nlinkp = LQNEXT(linkp);
+                               if (linkp->llcl_if = ifp) {
+                                       i = splimp();
+                                       (void)llc_statehandler(linkp, (struct llc *)0,
+                                                              NL_DISCONNECT_REQUEST,
+                                                              0, 1);
+                                       splx(i);
+                               }
+                               linkp = nlinkp;
+                       }
+               }
+       }
+       
+       case PRC_CONNECT_REQUEST: 
+               if (linkp == 0) {
+                       if ((linkp = llc_newlink((struct sockaddr_dl *) nlrt->rt_gateway, 
+                                                nlrt->rt_ifp, nlrt, 
+                                                pcb, llrt)) == 0)
+                               return (0);
+                       ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
+                       i = splimp();
+                       (void)llc_statehandler(linkp, (struct llc *) 0,
+                                               NL_CONNECT_REQUEST, 0, 1);
+                       splx(i);
+               }
+               return ((caddr_t)linkp);
+       
+       case PRC_DISCONNECT_REQUEST:
+               if (linkp == 0) 
+                       panic("no link control block!");
+
+               i = splimp();
+               (void)llc_statehandler(linkp, (struct llc *) 0,
+                                      NL_DISCONNECT_REQUEST, 0, 1);
+               splx(i);
+
+               /*
+                * The actual removal of the link control block is done by the
+                * cleaning neutrum (i.e. llc_timer()).
+                */
+               break;
+       
+       case PRC_RESET_REQUEST:
+               if (linkp == 0) 
+                       panic("no link control block!");
+
+               i = splimp();
+               (void)llc_statehandler(linkp, (struct llc *) 0,
+                                      NL_RESET_REQUEST, 0, 1);
+               splx(i);
+
+               break;
+
+       }
+       
+       return 0;
+}