136383Ssklower /***********************************************************
236383Ssklower Copyright IBM Corporation 1987
336383Ssklower
436383Ssklower All Rights Reserved
536383Ssklower
636383Ssklower Permission to use, copy, modify, and distribute this software and its
736383Ssklower documentation for any purpose and without fee is hereby granted,
836383Ssklower provided that the above copyright notice appear in all copies and that
936383Ssklower both that copyright notice and this permission notice appear in
1036383Ssklower supporting documentation, and that the name of IBM not be
1136383Ssklower used in advertising or publicity pertaining to distribution of the
1236383Ssklower software without specific, written prior permission.
1336383Ssklower
1436383Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536383Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636383Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736383Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836383Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936383Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036383Ssklower SOFTWARE.
2136383Ssklower
2236383Ssklower ******************************************************************/
2336383Ssklower
2436383Ssklower /*
2536383Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636383Ssklower */
2736383Ssklower /*
2836383Ssklower * $Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $
2936383Ssklower * $Source: /usr/argo/sys/netiso/RCS/if_lpb.c,v $
3036383Ssklower *
3136383Ssklower * LOOPBACK driver that mimics the
3236383Ssklower * Eicon x.25 board for use by CONS
3336383Ssklower */
3436383Ssklower
3536383Ssklower #ifndef lint
3636383Ssklower static char *rcsid = "$Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $";
3736383Ssklower #endif lint
3836383Ssklower
3936383Ssklower
4036383Ssklower #include "param.h"
4136383Ssklower #include "systm.h"
4236383Ssklower #include "types.h"
4336383Ssklower #include "mbuf.h"
4436383Ssklower #include "buf.h"
4536383Ssklower #include "protosw.h"
4636383Ssklower #include "socket.h"
4736383Ssklower #include "ioctl.h"
4836383Ssklower #include "errno.h"
4936383Ssklower
5036383Ssklower #include "../net/if.h"
5136383Ssklower #include "../net/netisr.h"
5236383Ssklower #include "../net/route.h"
53*37518Smckusick #include "machine/io.h"
5436383Ssklower #include "../machineio/ioccvar.h"
5536383Ssklower
5636383Ssklower #include "ecn.h"
5737469Ssklower #include "iso.h"
5837469Ssklower #include "argo_debug.h"
5936383Ssklower #include "../caif/eicon.h"
6036383Ssklower #include "iso_errno.h"
6136383Ssklower
6236383Ssklower #define LPB_DEBUG
6336383Ssklower #ifdef LPB_DEBUG
6436383Ssklower #define MT_LPB_OPEN 0x55
6536383Ssklower #define MT_LPB_ACK 0x56
6636383Ssklower #else LPB_DEBUG
6736383Ssklower #define MT_LPB_DATA MT_DATA
6836383Ssklower #define MT_LPB_ACK MT_DATA
6936383Ssklower #endif LPB_DEBUG
7036383Ssklower
7136383Ssklower extern struct ifqueue consintrq;
7236383Ssklower int lpboutput();
7336383Ssklower
7436383Ssklower /* These next 2 declarations are for Logical Unit Numbers - i.e. VC # -
7536383Ssklower * the 2I assigns and frees them; we have to fake it
7636383Ssklower */
7736383Ssklower
7836383Ssklower static u_char free_luns[32];
7936383Ssklower static u_char *next_lun = free_luns;
8036383Ssklower
8136383Ssklower /*
8236383Ssklower * Initialize all LUNs as available for use.
8336383Ssklower */
init_lpb()8436383Ssklower init_lpb()
8536383Ssklower {
8636383Ssklower register int i;
8736383Ssklower
8836383Ssklower for (i = 0; i < 32; i++) {
8936383Ssklower free_luns[i] = i+1;
9036383Ssklower }
9136383Ssklower next_lun = free_luns;
9236383Ssklower }
9336383Ssklower
9436383Ssklower /*
9536383Ssklower * Allocate new logical unit number.
9636383Ssklower * Allocating number n means that both n and -n are allocated & used.
9736383Ssklower * NOTE: next_lun always points to an UNALLOCATED lun, hence
9836383Ssklower * take a lun then increment, or decrement then stash the lun.
9936383Ssklower */
10036383Ssklower
10136383Ssklower u_char
getlun()10236383Ssklower getlun()
10336383Ssklower {
10436383Ssklower if( ((next_lun) - free_luns) > 32 ) {
10536383Ssklower printf("PANIC: if_lpb: too many channels! \n");
10636383Ssklower return 0;
10736383Ssklower }
10836383Ssklower IFDEBUG(D_CCONN)
10936383Ssklower printf("getlun: returns 0x%x\n", *next_lun);
11036383Ssklower ENDDEBUG
11136383Ssklower ASSERT( *next_lun != 0 );
11236383Ssklower if( *next_lun == 0 ) {
11336383Ssklower register int i;
11436383Ssklower
11536383Ssklower printf(
11636383Ssklower "PANIC IN lpb: free_luns 0x%x next_len 0x%x *next_lun 0x%x\n",
11736383Ssklower free_luns, next_lun, *next_lun);
11836383Ssklower
11936383Ssklower for(i=0; i<32; i++) {
12036383Ssklower printf("free_luns[ 0x%x ] = 0x%x\n", i, free_luns[i] );
12136383Ssklower }
12236383Ssklower }
12336383Ssklower return *(next_lun++);
12436383Ssklower
12536383Ssklower }
12636383Ssklower
12736383Ssklower /*
12836383Ssklower * When you free one you free its neg
12936383Ssklower */
13036383Ssklower
freelun(lun)13136383Ssklower freelun(lun)
13236383Ssklower u_char lun;
13336383Ssklower {
13436383Ssklower IFDEBUG(D_CCONN)
13536383Ssklower printf("freelun(0x%x)\n", lun);
13636383Ssklower ENDDEBUG
13736383Ssklower if( lun > 32 )
13836383Ssklower return;
13936383Ssklower
14036383Ssklower ASSERT( (lun & 0xc0) == 0 );
14136383Ssklower ASSERT( lun <= 32 );
14236383Ssklower
14336383Ssklower /* check for lun already in the list */
14436383Ssklower {
14536383Ssklower register u_char *r = next_lun;
14636383Ssklower
14736383Ssklower while( (int)(r - free_luns) <= 32 ) {
14836383Ssklower if( *r == lun ) {
14936383Ssklower return;
15036383Ssklower }
15136383Ssklower r++;
15236383Ssklower }
15336383Ssklower }
15436383Ssklower
15536383Ssklower next_lun --;
15636383Ssklower *next_lun = lun;
15736383Ssklower }
15836383Ssklower
15936383Ssklower
16036383Ssklower /*
16136383Ssklower * FUNCTION: lpboutput
16236383Ssklower *
16336383Ssklower * PURPOSE: Process an eicon x.25 request from a higher layer
16436383Ssklower * protocol.
16536383Ssklower * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device
16636383Ssklower * (m) is an mbuf *, *m is an eicon request structure
16736383Ssklower *
16836383Ssklower * RETURNS: unix error code
16936383Ssklower *
17036383Ssklower * NOTES: Mimics the eicon driver.
17136383Ssklower *
17236383Ssklower */
lpboutput(ifp,m)17336383Ssklower lpboutput(ifp,m)
17436383Ssklower register struct ifnet *ifp;
17536383Ssklower register struct mbuf *m; /* request */
17636383Ssklower {
17736383Ssklower int s;
17836383Ssklower struct eicon_request *req;
17936383Ssklower int error = 0;
18036383Ssklower
18136383Ssklower /* Do this even if (ifp->if_flags & IFF_LOOPBACK) == 0
18236383Ssklower * because whether or not a vc is on loopback is determined
18336383Ssklower * at the time of connection establishement.
18436383Ssklower */
18536383Ssklower s = splnet();
18636383Ssklower req = mtod(m, struct eicon_request *);
18736383Ssklower IFDEBUG(D_CDUMP_REQ)
18836383Ssklower dump_buf(req, sizeof(struct eicon_request));
18936383Ssklower ENDDEBUG
19036383Ssklower switch (req->e_cmd) {
19136383Ssklower case ECN_CALL: {
19236383Ssklower /*
19336383Ssklower * ECN_CALL -> ECN_ACCEPT (for orig CONNECT)
19436383Ssklower * -> ECN_CONNECT (other side's connect indication)
19536383Ssklower */
19636383Ssklower struct mbuf *mdata;
19736383Ssklower struct mbuf *mopen;
19836383Ssklower struct eicon_request *open;
19936383Ssklower
20036383Ssklower MGET(mopen, M_DONTWAIT, MT_LPB_OPEN);
20136383Ssklower if (mopen == NULL) {
20236383Ssklower printf("No mbufs for copy\n");
20336383Ssklower error = ENOBUFS;
20436383Ssklower break;
20536383Ssklower }
20636383Ssklower mopen->m_len = sizeof(struct eicon_request);
20736383Ssklower
20836383Ssklower open = mtod(mopen, struct eicon_request *);
20936383Ssklower bcopy( req, open, sizeof(struct eicon_request) );
21036383Ssklower
21136383Ssklower /* get mbuf for the connect data */
21236383Ssklower MGET(mdata, M_DONTWAIT, MT_LPB_OPEN);
21336383Ssklower if (mdata == NULL) {
21436383Ssklower printf("No mbufs for copy\n");
21536383Ssklower error = ENOBUFS;
21636383Ssklower break;
21736383Ssklower }
21836383Ssklower mdata->m_len = (e_data(req))->m_len;
21936383Ssklower e_data(open) = mdata; /* e_data is really mtod(open)->m_next */
22036383Ssklower /* make a copy of the connect data */
22136383Ssklower IFDEBUG(D_CCONN)
22236383Ssklower printf("bcopy( 0x%x, 0x%x, 0x%x)\n", mtod(e_data(req), caddr_t),
22336383Ssklower mtod(mdata, caddr_t),
22436383Ssklower (e_data(req))->m_len);
22536383Ssklower ENDDEBUG
22636383Ssklower bcopy( mtod(e_data(req), caddr_t), mtod(mdata, caddr_t),
22736383Ssklower (e_data(req))->m_len);
22836383Ssklower /* setup call */
22936383Ssklower open->e_cmd = ECN_CONNECT;
23036383Ssklower open->e_vc = getlun();
23136383Ssklower
23236383Ssklower /* setup call confirm */
23336383Ssklower req->e_cmd = ECN_ACCEPT;
23436383Ssklower req->e_vc = -(open->e_vc);
23536383Ssklower
23636383Ssklower IFDEBUG(D_CDUMP_REQ)
23736383Ssklower printf("lpboutput CALL middle \n");
23836383Ssklower ENDDEBUG
23936383Ssklower
24036383Ssklower if (IF_QFULL(&consintrq)) {
24136383Ssklower IF_DROP(&consintrq);
24236383Ssklower m_freem(mopen);
24336383Ssklower printf("lpboutput: response dropped\n");
24436383Ssklower error = ENOBUFS;
24536383Ssklower break;
24636383Ssklower } else {
24736383Ssklower /* connect */
24836383Ssklower IFDEBUG(D_CCONS);
24936383Ssklower printf("CONNECT 0x%x --> X25INTRQ\n", mopen);
25036383Ssklower ENDDEBUG
25136383Ssklower IF_ENQUEUE(&consintrq, mopen);
25236383Ssklower IFDEBUG(D_CDUMP_REQ);
25336383Ssklower dump_buf(open, sizeof(struct eicon_request));
25436383Ssklower ENDDEBUG
25536383Ssklower
25636383Ssklower /* confirm */
25736383Ssklower IFDEBUG(D_CCONS);
25836383Ssklower printf("CONFIRM 0x%x (data 0x%x =?= 0x%x) --> X25INTRQ\n",
25936383Ssklower m, m->m_next, e_data(req));
26036383Ssklower ENDDEBUG
26136383Ssklower IF_ENQUEUE(&consintrq, m);
26236383Ssklower IFDEBUG(D_CDUMP_REQ);
26336383Ssklower dump_buf(req, sizeof(struct eicon_request));
26436383Ssklower ENDDEBUG
26536383Ssklower }
26636383Ssklower } break;
26736383Ssklower
26836383Ssklower case ECN_RESET:
26936383Ssklower case ECN_CLEAR: {
27036383Ssklower /*
27136383Ssklower * ECN_RESET -> ECN_RESET (other side's reset indication)
27236383Ssklower * ECN_CLEAR -> ECN_CLEAR (other side's close indication)
27336383Ssklower * TODO: MAY HAVE DATA PACKET!
27436383Ssklower * TODO: Have to be able to handle a 2nd CLEAR on on vc!
27536383Ssklower */
27636383Ssklower freelun(req->e_vc);
27736383Ssklower freelun((-req->e_vc)&0xff);
27836383Ssklower req->e_vc = -req->e_vc; /* other side */
27936383Ssklower req->e_reason = E_CO_PDNCLRESET;
28036383Ssklower if (IF_QFULL(&consintrq)) {
28136383Ssklower IF_DROP(&consintrq);
28236383Ssklower printf("lpboutput: respose dropped\n");
28336383Ssklower error = ENOBUFS;
28436383Ssklower } else {
28536383Ssklower IFDEBUG(D_CCONS);
28636383Ssklower printf("CLOSE 0x%x --> X25INTRQ\n", m);
28736383Ssklower ENDDEBUG
28836383Ssklower IF_ENQUEUE(&consintrq, m);
28936383Ssklower IFDEBUG(D_CDUMP_REQ);
29036383Ssklower dump_buf(req, sizeof(struct eicon_request));
29136383Ssklower ENDDEBUG
29236383Ssklower }
29336383Ssklower } break;
29436383Ssklower
29536383Ssklower case ECN_SEND: {
29636383Ssklower /*
29736383Ssklower * ECN_SEND -> ECN_RECEIVE (data send becomes data recvd)
29836383Ssklower */
29936383Ssklower struct mbuf *m0;
30036383Ssklower struct eicon_request *ack;
30136383Ssklower
30236383Ssklower MGET(m0, M_DONTWAIT, MT_LPB_ACK); /* sets type, next, off */
30336383Ssklower if (m0 == NULL) {
30436383Ssklower printf("PANIC No mbufs for copy\n");
30536383Ssklower error = ENOBUFS;
30636383Ssklower break;
30736383Ssklower }
30836383Ssklower m0->m_len = sizeof(struct eicon_request);
30936383Ssklower
31036383Ssklower ack = mtod(m0, struct eicon_request *);
31136383Ssklower /* setup ack */
31236383Ssklower ack->e_cmd = ECN_ACK;
31336383Ssklower ack->e_vc = req->e_vc;
31436383Ssklower req->e_vc = -req->e_vc;
31536383Ssklower req->e_cmd = ECN_RECEIVE;
31636383Ssklower
31736383Ssklower if (IF_QFULL(&consintrq)) {
31836383Ssklower IF_DROP(&consintrq);
31936383Ssklower printf("lpboutput: ADR_ACK DROPPED\n");
32036383Ssklower m_freem(m0);
32136383Ssklower error = ECONNABORTED;
32236383Ssklower } else {
32336383Ssklower IF_ENQUEUE(&consintrq, m);
32436383Ssklower IFDEBUG(D_CCONS);
32536383Ssklower printf("DATA 0x%x --> X25INTRQ\n", m);
32636383Ssklower ENDDEBUG
32736383Ssklower IFDEBUG(D_CDUMP_REQ);
32836383Ssklower dump_buf(req, sizeof(struct eicon_request));
32936383Ssklower ENDDEBUG
33036383Ssklower IFDEBUG(D_CCONS);
33136383Ssklower printf("ACK 0x%x --> X25INTRQ\n", m0);
33236383Ssklower ENDDEBUG
33336383Ssklower IF_ENQUEUE(&consintrq, m0);
33436383Ssklower IFDEBUG(D_CDUMP_REQ);
33536383Ssklower dump_buf(ack, sizeof(struct eicon_request));
33636383Ssklower ENDDEBUG
33736383Ssklower }
33836383Ssklower } break;
33936383Ssklower
34036383Ssklower default:
34136383Ssklower printf("Bad loopback request 0x%x\n", req->e_cmd);
34236383Ssklower error = EINVAL;
34336383Ssklower }
34436383Ssklower
34536383Ssklower if( error ) {
34636383Ssklower m_freem(m);
34736383Ssklower } else
34836383Ssklower schednetisr(NETISR_X25);
34936383Ssklower
35036383Ssklower splx(s);
35136383Ssklower return error;
35236383Ssklower }
35336383Ssklower
35436383Ssklower #if NECN>0
35536383Ssklower /* nothing */
35636383Ssklower #else
35736383Ssklower
35836383Ssklower /* KLUDGE: when no ecn board config-ed in, we need a routing
35936383Ssklower * ecnifp to return null. We want to be able to configure with
36036383Ssklower * sw loopback only.
36136383Ssklower */
36236383Ssklower struct ifnet *
ecnifp(unit)36336383Ssklower ecnifp(unit)
36436383Ssklower int unit;
36536383Ssklower {
36636383Ssklower return (struct ifnet *)NULL;
36736383Ssklower }
36836383Ssklower
36936383Ssklower int
ecnoutput(ifp,m)37036383Ssklower ecnoutput(ifp, m)
37136383Ssklower struct ifnet *ifp;
37236383Ssklower struct mbuf *m;
37336383Ssklower {
37436383Ssklower printf("ecnoutput: ecn not configured\n");
37536383Ssklower (void) m_freem(m);
37636383Ssklower return ENETDOWN;
37736383Ssklower
37836383Ssklower }
37936383Ssklower
ecnshutdown(ifp)38036383Ssklower ecnshutdown(ifp)
38136383Ssklower {
38236383Ssklower printf("ecnshutdown: ecn not configured\n");
38336383Ssklower }
38436383Ssklower
ecnrestart(ifp)38536383Ssklower ecnrestart(ifp)
38636383Ssklower {
38736383Ssklower printf("ecnrestart: ecn not configured\n");
38836383Ssklower }
38936383Ssklower #endif NECN>0
390