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