date and time created 88/12/14 15:29:39 by sklower
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Thu, 15 Dec 1988 07:29:39 +0000 (23:29 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Thu, 15 Dec 1988 07:29:39 +0000 (23:29 -0800)
SCCS-vsn: sys/netiso/if_lpb.c 7.1

usr/src/sys/netiso/if_lpb.c [new file with mode: 0644]

diff --git a/usr/src/sys/netiso/if_lpb.c b/usr/src/sys/netiso/if_lpb.c
new file mode 100644 (file)
index 0000000..a34917d
--- /dev/null
@@ -0,0 +1,389 @@
+/***********************************************************
+               Copyright IBM Corporation 1987
+
+                      All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
+ */
+/*
+ * $Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $
+ * $Source: /usr/argo/sys/netiso/RCS/if_lpb.c,v $
+ *
+ *     LOOPBACK driver that mimics the
+ *     Eicon x.25 board for use by CONS
+ */
+
+#ifndef lint
+static char *rcsid = "$Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $";
+#endif lint
+
+
+#include "param.h"
+#include "systm.h"
+#include "types.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "ioctl.h"
+#include "errno.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../machine/io.h"
+#include "../machineio/ioccvar.h"
+
+#include "ecn.h"
+#include "../netiso/iso.h"
+#include "../netiso/argo_debug.h"
+#include "../caif/eicon.h"
+#include "iso_errno.h"
+
+#define LPB_DEBUG
+#ifdef LPB_DEBUG
+#define MT_LPB_OPEN    0x55
+#define MT_LPB_ACK     0x56
+#else LPB_DEBUG
+#define MT_LPB_DATA MT_DATA
+#define MT_LPB_ACK MT_DATA
+#endif LPB_DEBUG
+
+extern struct ifqueue  consintrq;      
+int                                            lpboutput();
+
+/* These next 2 declarations are for Logical Unit Numbers - i.e. VC # -
+ * the 2I assigns and frees them; we have to fake it
+ */
+
+static u_char                  free_luns[32];
+static u_char                  *next_lun = free_luns;
+
+/*
+ * Initialize all LUNs as available for use.
+ */
+init_lpb()
+{
+       register int i;
+
+       for (i = 0; i < 32; i++) {
+               free_luns[i] = i+1;
+       }
+       next_lun = free_luns;
+}
+
+/*
+ *     Allocate new logical unit number.
+ *  Allocating number n means that both n and -n are allocated & used.
+ *  NOTE: next_lun always points to an UNALLOCATED lun, hence
+ *      take a lun then increment, or decrement then stash the lun.
+ */
+
+u_char 
+getlun()
+{
+       if( ((next_lun) - free_luns) > 32 ) {
+               printf("PANIC: if_lpb: too many channels! \n");
+               return 0;
+       }
+       IFDEBUG(D_CCONN)
+               printf("getlun: returns 0x%x\n", *next_lun);
+       ENDDEBUG
+       ASSERT( *next_lun != 0 );
+       if( *next_lun == 0 ) {
+               register int i;
+
+               printf(
+               "PANIC IN lpb: free_luns 0x%x next_len 0x%x *next_lun 0x%x\n",
+                       free_luns, next_lun, *next_lun);
+               
+               for(i=0; i<32; i++) {
+                       printf("free_luns[ 0x%x ] = 0x%x\n", i, free_luns[i] );
+               }
+       }
+       return *(next_lun++);
+
+}
+
+/* 
+ * When you free one you free its neg 
+ */
+
+freelun(lun)
+u_char lun;
+{
+       IFDEBUG(D_CCONN)
+               printf("freelun(0x%x)\n", lun);
+       ENDDEBUG
+       if( lun > 32 )
+               return;
+
+       ASSERT( (lun & 0xc0) == 0 );
+       ASSERT( lun <= 32 );
+
+       /* check for lun already in the list */
+       {
+               register u_char *r = next_lun;
+
+               while( (int)(r - free_luns) <= 32 ) {
+                       if( *r == lun ) {
+                               return;
+                       }
+                       r++;
+               }
+       }
+
+       next_lun --;
+       *next_lun = lun;
+}
+
+
+/*
+ * FUNCTION:           lpboutput
+ *
+ * PURPOSE:                    Process an eicon x.25 request from a higher layer
+ *                                     protocol.
+ * ARGUMENTS:          (ifp) is points to the ifnet structure for this unit/device
+ *                                     (m)  is an mbuf *, *m is an eicon request structure
+ *
+ * RETURNS:                    unix error code
+ *
+ * NOTES:                      Mimics the eicon driver.
+ *
+ */
+lpboutput(ifp,m)
+       register struct ifnet   *ifp;
+       register struct mbuf    *m;                     /* request */
+{
+       int                                                     s;
+       struct eicon_request            *req;
+       int                                                     error = 0;
+
+       /* Do this even if (ifp->if_flags & IFF_LOOPBACK) == 0
+        * because whether or not a vc is on loopback is determined
+        * at the time of connection establishement.
+        */
+       s = splnet();
+       req = mtod(m, struct eicon_request *);
+       IFDEBUG(D_CDUMP_REQ)
+               dump_buf(req, sizeof(struct eicon_request));
+       ENDDEBUG
+       switch (req->e_cmd) {
+               case ECN_CALL: {
+                       /*
+                        *      ECN_CALL        ->      ECN_ACCEPT (for orig CONNECT)
+                        *                              ->      ECN_CONNECT     (other side's connect indication)
+                        */
+                       struct mbuf *mdata;
+                       struct mbuf *mopen;
+                       struct eicon_request *open;
+
+                       MGET(mopen, M_DONTWAIT, MT_LPB_OPEN);
+                       if (mopen == NULL) {
+                               printf("No mbufs for copy\n");
+                               error = ENOBUFS;
+                               break;
+                       }
+                       mopen->m_len = sizeof(struct eicon_request);
+
+                       open = mtod(mopen, struct eicon_request *);
+                       bcopy( req, open, sizeof(struct eicon_request) );
+
+                       /* get mbuf for the connect data */
+                       MGET(mdata, M_DONTWAIT, MT_LPB_OPEN);
+                       if (mdata == NULL) {
+                               printf("No mbufs for copy\n");
+                               error = ENOBUFS;
+                               break;
+                       }
+                       mdata->m_len = (e_data(req))->m_len;
+                       e_data(open) = mdata; /* e_data is really mtod(open)->m_next */
+                       /* make a copy of the connect data */
+                       IFDEBUG(D_CCONN)
+                               printf("bcopy( 0x%x, 0x%x, 0x%x)\n", mtod(e_data(req), caddr_t),
+                                               mtod(mdata, caddr_t), 
+                                               (e_data(req))->m_len);
+                       ENDDEBUG
+                       bcopy( mtod(e_data(req), caddr_t), mtod(mdata, caddr_t), 
+                                               (e_data(req))->m_len);
+                       /* setup call */
+                       open->e_cmd = ECN_CONNECT;
+                       open->e_vc = getlun();
+
+                       /* setup call confirm */
+                       req->e_cmd = ECN_ACCEPT;
+                       req->e_vc = -(open->e_vc);
+
+                       IFDEBUG(D_CDUMP_REQ)
+                               printf("lpboutput CALL middle \n");
+                       ENDDEBUG
+
+                       if (IF_QFULL(&consintrq)) {
+                               IF_DROP(&consintrq);
+                               m_freem(mopen);
+                               printf("lpboutput: response dropped\n");
+                               error = ENOBUFS;
+                               break;
+                       } else {
+                               /* connect */
+                               IFDEBUG(D_CCONS);
+                                       printf("CONNECT 0x%x --> X25INTRQ\n", mopen);
+                               ENDDEBUG
+                               IF_ENQUEUE(&consintrq, mopen);
+                               IFDEBUG(D_CDUMP_REQ);
+                                       dump_buf(open, sizeof(struct eicon_request));
+                               ENDDEBUG
+
+                               /* confirm */
+                               IFDEBUG(D_CCONS);
+                                       printf("CONFIRM 0x%x (data 0x%x =?= 0x%x) --> X25INTRQ\n", 
+                                               m, m->m_next, e_data(req));
+                               ENDDEBUG
+                               IF_ENQUEUE(&consintrq, m);
+                               IFDEBUG(D_CDUMP_REQ);
+                                       dump_buf(req, sizeof(struct eicon_request));
+                               ENDDEBUG
+                       }
+               } break;
+               
+               case ECN_RESET: 
+               case ECN_CLEAR: {
+                       /*
+                        *      ECN_RESET       ->      ECN_RESET       (other side's reset indication)
+                        *      ECN_CLEAR       ->      ECN_CLEAR       (other side's close indication)
+                        * TODO: MAY HAVE DATA PACKET! 
+                        * TODO: Have to be able to handle a 2nd CLEAR on on vc!
+                        */
+                       freelun(req->e_vc);
+                       freelun((-req->e_vc)&0xff);
+                       req->e_vc = -req->e_vc; /* other side */
+                       req->e_reason = E_CO_PDNCLRESET;
+                       if (IF_QFULL(&consintrq)) {
+                               IF_DROP(&consintrq);
+                               printf("lpboutput: respose dropped\n");
+                               error = ENOBUFS;
+                       } else {
+                               IFDEBUG(D_CCONS);
+                                       printf("CLOSE 0x%x --> X25INTRQ\n", m);
+                               ENDDEBUG
+                               IF_ENQUEUE(&consintrq, m);
+                               IFDEBUG(D_CDUMP_REQ);
+                                       dump_buf(req, sizeof(struct eicon_request));
+                               ENDDEBUG
+                       }
+               } break;
+               
+               case ECN_SEND: {
+                       /*
+                        *      ECN_SEND        ->      ECN_RECEIVE     (data send becomes data recvd)
+                        */
+                       struct mbuf *m0;
+                       struct eicon_request *ack;
+
+                       MGET(m0, M_DONTWAIT, MT_LPB_ACK); /* sets type, next, off */
+                       if (m0 == NULL) {
+                               printf("PANIC No mbufs for copy\n");
+                               error = ENOBUFS;
+                               break;
+                       }
+                       m0->m_len = sizeof(struct eicon_request);
+
+                       ack = mtod(m0, struct eicon_request *);
+                       /* setup ack */
+                       ack->e_cmd = ECN_ACK;
+                       ack->e_vc = req->e_vc;
+                       req->e_vc = -req->e_vc;
+                       req->e_cmd = ECN_RECEIVE;
+
+                       if (IF_QFULL(&consintrq)) {
+                               IF_DROP(&consintrq);
+                               printf("lpboutput: ADR_ACK DROPPED\n");
+                               m_freem(m0);
+                               error = ECONNABORTED;
+                       } else {
+                               IF_ENQUEUE(&consintrq, m);
+                               IFDEBUG(D_CCONS);
+                                       printf("DATA 0x%x --> X25INTRQ\n", m);
+                               ENDDEBUG
+                               IFDEBUG(D_CDUMP_REQ);
+                                       dump_buf(req, sizeof(struct eicon_request));
+                               ENDDEBUG
+                               IFDEBUG(D_CCONS);
+                                       printf("ACK 0x%x --> X25INTRQ\n", m0);
+                               ENDDEBUG
+                               IF_ENQUEUE(&consintrq, m0);
+                               IFDEBUG(D_CDUMP_REQ);
+                                       dump_buf(ack, sizeof(struct eicon_request));
+                               ENDDEBUG
+                       }
+               } break;
+               
+               default:
+                       printf("Bad loopback request 0x%x\n", req->e_cmd);
+                       error = EINVAL;
+       }
+
+       if( error ) {
+               m_freem(m);
+       } else
+               schednetisr(NETISR_X25);
+
+       splx(s);
+       return error;
+}
+
+#if NECN>0
+       /* nothing */
+#else
+
+/* KLUDGE: when no ecn board config-ed in, we need a routing
+ * ecnifp to return null.  We want to be able to configure with
+ * sw loopback only.
+ */
+struct ifnet  *
+ecnifp(unit)
+int unit;
+{
+       return (struct ifnet *)NULL;
+}
+
+int
+ecnoutput(ifp, m)
+       struct ifnet *ifp;
+       struct mbuf *m;
+{
+       printf("ecnoutput: ecn not configured\n");
+       (void) m_freem(m);
+       return ENETDOWN;
+               
+}
+
+ecnshutdown(ifp)
+{
+       printf("ecnshutdown: ecn not configured\n");
+}
+
+ecnrestart(ifp)
+{
+       printf("ecnrestart: ecn not configured\n");
+}
+#endif NECN>0