xref: /original-bsd/sys/netiso/if_lpb.c (revision 04ace372)
1 /***********************************************************
2 		Copyright IBM Corporation 1987
3 
4                       All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of IBM not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13 
14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 ******************************************************************/
23 
24 /*
25  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26  */
27 /*
28  * $Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $
29  * $Source: /usr/argo/sys/netiso/RCS/if_lpb.c,v $
30  *
31  *	LOOPBACK driver that mimics the
32  *	Eicon x.25 board for use by CONS
33  */
34 
35 #ifndef lint
36 static char *rcsid = "$Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $";
37 #endif lint
38 
39 
40 #include "param.h"
41 #include "systm.h"
42 #include "types.h"
43 #include "mbuf.h"
44 #include "buf.h"
45 #include "protosw.h"
46 #include "socket.h"
47 #include "ioctl.h"
48 #include "errno.h"
49 
50 #include "../net/if.h"
51 #include "../net/netisr.h"
52 #include "../net/route.h"
53 #include "machine/io.h"
54 #include "../machineio/ioccvar.h"
55 
56 #include "ecn.h"
57 #include "iso.h"
58 #include "argo_debug.h"
59 #include "../caif/eicon.h"
60 #include "iso_errno.h"
61 
62 #define LPB_DEBUG
63 #ifdef LPB_DEBUG
64 #define MT_LPB_OPEN	0x55
65 #define MT_LPB_ACK 	0x56
66 #else LPB_DEBUG
67 #define MT_LPB_DATA MT_DATA
68 #define MT_LPB_ACK MT_DATA
69 #endif LPB_DEBUG
70 
71 extern struct ifqueue 	consintrq;
72 int						lpboutput();
73 
74 /* These next 2 declarations are for Logical Unit Numbers - i.e. VC # -
75  * the 2I assigns and frees them; we have to fake it
76  */
77 
78 static u_char 			free_luns[32];
79 static u_char 			*next_lun = free_luns;
80 
81 /*
82  * Initialize all LUNs as available for use.
83  */
84 init_lpb()
85 {
86 	register int i;
87 
88 	for (i = 0; i < 32; i++) {
89 		free_luns[i] = i+1;
90 	}
91 	next_lun = free_luns;
92 }
93 
94 /*
95  *	Allocate new logical unit number.
96  *  Allocating number n means that both n and -n are allocated & used.
97  *  NOTE: next_lun always points to an UNALLOCATED lun, hence
98  *	 take a lun then increment, or decrement then stash the lun.
99  */
100 
101 u_char
102 getlun()
103 {
104 	if( ((next_lun) - free_luns) > 32 ) {
105 		printf("PANIC: if_lpb: too many channels! \n");
106 		return 0;
107 	}
108 	IFDEBUG(D_CCONN)
109 		printf("getlun: returns 0x%x\n", *next_lun);
110 	ENDDEBUG
111 	ASSERT( *next_lun != 0 );
112 	if( *next_lun == 0 ) {
113 		register int i;
114 
115 		printf(
116 		"PANIC IN lpb: free_luns 0x%x next_len 0x%x *next_lun 0x%x\n",
117 			free_luns, next_lun, *next_lun);
118 
119 		for(i=0; i<32; i++) {
120 			printf("free_luns[ 0x%x ] = 0x%x\n", i, free_luns[i] );
121 		}
122 	}
123 	return *(next_lun++);
124 
125 }
126 
127 /*
128  * When you free one you free its neg
129  */
130 
131 freelun(lun)
132 u_char	lun;
133 {
134 	IFDEBUG(D_CCONN)
135 		printf("freelun(0x%x)\n", lun);
136 	ENDDEBUG
137 	if( lun > 32 )
138 		return;
139 
140 	ASSERT( (lun & 0xc0) == 0 );
141 	ASSERT( lun <= 32 );
142 
143 	/* check for lun already in the list */
144 	{
145 		register u_char *r = next_lun;
146 
147 		while( (int)(r - free_luns) <= 32 ) {
148 			if( *r == lun ) {
149 				return;
150 			}
151 			r++;
152 		}
153 	}
154 
155 	next_lun --;
156 	*next_lun = lun;
157 }
158 
159 
160 /*
161  * FUNCTION:		lpboutput
162  *
163  * PURPOSE:			Process an eicon x.25 request from a higher layer
164  *					protocol.
165  * ARGUMENTS:	 	(ifp) is points to the ifnet structure for this unit/device
166  *					(m)  is an mbuf *, *m is an eicon request structure
167  *
168  * RETURNS:			unix error code
169  *
170  * NOTES:			Mimics the eicon driver.
171  *
172  */
173 lpboutput(ifp,m)
174 	register struct ifnet 	*ifp;
175 	register struct mbuf	*m;			/* request */
176 {
177 	int							s;
178 	struct eicon_request		*req;
179 	int							error = 0;
180 
181 	/* Do this even if (ifp->if_flags & IFF_LOOPBACK) == 0
182 	 * because whether or not a vc is on loopback is determined
183 	 * at the time of connection establishement.
184 	 */
185 	s = splnet();
186 	req = mtod(m, struct eicon_request *);
187 	IFDEBUG(D_CDUMP_REQ)
188 		dump_buf(req, sizeof(struct eicon_request));
189 	ENDDEBUG
190 	switch (req->e_cmd) {
191 		case ECN_CALL: {
192 			/*
193 			 *	ECN_CALL	->	ECN_ACCEPT (for orig CONNECT)
194 			 *				->	ECN_CONNECT	(other side's connect indication)
195 			 */
196 			struct mbuf *mdata;
197 			struct mbuf *mopen;
198 			struct eicon_request *open;
199 
200 			MGET(mopen, M_DONTWAIT, MT_LPB_OPEN);
201 			if (mopen == NULL) {
202 				printf("No mbufs for copy\n");
203 				error = ENOBUFS;
204 				break;
205 			}
206 			mopen->m_len = sizeof(struct eicon_request);
207 
208 			open = mtod(mopen, struct eicon_request *);
209 			bcopy( req, open, sizeof(struct eicon_request) );
210 
211 			/* get mbuf for the connect data */
212 			MGET(mdata, M_DONTWAIT, MT_LPB_OPEN);
213 			if (mdata == NULL) {
214 				printf("No mbufs for copy\n");
215 				error = ENOBUFS;
216 				break;
217 			}
218 			mdata->m_len = (e_data(req))->m_len;
219 			e_data(open) = mdata; /* e_data is really mtod(open)->m_next */
220 			/* make a copy of the connect data */
221 			IFDEBUG(D_CCONN)
222 				printf("bcopy( 0x%x, 0x%x, 0x%x)\n", mtod(e_data(req), caddr_t),
223 						mtod(mdata, caddr_t),
224 						(e_data(req))->m_len);
225 			ENDDEBUG
226 			bcopy( mtod(e_data(req), caddr_t), mtod(mdata, caddr_t),
227 						(e_data(req))->m_len);
228 			/* setup call */
229 			open->e_cmd = ECN_CONNECT;
230 			open->e_vc = getlun();
231 
232 			/* setup call confirm */
233 			req->e_cmd = ECN_ACCEPT;
234 			req->e_vc = -(open->e_vc);
235 
236 			IFDEBUG(D_CDUMP_REQ)
237 				printf("lpboutput CALL middle \n");
238 			ENDDEBUG
239 
240 			if (IF_QFULL(&consintrq)) {
241 				IF_DROP(&consintrq);
242 				m_freem(mopen);
243 				printf("lpboutput: response dropped\n");
244 				error = ENOBUFS;
245 				break;
246 			} else {
247 				/* connect */
248 				IFDEBUG(D_CCONS);
249 					printf("CONNECT 0x%x --> X25INTRQ\n", mopen);
250 				ENDDEBUG
251 				IF_ENQUEUE(&consintrq, mopen);
252 				IFDEBUG(D_CDUMP_REQ);
253 					dump_buf(open, sizeof(struct eicon_request));
254 				ENDDEBUG
255 
256 				/* confirm */
257 				IFDEBUG(D_CCONS);
258 					printf("CONFIRM 0x%x (data 0x%x =?= 0x%x) --> X25INTRQ\n",
259 						m, m->m_next, e_data(req));
260 				ENDDEBUG
261 				IF_ENQUEUE(&consintrq, m);
262 				IFDEBUG(D_CDUMP_REQ);
263 					dump_buf(req, sizeof(struct eicon_request));
264 				ENDDEBUG
265 			}
266 		} break;
267 
268 		case ECN_RESET:
269 		case ECN_CLEAR: {
270 			/*
271 			 *	ECN_RESET	->	ECN_RESET	(other side's reset indication)
272 			 *	ECN_CLEAR	->	ECN_CLEAR	(other side's close indication)
273 			 * TODO: MAY HAVE DATA PACKET!
274 			 * TODO: Have to be able to handle a 2nd CLEAR on on vc!
275 			 */
276 			freelun(req->e_vc);
277 			freelun((-req->e_vc)&0xff);
278 			req->e_vc = -req->e_vc; /* other side */
279 			req->e_reason = E_CO_PDNCLRESET;
280 			if (IF_QFULL(&consintrq)) {
281 				IF_DROP(&consintrq);
282 				printf("lpboutput: respose dropped\n");
283 				error = ENOBUFS;
284 			} else {
285 				IFDEBUG(D_CCONS);
286 					printf("CLOSE 0x%x --> X25INTRQ\n", m);
287 				ENDDEBUG
288 				IF_ENQUEUE(&consintrq, m);
289 				IFDEBUG(D_CDUMP_REQ);
290 					dump_buf(req, sizeof(struct eicon_request));
291 				ENDDEBUG
292 			}
293 		} break;
294 
295 		case ECN_SEND: {
296 			/*
297 			 *	ECN_SEND 	->	ECN_RECEIVE	(data send becomes data recvd)
298 			 */
299 			struct mbuf *m0;
300 			struct eicon_request *ack;
301 
302 			MGET(m0, M_DONTWAIT, MT_LPB_ACK); /* sets type, next, off */
303 			if (m0 == NULL) {
304 				printf("PANIC No mbufs for copy\n");
305 				error = ENOBUFS;
306 				break;
307 			}
308 			m0->m_len = sizeof(struct eicon_request);
309 
310 			ack = mtod(m0, struct eicon_request *);
311 			/* setup ack */
312 			ack->e_cmd = ECN_ACK;
313 			ack->e_vc = req->e_vc;
314 			req->e_vc = -req->e_vc;
315 			req->e_cmd = ECN_RECEIVE;
316 
317 			if (IF_QFULL(&consintrq)) {
318 				IF_DROP(&consintrq);
319 				printf("lpboutput: ADR_ACK DROPPED\n");
320 				m_freem(m0);
321 				error = ECONNABORTED;
322 			} else {
323 				IF_ENQUEUE(&consintrq, m);
324 				IFDEBUG(D_CCONS);
325 					printf("DATA 0x%x --> X25INTRQ\n", m);
326 				ENDDEBUG
327 				IFDEBUG(D_CDUMP_REQ);
328 					dump_buf(req, sizeof(struct eicon_request));
329 				ENDDEBUG
330 				IFDEBUG(D_CCONS);
331 					printf("ACK 0x%x --> X25INTRQ\n", m0);
332 				ENDDEBUG
333 				IF_ENQUEUE(&consintrq, m0);
334 				IFDEBUG(D_CDUMP_REQ);
335 					dump_buf(ack, sizeof(struct eicon_request));
336 				ENDDEBUG
337 			}
338 		} break;
339 
340 		default:
341 			printf("Bad loopback request 0x%x\n", req->e_cmd);
342 			error = EINVAL;
343 	}
344 
345 	if( error ) {
346 		m_freem(m);
347 	} else
348 		schednetisr(NETISR_X25);
349 
350 	splx(s);
351 	return error;
352 }
353 
354 #if NECN>0
355 	/* nothing */
356 #else
357 
358 /* KLUDGE: when no ecn board config-ed in, we need a routing
359  * ecnifp to return null.  We want to be able to configure with
360  * sw loopback only.
361  */
362 struct ifnet  *
363 ecnifp(unit)
364 int unit;
365 {
366 	return (struct ifnet *)NULL;
367 }
368 
369 int
370 ecnoutput(ifp, m)
371 	struct ifnet *ifp;
372 	struct mbuf *m;
373 {
374 	printf("ecnoutput: ecn not configured\n");
375 	(void) m_freem(m);
376 	return ENETDOWN;
377 
378 }
379 
380 ecnshutdown(ifp)
381 {
382 	printf("ecnshutdown: ecn not configured\n");
383 }
384 
385 ecnrestart(ifp)
386 {
387 	printf("ecnrestart: ecn not configured\n");
388 }
389 #endif NECN>0
390