xref: /csrg-svn/sys/vax/if/if_ddn.c (revision 24801)
1 /*	@(#)if_ddn.c	6.2 (Berkeley) 09/16/85 */
2 
3 
4 /************************************************************************\
5 
6      ________________________________________________________
7     /                                                        \
8    |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
9    |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
10    |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
11    |       AAAA AAAA      CCCC              CCCC              |
12    |      AAAA   AAAA     CCCC              CCCC              |
13    |     AAAA     AAAA    CCCC              CCCC              |
14    |    AAAA       AAAA   CCCC              CCCC              |
15    |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
16    |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
17    | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
18     \________________________________________________________/
19 
20 	Copyright (c) 1985 by Advanced Computer Communications
21 	720 Santa Barbara Street, Santa Barbara, California  93101
22 	(805) 963-9431
23 
24 	This software may be duplicated and used on systems
25 	which are licensed to run U.C. Berkeley versions of
26 	the UNIX operating system.  Any duplication of any
27 	part of this software must include a copy of ACC's
28 	copyright notice.
29 
30 
31 File:
32 		if_ddn.c
33 
34 Author:
35 		Art Berggreen
36 
37 Project:
38 		4.2 DDN X.25 network driver
39 
40 Function:
41 		This is a network device driver for BSD 4.2 UNIX which
42 		provides an interface between IP and ACC's ACP625
43 		(IF-11/X25) for connecting to the Defense Data Network.
44 
45 Components:
46 
47 Revision History:
48 		16-May-1985:	V1.0 - First release.
49 				Art Berggreen.
50 
51 \************************************************************************/
52 
53 
54 /*	if_ddn.c	 V1.0	5/16/85	*/
55 
56 /*
57  * ACC ACP625 DDN/X.25 Network device driver
58  */
59 
60 /* #define DDNDEBUG 1		/* Enable definition for Debug code */
61 
62 #include "ddn.h"
63 #if NDDN > 0
64 #include "../machine/pte.h"
65 
66 #include "param.h"
67 #include "systm.h"
68 #include "mbuf.h"
69 #include "buf.h"
70 #include "protosw.h"
71 #include "socket.h"
72 #include "vmmac.h"
73 #include "errno.h"
74 #include "time.h"
75 #include "kernel.h"
76 #include "ioctl.h"
77 
78 #include "../net/if.h"
79 #include "../net/netisr.h"
80 #include "../net/route.h"
81 
82 #ifdef	BBNNET
83 #define	INET
84 #endif
85 #ifdef	INET
86 #include "../netinet/in.h"
87 #include "../netinet/in_systm.h"
88 #include "../netinet/in_var.h"
89 #include "../netinet/ip.h"
90 #endif
91 
92 #include "../vax/cpu.h"
93 #include "../vax/mtpr.h"
94 #include "if_ddnreg.h"
95 #include "if_ddnvar.h"
96 #include "if_uba.h"
97 #include "../vaxuba/ubareg.h"
98 #include "../vaxuba/ubavar.h"
99 
100 
101 
102 /* declare global functions */
103 
104 int ddnprobe();
105 int ddnattach();
106 int ddnreset();
107 int ddninit();
108 int ddnoutput();
109 int ddntimer();
110 int ddnioctl();
111 int ddnintr();
112 
113 /* declare local functions */
114 
115 static void x25_init();
116 static struct ddn_cb *locate_x25_lcn();
117 static boolean convert_ip_addr();
118 static int convert_x25_addr();
119 static boolean make_x25_call();
120 static void ddn_start();
121 static void ddn_iorq();
122 static void start_chn();
123 static void ddn_data();
124 static void ddn_supr();
125 static void supr_msg();
126 static boolean decode_ring();
127 static void clear_lcn();
128 static void send_restart();
129 static void send_supr();
130 #ifdef DDNDEBUG
131 static void prt_addr();
132 static void prt_bytes();
133 #endif DDNDEBUG
134 
135 
136 struct	uba_device *ddninfo[NDDN];	/* ptrs to device info */
137 u_short	ddnstd[] = { 0766740, 0 };	/* standard addresses */
138 struct	uba_driver ddndriver =		/* device driver info */
139   {
140     ddnprobe,				/* device probe routine */
141     0,					/* slave probe routine */
142     ddnattach,				/* device attach routine */
143     0,					/* "dmago" routine */
144     ddnstd,				/* device address */
145     "ddn",				/* device name */
146     ddninfo				/* ptr to device info ptrs */
147   };
148 
149 static u_char init_msg[] =
150   {
151     LINE_CNTL,				/* set command code */
152     0x00,				/* not used */
153     0x00,				/* not used */
154     0x00,				/* extension length (set at runtime) */
155     LINK_DISABLE,			/* link disable */
156 /*    LINK_LOOPBACK,			/* loopback mode */
157 /*    LOOP_INTERNAL,			/*   = internal loopback */
158     PKT_SIZE,				/* packet size */
159     0x80,				/*   128 - LSB */
160     0x00,				/*   128 - MSB */
161     PKT_WINDOW,				/* packet window */
162     0x02,				/*   = 2 */
163     LINK_ENABLE				/* link enable */
164   };
165 
166 u_char cb_cmnd[4] =
167   {
168     CALL,
169     0,
170     0,
171     0
172   };
173 
174 u_char cb_called_addr[16] = {0};
175 
176 u_char cb_calling_addr[16] = {0};
177 
178 u_char cb_facilities[64] = {0};
179 
180 u_char cb_protocol[5] = {0};
181 
182 u_char cb_user_data[1] = {0};
183 
184 #ifdef DDNDEBUG
185 int ddn_debug = 1;		/* values 0-8 cause increasing verbosity */
186 #endif DDNDEBUG
187 
188 
189 /***********************************************************************\
190 *									*
191 *	Information for each device unit is maintained in an array	*
192 *	of structures named ddn_softc[].  The array is indexed by	*
193 *	unit number.  Each entry includes the network interface		*
194 *	structure (ddn_if) used by the routing code to locate the	*
195 *	interface,  an array of Logical	Channel control blocks which	*
196 *	maintain information about each of the Logical Channels (LCNs)	*
197 *	through which X.25 virtual calls are established, a queue of	*
198 *	I/O requests pending for the UMC, the UNIBUS interrupt vector	*
199 *	for the unit and misc flags.  The Logical Channel Control	*
200 *	blocks maintain information about the state of each LCN,	*
201 *	a queue of outbound data, Half Duplex Channel (HDX) blocks	*
202 *	used for queuing I/O requests to the UMC and an ifuba		*
203 *	structure which records the UNIBUS resources being held by	*
204 *	the LCN.							*
205 *									*
206 \***********************************************************************/
207 
208 struct sioq		/* Start I/O queue head */
209   {
210     struct hdx_chan	*sq_head;	/* queue head */
211     struct hdx_chan	*sq_tail;	/* queue tail */
212   };
213 
214 struct hdx_chan		/* HDX channel block */
215   {
216     struct hdx_chan	*hc_next;	/* link to next HDX channel */
217     u_char		hc_chan;	/* HDX channel number */
218     u_char		hc_adx;		/* address bits 17-16 */
219     u_short		hc_addr;	/* address bits 15-00 */
220     u_short		hc_cnt;		/* byte count */
221     u_char		hc_func;	/* I/O function */
222     u_char		hc_sbfc;	/* I/O subfunction */
223   };
224 
225 struct ddn_cb		/* Logical Channel control block */
226   {
227     struct in_addr	dc_inaddr;	/* remote Internet address */
228     u_char		dc_lcn;		/* LCN number */
229     u_char		dc_state;	/* LCN state */
230     u_short		dc_timer;	/* LCN timer */
231     struct ifqueue	dc_oq;		/* LCN output queue */
232     struct hdx_chan	dc_rchan;	/* LCN read HDX channel */
233     struct hdx_chan	dc_wchan;	/* LCN write HDX channel */
234     struct ifuba	dc_ifuba;	/* UNIBUS resources */
235     u_short		dc_flags;	/* misc flags */
236   };
237 
238 struct ddn_softc	/* device control structure */
239   {
240     struct ifnet	ddn_if;		/* network-visible interface */
241     struct ddn_cb	ddn_cb[NDDNCH+1]; /* Logical Channel cntl blks */
242     struct sioq		ddn_sioq;	/* start I/O queue */
243     int			ddn_vector;	/* UNIBUS interrupt vector */
244     u_short		ddn_flags;	/* misc flags */
245     struct in_addr	ddn_ipaddr;	/* local IP address */
246   } ddn_softc[NDDN];
247 
248 
249 /***********************************************************************\
250 *				ddnprobe()				*
251 *************************************************************************
252 *									*
253 *	This routine probes the device to obtain the UNIBUS interrupt	*
254 *	vector.  Since the UMC is a soft vector device, we obtain	*
255 *	an unused vector from the uba structure and return that.	*
256 *	The UMC is given the vector and the board is reset.		*
257 *	In order to save the vector in the device info structure, we	*
258 *	place it in a static temporary where the attach routine can	*
259 *	find it and save it in the device info structure.  This is	*
260 *	necessary because probe only provides a pointer to the device	*
261 *	and we have no idea which unit is being referenced.  This	*
262 *	works in 4.2 because the attach routine is called immediately	*
263 *	after a successful probe.					*
264 *									*
265 \***********************************************************************/
266 
267 #define INIT_DELAY	(100 * 2)	/* time for board initialization */
268 					/*   ( in 10 millisecond ticks) */
269 
270 static int savevec;			/* static variable for vector */
271 
272 ddnprobe(reg)
273 caddr_t reg;
274   {
275     register int br, cvec;		/* r11, r10 value-result */
276     register struct ddnregs *addr = (struct ddnregs *)reg;
277     register int delay_time;
278 
279 #ifdef lint
280     br = 0; cvec = br; br = cvec;
281 #endif
282 
283     cvec = savevec = (uba_hd[numuba].uh_lastiv -= 4);	/* return vector */
284     br = 0x15;				/* return bus level */
285 
286     addr->ioini = 0;			/* clear handshake flags */
287     addr->ionmi = 0;
288     addr->staack = 0;
289     addr->xfrgnt = 0;
290     addr->iovect = cvec >> 2;		/* pass vector to UMC */
291     addr->csr = DDN_RST;		/* reset the board */
292     delay_time = mfpr(TODR) + INIT_DELAY;
293     while(delay_time > mfpr(TODR)) /* wait */ ;
294 
295     return (sizeof(struct ddnregs));
296   }
297 
298 
299 /***********************************************************************\
300 *				ddnattach				*
301 *************************************************************************
302 *									*
303 *	This routine attaches the device to the network software.	*
304 *	The network interface structure is filled in.  The device	*
305 *	will be initialized when the system is ready to accept packets.	*
306 *									*
307 \***********************************************************************/
308 
309 ddnattach(ui)
310 struct uba_device *ui;
311   {
312     register struct ddn_softc *ds = &ddn_softc[ui->ui_unit];
313 
314     ds->ddn_vector = savevec;		/* save vector from probe() */
315     ds->ddn_if.if_unit = ui->ui_unit;	/* set unit number */
316     ds->ddn_if.if_name = "ddn";		/* set device name */
317     ds->ddn_if.if_mtu = DDNMTU;		/* set max msg size */
318     ds->ddn_if.if_init = ddninit;	/* set init routine addr */
319     ds->ddn_if.if_ioctl = ddnioctl;	/* set ioctl routine addr */
320     ds->ddn_if.if_output = ddnoutput;	/* set output routine addr */
321     ds->ddn_if.if_reset = ddnreset;	/* set reset routine addr */
322     ds->ddn_if.if_watchdog = ddntimer;	/* set timer routine addr */
323     if_attach(&ds->ddn_if);
324   }
325 
326 
327 /***********************************************************************\
328 *				ddnreset()				*
329 *************************************************************************
330 *									*
331 *	Reset of interface after UNIBUS reset.				*
332 *	If interface is on specified uba, reset its state.		*
333 *									*
334 \***********************************************************************/
335 
336 ddnreset(unit, uban)
337 int unit, uban;
338   {
339     register struct uba_device *ui;
340     register struct ddnregs *addr;
341     register int delay_time;
342 
343     if (unit >= NDDN || (ui = ddninfo[unit]) == 0 || ui->ui_alive == 0 ||
344       ui->ui_ubanum != uban)
345 	return;
346 
347     printf(" ddn%d", unit);
348 
349     addr = (struct ddnregs *)ui->ui_addr;
350     addr->ioini = 0;			/* clear handshake flags */
351     addr->ionmi = 0;
352     addr->staack = 0;
353     addr->xfrgnt = 0;
354     addr->iovect = ddn_softc[unit].ddn_vector >> 2;  /* pass vector to UMC */
355     addr->csr = DDN_RST;		/* reset the board */
356     delay_time = mfpr(TODR) + INIT_DELAY;
357     while(delay_time > mfpr(TODR)) /* wait */ ;
358 
359     ddninit(unit);
360   }
361 
362 
363 /***********************************************************************\
364 *				ddninit()				*
365 *************************************************************************
366 *									*
367 *	This routine initializes the interface for operation.  The	*
368 *	device control blocks are initialized, UNIBUS resources are	*
369 *	allocated and an X.25 initialization message is sent to the	*
370 *	UMC.								*
371 *									*
372 \***********************************************************************/
373 
374 ddninit(unit)
375 int unit;
376   {
377     register struct ddn_softc *ds = &ddn_softc[unit];
378     register struct ddn_cb *dc;
379     register struct uba_device *ui = ddninfo[unit];
380     int lcn, s;
381 
382 #ifdef DDNDEBUG
383 if (ddn_debug > 0)
384   {
385 printf("ddn%d: ddninit()\n", unit);
386   }
387 #endif DDNDEBUG
388 
389     if (ds->ddn_if.if_addrlist == 0)	/* if we have no internet addr */
390 	return;				/*   don't init yet */
391 
392     dc = ds->ddn_cb;			/* setup ptr to first LCN cntl block */
393 
394     for(lcn = 0; lcn <= NDDNCH; lcn++)	/* for all LCN's ... */
395       {
396     	dc->dc_lcn = lcn;		/* record LCN */
397     	dc->dc_inaddr.s_addr = 0;	/* clear remote internet addr */
398     	dc->dc_state = LC_DOWN;		/* init LCN state */
399     	dc->dc_timer = TMO_OFF;		/* turn LCN timer off */
400 
401 		/* init LCN output queue */
402 
403     	dc->dc_oq.ifq_head = (struct mbuf *)0;
404     	dc->dc_oq.ifq_tail = (struct mbuf *)0;
405     	dc->dc_oq.ifq_len = 0;
406     	dc->dc_oq.ifq_maxlen = DDN_OQMAX;
407     	dc->dc_oq.ifq_drops = 0;
408 
409     		/* init HDX channels */
410 
411     	dc->dc_rchan.hc_next = (struct hdx_chan *)0;
412     	dc->dc_rchan.hc_chan = lcn * 2;
413     	dc->dc_wchan.hc_next = (struct hdx_chan *)0;
414     	dc->dc_wchan.hc_chan = (lcn * 2) + 1;
415 
416     		/* init UNIBUS resources */
417 
418     	if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
419     	    0, (int)btoc(DDNMTU)) == 0)
420     	  {
421     	    printf("ddn%d: failed getting UBA resources for lcn %d\n",
422     		unit, lcn);
423     	    ds->ddn_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
424     	    return;
425     	  }
426 
427     	dc->dc_flags = 0;		/* initialize flags */
428 
429 	dc++;				/* point at next cntl blk */
430       }
431 
432     ds->ddn_sioq.sq_head = (struct hdx_chan *)0;
433     ds->ddn_sioq.sq_tail = (struct hdx_chan *)0;
434     ds->ddn_if.if_flags |= IFF_RUNNING;
435 
436     s = splimp();
437 
438     dc = ds->ddn_cb;			/* setup ptr to first LCN cntl block */
439 
440     for(lcn = 0; lcn <= NDDNCH; lcn++)	/* issue reads on all LCNs */
441       {
442     	ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
443 	dc++;
444       }
445 
446     x25_init(ds);			/* init the X.25 board */
447 
448     splx(s);
449 
450     ddntimer(unit);			/* start timers */
451   }
452 
453 
454 /***********************************************************************\
455 *				ddnoutput()				*
456 *************************************************************************
457 *									*
458 *	This routine is called by the network software when it has	*
459 *	an IP datagram to send out this interface.  An attempt is	*
460 *	made to find a LCN which has a virtual circuit open to the	*
461 *	indicated host.  If an LCN is found the packet is queued for	*
462 *	output on that LCN.						*
463 *									*
464 \***********************************************************************/
465 
466 ddnoutput(ifp, m0, dst)
467 struct ifnet *ifp;
468 struct mbuf *m0;
469 struct sockaddr_in *dst;
470   {
471     register struct mbuf *m = m0;
472     register struct ddn_softc *ds = &ddn_softc[ifp->if_unit];
473     register struct ddn_cb *dc;
474     register struct ifqueue *oq;
475     int s;
476 
477     if ((ds->ddn_if.if_flags & IFF_UP) == 0)
478 	return (ENETDOWN);
479 
480     switch (dst->sin_family)
481       {
482 
483 #ifdef INET
484     case AF_INET:
485 	break;
486 #endif INET
487 
488     default:
489 	printf("ddn%d: can't handle af%d\n", ifp->if_unit,
490 	    dst->sin_family);
491 	m_freem(m0);
492 	return (EAFNOSUPPORT);
493       }
494 
495 
496 #ifdef DDNDEBUG
497 if (ddn_debug > 6)
498   {
499 printf("ddnoutput(): dst = ");
500 prt_addr(dst->sin_addr.s_addr);
501 printf("\n");
502   }
503 #endif DDNDEBUG
504 
505     s = splimp();
506 
507     /* try to find an LCN */
508 
509     if (dc = locate_x25_lcn(ds, dst->sin_addr))
510       {						/* if found */
511 	oq = &(dc->dc_oq);			/*   point to output queue */
512 	dc->dc_state = LC_DATA_IDLE;
513 	dc->dc_timer = TMO_DATA_IDLE;
514 	if (IF_QFULL(oq))			/*   if q full */
515     	  {
516 	    IF_DROP(oq);			/*     drop the data */
517 	    m_freem(m);
518 	    splx(s);
519 	    return (ENOBUFS);
520 	  }
521 	IF_ENQUEUE(oq, m);			/*   otherwise queue it */
522 	ddn_start(ds, dc);			/*   and try to output */
523 	splx(s);
524 	return (0);
525       }
526     else					/* if no circuit available */
527       {
528     	IF_DROP(&ifp->if_snd);			/*   drop the data */
529     	m_freem(m);
530 	splx(s);
531 	return (EHOSTUNREACH);
532       }
533 
534   }
535 
536 
537 /***********************************************************************\
538 *				ddntimer()				*
539 *************************************************************************
540 *									*
541 *	This routine is entered once a second to perform timer		*
542 *	managment.  The LCN table is scanned for active timers,		*
543 *	(nonzero) which are decremented.  If a timer expires		*
544 *	(becomes zero), the proper action is taken.			*
545 *									*
546 \***********************************************************************/
547 
548 int ddntimer(unit)
549 int unit;
550   {
551     register struct ddn_softc *ds = &ddn_softc[unit];
552     register struct ddn_cb *dc;
553     register int s, lcn;
554 
555 #ifdef DDNDEBUG
556 if (ddn_debug > 7)
557   {
558 printf("ddntimer()\n");
559   }
560 #endif DDNDEBUG
561 
562     ds->ddn_if.if_timer = DDN_TIMEOUT;		/* restart timer */
563 
564     dc = ds->ddn_cb;
565 
566     s = splimp();
567 
568     for(lcn = 0; lcn <= NDDNCH; lcn++)		/* scan all LCN's */
569       {
570     	if (dc->dc_timer && (--(dc->dc_timer) == 0))
571     	  {					/* if a timer expired */
572     	    if (dc->dc_state == LC_RESTART)
573     	      {					/*   if a restart was out */
574     		send_restart(ds);		/*     send another one */
575     		break;
576     	      }
577     	    else				/*   otherwise */
578     	      {
579     		clear_lcn(ds, dc);		/*     clear the LCN */
580     	      }
581     	  }
582 	dc++;
583       }
584     splx(s);
585   }
586 
587 
588 /***********************************************************************\
589 *				ddnioctl()				*
590 *************************************************************************
591 *									*
592 *	This routine processes device dependent ioctl's.  Currently,	*
593 *	the only ioctl supported is used to set the host's internet	*
594 *	address for this network interface.				*
595 *									*
596 \***********************************************************************/
597 
598 ddnioctl(ifp, cmd, data)
599 	register struct ifnet *ifp;
600 	int cmd;
601 	caddr_t data;
602 {
603 	struct ifaddr *ifa = (struct ifaddr *) data;
604 	int s = splimp(), error = 0;
605 	struct endevice *enaddr;
606 
607 	switch (cmd) {
608 
609 	case SIOCSIFADDR:
610 		if (ifa->ifa_addr.sa_family != AF_INET)
611 			return(EINVAL);
612 		ifp->if_flags |= IFF_UP;
613 		if ((ifp->if_flags & IFF_RUNNING) == 0)
614 			ddninit(ifp->if_unit);
615 		ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr;
616 		break;
617 
618 	default:
619 		error = EINVAL;
620 		break;
621 	}
622 	splx(s);
623 	return (error);
624 }
625 
626 
627 /***********************************************************************\
628 *				ddnintr()				*
629 *************************************************************************
630 *									*
631 *	This is the interrupt handler for UNIBUS interrupts from the	*
632 *	UMC.  The interrupting HDX channel and interrupt type are	*
633 *	obtained from the completion comm regs.  If the interrupt is	*
634 *	an I/O request acknowledge, the next I/O request is passed	*
635 *	to the UMC.  If the interrupt is an I/O completion, the		*
636 *	completion is processed depending on whether it is for the	*
637 *	supervisor or a data channel.					*
638 *									*
639 \***********************************************************************/
640 
641 ddnintr(unit)
642 int unit;
643   {
644     register struct ddn_softc *ds = &ddn_softc[unit];
645     register struct hdx_chan *hc;
646     register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr;
647     int chan, type, cc, cnt;
648 
649     /*
650      * Check for hardware errors.
651      */
652     if (addr->csr & DDN_UER)
653       {
654 	printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS);
655 	addr->csr = 0;		/* disable i/f */
656     	return;
657       }
658 
659     /*
660      * Get logical channel info.
661      */
662     if ((chan = addr->stachn) >= ((NDDNCH+1)*2))
663       {
664     	printf("ddn%d: unknown channel, chan=%d\n", unit, chan);
665     	return;
666       }
667 
668     if (chan & 0x01)
669     	hc = &(ds->ddn_cb[chan/2].dc_wchan);
670     else
671     	hc = &(ds->ddn_cb[chan/2].dc_rchan);
672 
673     type = addr->statyp;
674     cc = addr->stacc;
675     cnt = hc->hc_cnt - addr->stacnt;
676 
677     /* Figure out what kind of interrupt it was */
678 
679     switch(type)
680       {
681     case DDNSACK:		/* start i/o accepted */
682     	if (hc != ds->ddn_sioq.sq_head)  /* does ack match waiting req? */
683     	  {
684     	    printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n",
685     		unit, chan, hc, ds->ddn_sioq.sq_head);
686     	    addr->csr = 0;		/* disable UMC */
687     	    return;
688     	  }
689 
690 	/* dequeue old request by copying link to queue head */
691 	/*   and start next I/O request if queue has not gone empty */
692 
693     	if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next)
694     	  {
695     	    start_chn(ds);
696     	  }
697     	break;
698 
699     case DDNDONE:		/* i/o completion */
700     	switch (cc)
701     	  {
702     	case DDNIOCABT:		/* probably VCN flush */
703 	    break;
704 
705     	case DDNIOCERR:
706     	    printf("ddn%d: program error ", unit);
707     	    goto daterr;
708 
709     	case DDNIOCOVR:
710     	    printf("ddn%d: overrun error ", unit);
711     	    goto daterr;
712 
713     	case DDNIOCUBE:
714     	    printf("ddn%d: NXM timeout or UB parity error ", unit);
715 
716     	daterr:
717     	    printf("chan=%d func=%x\n", chan, hc->hc_func);
718     	    if (hc->hc_func & DDNRDB)
719     		ds->ddn_if.if_ierrors++;
720     	    else
721     		ds->ddn_if.if_oerrors++;
722     	  }
723 
724     	/* was it supervisor or data traffic? */
725 
726     	if (chan > 1)
727     	    ddn_data(unit, chan, cc, cnt);
728     	else
729     	    ddn_supr(unit, chan, cc, cnt);
730 
731       }
732 
733     /*
734      * Ack the interrupt
735      */
736     addr->staack = 1;
737     if (!(addr->ionmi))
738       {
739     	addr->ionmi = 1;
740     	addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
741       }
742   }
743 
744 
745 /***********************************************************************\
746 *				x25_init()				*
747 *************************************************************************
748 *									*
749 *	This routine builds and sends an X.25 initialization msg	*
750 *	to the UMC.							*
751 *									*
752 \***********************************************************************/
753 
754 static void x25_init(ds)
755 struct ddn_softc *ds;
756   {
757     struct mbuf *m;
758     register u_char *bp;
759 
760 #ifdef DDNDEBUG
761 if (ddn_debug > 0)
762   {
763 printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit);
764   }
765 #endif DDNDEBUG
766 
767     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get X25 init buffer */
768     if (m == 0)
769       {
770     	printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit);
771     	return;
772       }
773 
774     init_msg[3] = sizeof(init_msg) - 4;	/* set cmnd ext length */
775 
776     bcopy(init_msg, mtod(m, u_char *), sizeof(init_msg));
777 
778     m->m_len = sizeof(init_msg);	/* set msg length */
779 
780     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
781     ddn_start(ds, &(ds->ddn_cb[0]));
782   }
783 
784 
785 /***********************************************************************\
786 *			locate_x25_lcn()				*
787 *************************************************************************
788 *									*
789 *	This routine tries to locate an X25 LCN associated with a	*
790 *	remote internet address.  A linear search of the LCN table	*
791 *	is made for a matching address.  If the search succeeds, the	*
792 *	LCN is returned.  If the search fails, the LCN table is		*
793 *	searched for an unused table entry.  If an unused table entry	*
794 *	is found, an X25 call is generated to the host specified in	*
795 *	the destination internet address.  If no LCN is available,	*
796 *	zero is returned.						*
797 *									*
798 \***********************************************************************/
799 
800 static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
801 struct ddn_softc *ds;
802 struct in_addr ip_addr;
803   {
804     register int lcn;
805     register struct ddn_cb *dc;
806     struct mbuf *m_callbfr;
807 
808 #ifdef DDNDEBUG
809 if (ddn_debug > 6)
810   {
811 printf("locate_x25_lcn()\n");
812   }
813 #endif DDNDEBUG
814 
815     dc = &(ds->ddn_cb[1]);
816     for(lcn = 1; lcn <= NDDNCH; lcn++)	/* scan LCN table for addr match */
817       {
818     	if (dc->dc_inaddr.s_addr == ip_addr.s_addr)	/* if found */
819     	    return(dc);		     			/*   return LCN */
820 	dc++;
821       }
822 
823     dc = &(ds->ddn_cb[1]);
824     for(lcn = 1; lcn <= NDDNCH; lcn++)	/* scan LCN table for free entry */
825       {
826     	if (dc->dc_state == LC_IDLE)
827     	    break;
828 	dc++;
829       }
830 
831     if (lcn > NDDNCH)			/* if we didn't find a free entry */
832         return(0);			/*   return empty handed */
833 
834 
835     if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc))
836       {					/*  addr can be converted */
837 	dc->dc_inaddr.s_addr = ip_addr.s_addr;
838     	return(dc);			/*   and return the LCN */
839       }
840     else
841       {
842 	return(0);				/* give up */
843       }
844   }
845 
846 
847 /***********************************************************************\
848 *			convert_ip_addr()				*
849 *************************************************************************
850 *									*
851 *	This routine accepts an internet address and attempts to	*
852 *	translate to an equivalent X25 address.  For DDN this follows	*
853 *	the guidelines in the DDN X25 interface spec.  The resultant	*
854 *	X25 address is stored in the X25 called addr buffer.  The	*
855 *	routine returns TRUE if successfull, FALSE otherwise.		*
856 *									*
857 *	NOTE: Although IF-11/X25 was designed to accept ASCII coded	*
858 *	digits for the address fields, we only supply the binary	*
859 *	values.  The front-end only uses the low four bits to extract	*
860 *	the binary value from the ASCII digits, so this works out.	*
861 *									*
862 \***********************************************************************/
863 
864 static boolean convert_ip_addr(ip_addr, x25addr)
865 struct in_addr ip_addr;
866 u_char x25addr[];
867   {
868     register int temp;
869     union {
870 	struct in_addr ip;
871 	struct {	 /*   (assumes Class A network number) */
872 	    u_char s_net;
873 	    u_char s_host;
874 	    u_char s_lh;
875 	    u_char s_impno;
876 	} imp;
877     } imp_addr;
878 
879     imp_addr.ip = ip_addr;
880     x25addr[0] = 14;		/* set addr length */
881 
882     x25addr[1] = 0;		/* clear DNIC */
883     x25addr[2] = 0;
884     x25addr[3] = 0;
885     x25addr[4] = 0;
886 
887     if (imp_addr.imp.s_host < 64)	/* Physical:  0000 0 IIIHH00 [SS] */
888       {					/*   s_impno -> III, s_host -> HH */
889     	x25addr[5] = 0;		/* set flag bit */
890     	x25addr[6] = imp_addr.imp.s_impno / 100;
891     	x25addr[7] = (imp_addr.imp.s_impno % 100) / 10;
892     	x25addr[8] = imp_addr.imp.s_impno % 10;
893     	x25addr[9] = imp_addr.imp.s_host / 10;
894     	x25addr[10] = imp_addr.imp.s_host % 10;
895       }
896     else			/* Logical:   0000 1 RRRRR00 [SS]	*/
897       {				/*   s_host * 256 + s_impno -> RRRRR	*/
898     	temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
899     	x25addr[5] = 1;
900     	x25addr[6] = temp / 10000;
901     	x25addr[7] = (temp % 10000) / 1000;
902     	x25addr[8] = (temp % 1000) / 100;
903     	x25addr[9] = (temp % 100) / 10;
904     	x25addr[10] = temp % 10;
905       }
906 
907     x25addr[11] = 0;		/* clear rest of addr */
908     x25addr[12] = 0;
909     x25addr[13] = 0;
910     x25addr[14] = 0;
911 
912 #ifdef DDNDEBUG
913 if (ddn_debug > 4)
914   {
915 printf("convert_ip_addr():  ");
916 prt_addr(ip_addr);
917 printf(" ==> ");
918 prt_bytes(x25addr, 14);
919 printf("\n");
920   }
921 #endif DDNDEBUG
922 
923     return(1);
924   }
925 
926 
927 /***********************************************************************\
928 *			convert_x25_addr()				*
929 *************************************************************************
930 *									*
931 *	This routine accepts an X25 address and attempts to translate	*
932 *	to an equivalent internet address.  For DDN this follows the	*
933 *	guidelines in the DDN X25 interface spec.  The resultant	*
934 *	internet address is returned to the caller.			*
935 *									*
936 \***********************************************************************/
937 
938 static int convert_x25_addr(x25addr)
939 u_char x25addr[];
940   {
941     register int cnt, temp;
942     union {
943 	struct in_addr ip;
944 	struct {	 /*   (assumes Class A network number) */
945 	    u_char s_net;
946 	    u_char s_host;
947 	    u_char s_lh;
948 	    u_char s_impno;
949 	} imp;
950     } imp_addr;
951 
952     if (((cnt = x25addr[0]) < 12) || (cnt > 14))
953       {
954     	printf("DDN: illegal X25 address length!\n");
955     	return(0);
956       }
957 
958     switch(x25addr[5] & 0x0f)
959       {
960     case 0:			/* Physical:  0000 0 IIIHH00 [SS]	*/
961 	imp_addr.imp.s_impno =
962 		((int)(x25addr[6] & 0x0f) * 100) +
963 		((int)(x25addr[7] & 0x0f) * 10)  +
964 		((int)(x25addr[8] & 0x0f));
965 
966 
967     	imp_addr.imp.s_host =
968     		((int)(x25addr[9] & 0x0f) * 10) +
969 		((int)(x25addr[10] & 0x0f));
970         break;
971     case 1:			/* Logical:   0000 1 RRRRR00 [SS]	*/
972     	temp =    ((int)(x25addr[6] & 0x0f) * 10000)
973 		+ ((int)(x25addr[7] & 0x0f) * 1000)
974 		+ ((int)(x25addr[8] & 0x0f) * 100)
975     		+ ((int)(x25addr[9] & 0x0f) * 10)
976 		+ ((int)(x25addr[10] & 0x0f));
977 
978     	imp_addr.imp.s_host = temp >> 8;
979     	imp_addr.imp.s_impno = temp & 0xff;
980     	break;
981     default:
982     	printf("DDN: illegal X25 address format!\n");
983     	return(0);
984       }
985 
986     imp_addr.imp.s_lh = 0;
987     imp_addr.imp.s_net = 0;
988 
989 #ifdef DDNDEBUG
990 if (ddn_debug > 4)
991   {
992 printf("convert_x25_addr():  ");
993 prt_bytes(&x25addr[1], cnt);
994 printf(" ==> ");
995 prt_addr(imp_addr.ip);
996 printf("\n");
997   }
998 #endif DDNDEBUG
999 
1000     return(imp_addr.ip.s_addr);
1001   }
1002 
1003 
1004 /***********************************************************************\
1005 *			make_x25_call()					*
1006 *************************************************************************
1007 *									*
1008 *	This routine places an X25 call using the X25 Call Msg		*
1009 *	buffer.  The calling LCN is placed in the appropriate state	*
1010 *	and a timer is started.						*
1011 *									*
1012 \***********************************************************************/
1013 
1014 static boolean make_x25_call(ds, dc)
1015 register struct ddn_softc *ds;
1016 register struct ddn_cb *dc;
1017   {
1018     register struct mbuf *m_callbfr;
1019     register u_char *cb;
1020 
1021     MGET(m_callbfr, M_DONTWAIT, MT_DATA);  /* try to get call cmnd buffer */
1022     if (m_callbfr == 0)
1023 	return(0);
1024 
1025     cb = mtod(m_callbfr, u_char *);
1026 
1027     convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
1028 
1029     cb_protocol[0] = 4;
1030     cb_protocol[1] = X25_PROTO_IP;	/* protocol = IP */
1031     cb_protocol[2] = 0;
1032     cb_protocol[3] = 0;
1033     cb_protocol[4] = 0;
1034 
1035     cb_facilities[0] = 4;		/* number facility bytes */
1036     cb_facilities[1] = 0;		/*  options marker */
1037     cb_facilities[2] = 0;
1038     cb_facilities[3] = X25_FACIL_DDN;	/*  DDN standard mode */
1039     cb_facilities[4] = FAC_DDNSTD;
1040 
1041     cb_user_data[0] = 0;		/* no user data */
1042 
1043     cb_cmnd[0] = CALL;			/* set command code */
1044     cb_cmnd[1] = dc->dc_lcn << 1;	/* set channel id */
1045     cb_cmnd[2] = 0;
1046     cb_cmnd[3] = (cb_called_addr[0] + 1) +	/* tally up cmnd ext length */
1047 		 (cb_calling_addr[0] + 1) +
1048 		 (cb_protocol[0] + 1) +
1049 		 (cb_facilities[0] + 1) +
1050 		 (cb_user_data[0] + 1);
1051 
1052     m_callbfr->m_len = cb_cmnd[3] + 4;
1053 
1054     /* copy command header */
1055     bcopy(cb_cmnd, cb, 4);
1056     cb += 4;
1057 
1058     /* copy called address */
1059     bcopy(cb_called_addr, cb, cb_called_addr[0] + 1);
1060     cb += (cb_called_addr[0] + 1);
1061 
1062     /* copy calling address */
1063     bcopy(cb_calling_addr, cb, cb_calling_addr[0] + 1);
1064     cb += (cb_calling_addr[0] + 1);
1065 
1066     /* copy protocol */
1067     bcopy(cb_protocol, cb, cb_protocol[0] + 1);
1068     cb += (cb_protocol[0] + 1);
1069 
1070     /* copy facilities */
1071     bcopy(cb_facilities, cb, cb_facilities[0] + 1);
1072     cb += (cb_facilities[0] + 1);
1073 
1074     /* copy user data */
1075     bcopy(cb_user_data, cb, cb_user_data[0] + 1);
1076     cb += (cb_user_data[0] + 1);
1077 
1078     dc->dc_state = LC_CALL_PENDING;		/* set state */
1079     dc->dc_timer = TMO_CALL_PENDING;		/* start call timeout */
1080 
1081 #ifdef DDNDEBUG
1082 if (ddn_debug > 3)
1083   {
1084 printf("make_x25_call(): call_bfr = ");
1085 prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
1086 printf("\n");
1087   }
1088 #endif DDNDEBUG
1089 
1090     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr);
1091     ddn_start(ds, &(ds->ddn_cb[0]));
1092 
1093     return(1);
1094   }
1095 
1096 
1097 /***********************************************************************\
1098 *				ddn_start()				*
1099 *************************************************************************
1100 *									*
1101 *	This routine attempts to start output of data queued on	a	*
1102 *	specific LCN.  If the LCN was not already busy and data is	*
1103 *	available for output, the data is copied into the LCN's I/O	*
1104 *	buffer and an I/O request queued to the UMC.			*
1105 *									*
1106 \***********************************************************************/
1107 
1108 static void ddn_start(ds, dc)
1109 register struct ddn_softc *ds;
1110 register struct ddn_cb *dc;
1111   {
1112     register struct mbuf *m;
1113     int len;
1114 
1115     /*
1116      * If output isn't active, attempt to
1117      * start sending a new packet.
1118      */
1119 
1120     if ((dc->dc_flags & DC_OBUSY) ||
1121     	(dc->dc_oq.ifq_len == 0) ||
1122     	((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE)))
1123       {
1124     	return;
1125       }
1126 
1127     IF_DEQUEUE(&dc->dc_oq, m);
1128 
1129     len = if_wubaput(&dc->dc_ifuba, m);	/* copy data to mapped mem */
1130     dc->dc_flags |= DC_OBUSY;
1131 
1132     ddn_iorq(ds, dc, len, DDNWRT+DDNEOS);
1133   }
1134 
1135 
1136 /***********************************************************************\
1137 *				ddn_iorq()				*
1138 *************************************************************************
1139 *									*
1140 *	This routine builds UMC I/O requests and queues them for	*
1141 *	delivery to the UMC. If the UMC I/O request comm regs are	*
1142 *	not busy, the I/O request is passed to the UMC.			*
1143 *									*
1144 \***********************************************************************/
1145 
1146 static void ddn_iorq(ds, dc, len, func)
1147 struct ddn_softc *ds;
1148 struct ddn_cb *dc;
1149 int len, func;
1150   {
1151     register struct hdx_chan *hc;
1152     register int info;
1153 
1154 
1155     /* get appropriate UNIBUS mapping info */
1156 
1157     if (func & DDNRDB)		/* read or write? */
1158       {
1159     	hc = &dc->dc_rchan;
1160     	info = dc->dc_ifuba.ifu_r.ifrw_info;
1161       }
1162     else
1163       {
1164     	hc = &dc->dc_wchan;
1165     	info = dc->dc_ifuba.ifu_w.ifrw_info;
1166       }
1167 
1168     /* set channel info */
1169 
1170     hc->hc_adx = (u_char)((info & 0x30000) >> 12);
1171     hc->hc_addr = (u_short)(info & 0xffff);
1172     hc->hc_cnt = len;
1173     hc->hc_func = (u_char)func;
1174     hc->hc_sbfc = 0;
1175 
1176     /*
1177      * If UMC comm regs busy, queue start i/o for later.
1178      */
1179     if (ds->ddn_sioq.sq_head)
1180       {
1181     	(ds->ddn_sioq.sq_tail)->hc_next = hc;
1182     	ds->ddn_sioq.sq_tail = hc;
1183     	hc->hc_next = 0;
1184     	return;
1185       }
1186 
1187     /* start i/o on channel now */
1188 
1189     ds->ddn_sioq.sq_head = hc;
1190     ds->ddn_sioq.sq_tail = hc;
1191     hc->hc_next = 0;
1192     start_chn(ds);
1193   }
1194 
1195 
1196 /***********************************************************************\
1197 *				start_chn()				*
1198 *************************************************************************
1199 *									*
1200 *	This routine copies UMC I/O requests into the UMC comm regs	*
1201 *	and notifies the UMC.						*
1202 *									*
1203 \***********************************************************************/
1204 
1205 static void start_chn(ds)
1206 struct ddn_softc *ds;
1207   {
1208     register struct hdx_chan *hc = ds->ddn_sioq.sq_head;
1209     register struct ddnregs *addr =
1210     	(struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr;
1211 
1212     /*
1213      * Set up comm regs.
1214      */
1215     addr->iochn = hc->hc_chan;
1216     addr->ioadx = hc->hc_adx;
1217     addr->ioadl = hc->hc_addr;
1218     addr->iocnt = hc->hc_cnt;
1219     addr->iofcn = hc->hc_func;
1220     addr->iosbf = hc->hc_sbfc;
1221     addr->ioini = 1;
1222 
1223     /* signal UMC if necessary */
1224 
1225     if (!(addr->ionmi))
1226       {
1227     	addr->ionmi = 1;
1228     	addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
1229       }
1230   }
1231 
1232 
1233 /***********************************************************************\
1234 *				ddn_data()				*
1235 *************************************************************************
1236 *									*
1237 *	This routine is called when a data channel I/O completes.	*
1238 *	If the completion was for a write, an attempt is made to	*
1239 *	start output on the next packet waiting for output on that	*
1240 *	LCN.  If the completion was for a read, the received packet	*
1241 *	is sent to the IP input queue (if no error) and another read	*
1242 *	is started on the LCN.						*
1243 *									*
1244 \***********************************************************************/
1245 
1246 static void ddn_data(unit, chan, cc, rcnt)
1247 int unit, chan, cc, rcnt;
1248 {
1249     register struct ddn_softc *ds = &ddn_softc[unit];
1250     register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]);
1251     register struct ifqueue *inq = &ipintrq;
1252     register struct mbuf *m;
1253 
1254     if (chan & 0x01)			/* was it read or write? */
1255       {					/*   write, fire up next output */
1256     	ds->ddn_if.if_opackets++;
1257     	dc->dc_flags &= ~DC_OBUSY;
1258     	ddn_start(ds, dc);
1259       }
1260     else				/*   read, process rcvd packet */
1261       {
1262     	if (cc == DDNIOCOK)
1263     	  {				/* Queue good packet for input */
1264     	    ds->ddn_if.if_ipackets++;
1265 	    dc->dc_state = LC_DATA_IDLE;
1266 	    dc->dc_timer = TMO_DATA_IDLE;
1267     	    m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
1268     	    if (m)
1269     	      {
1270     		if (IF_QFULL(inq))
1271     		  {
1272     		    IF_DROP(inq);
1273     		    m_freem(m);
1274     		  }
1275     		else
1276     		  {
1277     		    IF_ENQUEUE(inq, m);
1278     		    schednetisr(NETISR_IP);
1279     		  }
1280     	      }
1281     	  }
1282 
1283     	/* hang a new data read */
1284 
1285     	ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
1286 
1287       }
1288   }
1289 
1290 
1291 /***********************************************************************\
1292 *				ddn_supr()				*
1293 *************************************************************************
1294 *									*
1295 *	This routine is called when a supervisor I/O completes.		*
1296 *	If the completion was for a write, an attempt is made to	*
1297 *	start output on the next supervisor command waiting for		*
1298 *	output.  If the completion was for a read, the received		*
1299 *	supervisor message is processed and another read is started.	*
1300 *									*
1301 \***********************************************************************/
1302 
1303 static void ddn_supr(unit, chan, cc, rcnt)
1304 int unit, chan, cc, rcnt;
1305 {
1306     register struct ddn_softc *ds = &ddn_softc[unit];
1307     u_char *p;
1308 
1309     /* was it read or write? */
1310 
1311     if (chan & 0x01)
1312       {
1313     	ds->ddn_cb[0].dc_flags &= ~DC_OBUSY;
1314     	ddn_start(ds, &(ds->ddn_cb[0]));
1315       }
1316     else
1317       {
1318     	if (cc == DDNIOCOK)
1319     	  {
1320     	    p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr);
1321 
1322     	    /* process supervisor message */
1323 
1324     	    supr_msg(ds, p);
1325 
1326     	  }
1327 
1328     	/* hang a new supr read */
1329 
1330     	ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR);
1331       }
1332   }
1333 
1334 
1335 /***********************************************************************\
1336 *				supr_msg()				*
1337 *************************************************************************
1338 *									*
1339 *	This routine processes received supervisor messages.		*
1340 *	Depending on the message type, the appropriate action is	*
1341 *	taken.
1342 *									*
1343 \***********************************************************************/
1344 
1345 static void supr_msg(ds, p)
1346 struct ddn_softc *ds;
1347 u_char p[];
1348   {
1349     register struct ddn_cb *dc;
1350     register int lcn;
1351     register struct mbuf *m;
1352 
1353 #ifdef DDNDEBUG
1354 if (ddn_debug > 5)
1355   {
1356 printf("supr_msg():  ");
1357 prt_bytes(p, 4+p[3]);
1358 printf("\n");
1359   }
1360 #endif DDNDEBUG
1361 
1362     switch (p[0])
1363       {
1364     case LINE_STATUS:			/*   link status msg */
1365 	if (p[2] == LINK_UP)		/*   if link came up */
1366 	  {
1367     	    send_restart(ds);		/*     send restart msg */
1368 	  }
1369 	else				/*   if link went down */
1370 	  {
1371     	    ds->ddn_if.if_flags &= ~IFF_UP;
1372     	    dc = ds->ddn_cb;
1373     	    for(lcn = 0; lcn <= NDDNCH; lcn++) /*    for all LCN's */
1374     	      {
1375     		dc->dc_state = LC_DOWN;  /* set state */
1376     		dc->dc_timer = TMO_OFF;  /* stop timer */
1377 		dc++;
1378     	      }
1379 	  }
1380     	break;
1381 
1382     case RESTART:			/* restart received */
1383     	if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */
1384     	    send_supr(ds, RSTRT_ACK, 0, 0);    /*   send restart ack */
1385 	/* fall thru */
1386     case RSTRT_ACK:			/* restart ack */
1387     	ds->ddn_if.if_flags |= IFF_UP;
1388     	dc = ds->ddn_cb;
1389     	for(lcn = 0; lcn <= NDDNCH; lcn++)	/* for all LCN's */
1390     	  {
1391     	    dc->dc_state = LC_IDLE;   /* set state */
1392     	    dc->dc_timer = TMO_OFF;   /* stop timer */
1393     	    dc->dc_inaddr.s_addr = 0; /* forget address */
1394     	    while (dc->dc_oq.ifq_len) /* drop pending data */
1395     	      {
1396     		IF_DEQUEUE(&dc->dc_oq, m);
1397     		m_freem(m);
1398     	      }
1399 	    dc++;
1400     	  }
1401     	break;
1402 
1403     case ANSWER:			/* call answered */
1404     	lcn = p[1] / 2;
1405     	dc = &(ds->ddn_cb[lcn]);
1406     	if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */
1407     	  {
1408     	    dc->dc_state = LC_DATA_IDLE;  /* set state */
1409     	    dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1410     	    ddn_start(ds, dc);		  /* try to send data */
1411     	  }
1412     	break;
1413 
1414     case RING:				/* incoming call */
1415     	for(lcn = NDDNCH; lcn > 0; lcn--)	/* search LCN's */
1416     	  {
1417     	    if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */
1418     	    	break;
1419     	  }
1420 
1421     	if (lcn && decode_ring(p))	/* if a free LCN found */
1422 					/*   and ring looks ok */
1423     	  {
1424     	    dc = &(ds->ddn_cb[lcn]);
1425     	    dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr);
1426     	    dc->dc_state = LC_DATA_IDLE;  /* set state */
1427     	    dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1428     	    send_supr(ds, ANSWER, lcn * 2, p[2]); /* send answer */
1429     	  }
1430     	else				/* if no free LCN's */
1431     	  {
1432     	    send_supr(ds, CLEARVC, p[2], 0); /* clear call */
1433     	  }
1434     	break;
1435 
1436     case CLEARLC:			/* clear by LCN */
1437     	lcn = p[1] / 2;			/* get LCN */
1438     	dc = &(ds->ddn_cb[lcn]);
1439     	if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */
1440     	  {
1441     	    send_supr(ds, CLEARLC, p[1], 0);      /*   ack the clear */
1442     	  }
1443     	dc->dc_state = LC_IDLE; /* set state */
1444     	dc->dc_timer = TMO_OFF; /* stop timer */
1445     	dc->dc_inaddr.s_addr = 0; /* forget address */
1446     	while (dc->dc_oq.ifq_len) /* drop pending data */
1447     	  {
1448     	    IF_DEQUEUE(&dc->dc_oq, m);
1449     	    m_freem(m);
1450     	  }
1451     	break;
1452 
1453     case CLEARVC:			/* clear by VCN */
1454     	send_supr(ds, CLEARVC, p[1], 0); /* send clear ack */
1455     	break;
1456 
1457     case RESET:				/* X25 reset */
1458 	send_supr(ds, RESET_ACK, p[1], 0); /* send reset ack */
1459     	printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */
1460 	break;
1461 
1462     case INTERRUPT:			/* X25 interrupt */
1463     	printf("X25 INTERRUPT on lcn = %d, code = %d\n",	/* log it */
1464     	    p[1] / 2, p[2]);
1465 	break;
1466 
1467     default:
1468     	printf("ddn%d: supervisor error, code=%x\n",
1469 	   ds->ddn_if.if_unit, p[0]);
1470       }
1471   }
1472 
1473 
1474 /***********************************************************************\
1475 *				decode_ring()				*
1476 *************************************************************************
1477 *									*
1478 *	This routine parses and validates the incoming call msg.	*
1479 *									*
1480 \***********************************************************************/
1481 
1482 static boolean decode_ring(p)
1483 register u_char *p;
1484   {
1485     register int cnt;
1486 
1487 #ifdef DDNDEBUG
1488 if (ddn_debug > 3)
1489   {
1490 printf("decode_ring()\n");
1491   }
1492 #endif DDNDEBUG
1493 
1494 
1495     p += 3;			/* skip to cmnd ext length */
1496     if (*p++ < 5)		/* is count appropriate */
1497 	return(0);		/*   return false if not */
1498 
1499     /* called address */
1500     if ((cnt = *p + 1) > 16)	/* is called addr len legal? */
1501 	return(0);		/*   return false if not */
1502     bcopy(p, cb_called_addr, cnt); /* copy field */
1503     p += cnt;
1504 
1505     /* calling address */
1506     if ((cnt = *p + 1) > 16)	/* is calling addr len legal? */
1507 	return(0);		/*   return false if not */
1508     bcopy(p, cb_calling_addr, cnt); /* copy field */
1509     p += cnt;
1510 
1511     /* protocol part of user data */
1512     if ((cnt = *p + 1) > 5)	/* is protocol len legal? */
1513 	return(0);		/*   return false if not */
1514     bcopy(p, cb_protocol, cnt); /* copy field */
1515     p += cnt;
1516 
1517     /* facilities */
1518     if ((cnt = *p + 1) > 64)	/* is facilities len legal? */
1519 	return(0);		/*   return false if not */
1520     bcopy(p, cb_facilities, cnt); /* copy field */
1521     p += cnt;
1522 
1523     /* ignore rest of user data for now */
1524 
1525     if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP))
1526 	return(0);		/* bad if not IP */
1527 
1528     return(1);			/* looks ok */
1529   }
1530 
1531 
1532 /***********************************************************************\
1533 *				clear_lcn()				*
1534 *************************************************************************
1535 *									*
1536 *	This routine clears an X25 circuit and releases any buffers	*
1537 *	queued for transmission.					*
1538 *									*
1539 \***********************************************************************/
1540 
1541 static void clear_lcn(ds, dc)
1542 struct ddn_softc *ds;
1543 struct ddn_cb *dc;
1544   {
1545     register struct mbuf *m;
1546 
1547 #ifdef DDNDEBUG
1548 if (ddn_debug > 3)
1549   {
1550 printf("clear_lcn(%d)\n", dc->dc_lcn);
1551   }
1552 #endif DDNDEBUG
1553 
1554     dc->dc_state = LC_CLR_PENDING;  /* set state */
1555     dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
1556     dc->dc_inaddr.s_addr = 0;	    /* clear associated address */
1557     while (dc->dc_oq.ifq_len)	    /* drop any pending data */
1558       {
1559     	IF_DEQUEUE(&dc->dc_oq, m);
1560     	m_freem(m);
1561       }
1562     send_supr(ds, CLEARLC, dc->dc_lcn * 2, 0);    /* send clear msg */
1563   }
1564 
1565 
1566 /***********************************************************************\
1567 *				send_restart()				*
1568 *************************************************************************
1569 *									*
1570 *	This routine marks all LCNs as being in a restarting state	*
1571 *	and sends a restart command to X25.				*
1572 *									*
1573 \***********************************************************************/
1574 
1575 static void send_restart(ds)
1576 struct ddn_softc *ds;
1577   {
1578     register struct ddn_cb *dc;
1579     register int lcn;
1580     struct mbuf *m;
1581 
1582 #ifdef DDNDEBUG
1583 if (ddn_debug > 1)
1584   {
1585 printf("send_restart()\n");
1586   }
1587 #endif DDNDEBUG
1588     dc = ds->ddn_cb;
1589     for(lcn = 0; lcn <= NDDNCH; lcn++)	    /* for all LCN's */
1590       {
1591     	dc->dc_state = LC_RESTART;  /* set state */
1592     	dc->dc_timer = TMO_RESTART; /* start restart timeout */
1593     	dc->dc_inaddr.s_addr = 0;     /* forget address */
1594     	while (dc->dc_oq.ifq_len)	/* drop any pending data */
1595     	  {
1596     	    IF_DEQUEUE(&dc->dc_oq, m);
1597     	    m_freem(m);
1598     	  }
1599 	dc++;
1600       }
1601 
1602     send_supr(ds, RESTART, 0, 0);	    /* send restart msg */
1603   }
1604 
1605 
1606 /***********************************************************************\
1607 *				send_supr()				*
1608 *************************************************************************
1609 *									*
1610 *	This routine is used to send short (4 bytes only) supervisor	*
1611 *	commands.							*
1612 *									*
1613 \***********************************************************************/
1614 
1615 static void send_supr(ds, cmd, p1, p2)
1616 struct ddn_softc *ds;
1617 int cmd, p1, p2;
1618   {
1619     struct mbuf *m;
1620     register u_char *cp;
1621 
1622 #ifdef DDNDEBUG
1623 if (ddn_debug > 6)
1624   {
1625 printf("send_supr():  %x %x %x\n", cmd, p1, p2);
1626   }
1627 #endif DDNDEBUG
1628 
1629     MGET(m, M_DONTWAIT, MT_DATA);
1630 
1631     if (m == 0)
1632       {
1633     	printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit);
1634     	return;
1635       }
1636 
1637     cp = mtod(m, u_char *);
1638 
1639     /* build supervisor message */
1640 
1641     *cp++ = (byte)cmd;
1642     *cp++ = (byte)p1;
1643     *cp++ = (byte)p2;
1644     *cp++ = 0;
1645 
1646     m->m_len = 4;
1647 
1648     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
1649     ddn_start(ds, &(ds->ddn_cb[0]));
1650 
1651   }
1652 
1653 
1654 #ifdef DDNDEBUG
1655 
1656 /***********************************************************************\
1657 *				prt_addr()				*
1658 *************************************************************************
1659 *									*
1660 *	This routine is used to print internet addresses in the		*
1661 *	standard A.B.C.D format.					*
1662 *									*
1663 \***********************************************************************/
1664 
1665 static void prt_addr(addr)
1666 struct in_addr addr;
1667   {
1668     printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
1669   }
1670 
1671 /***********************************************************************\
1672 *				prt_bytes()				*
1673 *************************************************************************
1674 *									*
1675 *	This routine is used to print a string of bytes in hex.		*
1676 *									*
1677 \***********************************************************************/
1678 
1679 static void prt_bytes(bp, cnt)
1680 u_char *bp;
1681 int cnt;
1682   {
1683     while(cnt--)
1684       {
1685 	printf(" %x", *bp++ & 0xff);
1686       }
1687   }
1688 
1689 #endif DDNDEBUG
1690 
1691 #endif NDDN
1692