xref: /original-bsd/sys/vax/if/if_ddn.c (revision 1a56dd2c)
1 /*	@(#)if_ddn.c	7.1 (Berkeley) 06/05/86 */
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; ddnintr(0);
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 
603 	switch (cmd) {
604 
605 	case SIOCSIFADDR:
606 		if (ifa->ifa_addr.sa_family != AF_INET)
607 			return(EINVAL);
608 		ifp->if_flags |= IFF_UP;
609 		if ((ifp->if_flags & IFF_RUNNING) == 0)
610 			ddninit(ifp->if_unit);
611 		ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr;
612 		break;
613 
614 	default:
615 		error = EINVAL;
616 		break;
617 	}
618 	splx(s);
619 	return (error);
620 }
621 
622 
623 /***********************************************************************\
624 *				ddnintr()				*
625 *************************************************************************
626 *									*
627 *	This is the interrupt handler for UNIBUS interrupts from the	*
628 *	UMC.  The interrupting HDX channel and interrupt type are	*
629 *	obtained from the completion comm regs.  If the interrupt is	*
630 *	an I/O request acknowledge, the next I/O request is passed	*
631 *	to the UMC.  If the interrupt is an I/O completion, the		*
632 *	completion is processed depending on whether it is for the	*
633 *	supervisor or a data channel.					*
634 *									*
635 \***********************************************************************/
636 
637 ddnintr(unit)
638 int unit;
639   {
640     register struct ddn_softc *ds = &ddn_softc[unit];
641     register struct hdx_chan *hc;
642     register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr;
643     int chan, type, cc, cnt;
644 
645     /*
646      * Check for hardware errors.
647      */
648     if (addr->csr & DDN_UER)
649       {
650 	printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS);
651 	addr->csr = 0;		/* disable i/f */
652     	return;
653       }
654 
655     /*
656      * Get logical channel info.
657      */
658     if ((chan = addr->stachn) >= ((NDDNCH+1)*2))
659       {
660     	printf("ddn%d: unknown channel, chan=%d\n", unit, chan);
661     	return;
662       }
663 
664     if (chan & 0x01)
665     	hc = &(ds->ddn_cb[chan/2].dc_wchan);
666     else
667     	hc = &(ds->ddn_cb[chan/2].dc_rchan);
668 
669     type = addr->statyp;
670     cc = addr->stacc;
671     cnt = hc->hc_cnt - addr->stacnt;
672 
673     /* Figure out what kind of interrupt it was */
674 
675     switch(type)
676       {
677     case DDNSACK:		/* start i/o accepted */
678     	if (hc != ds->ddn_sioq.sq_head)  /* does ack match waiting req? */
679     	  {
680     	    printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n",
681     		unit, chan, hc, ds->ddn_sioq.sq_head);
682     	    addr->csr = 0;		/* disable UMC */
683     	    return;
684     	  }
685 
686 	/* dequeue old request by copying link to queue head */
687 	/*   and start next I/O request if queue has not gone empty */
688 
689     	if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next)
690     	  {
691     	    start_chn(ds);
692     	  }
693     	break;
694 
695     case DDNDONE:		/* i/o completion */
696     	switch (cc)
697     	  {
698     	case DDNIOCABT:		/* probably VCN flush */
699 	    break;
700 
701     	case DDNIOCERR:
702     	    printf("ddn%d: program error ", unit);
703     	    goto daterr;
704 
705     	case DDNIOCOVR:
706     	    printf("ddn%d: overrun error ", unit);
707     	    goto daterr;
708 
709     	case DDNIOCUBE:
710     	    printf("ddn%d: NXM timeout or UB parity error ", unit);
711 
712     	daterr:
713     	    printf("chan=%d func=%x\n", chan, hc->hc_func);
714     	    if (hc->hc_func & DDNRDB)
715     		ds->ddn_if.if_ierrors++;
716     	    else
717     		ds->ddn_if.if_oerrors++;
718     	  }
719 
720     	/* was it supervisor or data traffic? */
721 
722     	if (chan > 1)
723     	    ddn_data(unit, chan, cc, cnt);
724     	else
725     	    ddn_supr(unit, chan, cc);
726 
727       }
728 
729     /*
730      * Ack the interrupt
731      */
732     addr->staack = 1;
733     if (!(addr->ionmi))
734       {
735     	addr->ionmi = 1;
736     	addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
737       }
738   }
739 
740 
741 /***********************************************************************\
742 *				x25_init()				*
743 *************************************************************************
744 *									*
745 *	This routine builds and sends an X.25 initialization msg	*
746 *	to the UMC.							*
747 *									*
748 \***********************************************************************/
749 
750 static void x25_init(ds)
751 struct ddn_softc *ds;
752   {
753     struct mbuf *m;
754 
755 #ifdef DDNDEBUG
756 if (ddn_debug > 0)
757   {
758 printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit);
759   }
760 #endif DDNDEBUG
761 
762     MGET(m, M_DONTWAIT, MT_DATA);	/* try to get X25 init buffer */
763     if (m == 0)
764       {
765     	printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit);
766     	return;
767       }
768 
769     init_msg[3] = sizeof(init_msg) - 4;	/* set cmnd ext length */
770 
771     bcopy((caddr_t)init_msg, mtod(m, caddr_t), sizeof(init_msg));
772 
773     m->m_len = sizeof(init_msg);	/* set msg length */
774 
775     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
776     ddn_start(ds, &(ds->ddn_cb[0]));
777   }
778 
779 
780 /***********************************************************************\
781 *			locate_x25_lcn()				*
782 *************************************************************************
783 *									*
784 *	This routine tries to locate an X25 LCN associated with a	*
785 *	remote internet address.  A linear search of the LCN table	*
786 *	is made for a matching address.  If the search succeeds, the	*
787 *	LCN is returned.  If the search fails, the LCN table is		*
788 *	searched for an unused table entry.  If an unused table entry	*
789 *	is found, an X25 call is generated to the host specified in	*
790 *	the destination internet address.  If no LCN is available,	*
791 *	zero is returned.						*
792 *									*
793 \***********************************************************************/
794 
795 static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
796 struct ddn_softc *ds;
797 struct in_addr ip_addr;
798   {
799     register int lcn;
800     register struct ddn_cb *dc;
801 
802 #ifdef DDNDEBUG
803 if (ddn_debug > 6)
804   {
805 printf("locate_x25_lcn()\n");
806   }
807 #endif DDNDEBUG
808 
809     dc = &(ds->ddn_cb[1]);
810     for(lcn = 1; lcn <= NDDNCH; lcn++)	/* scan LCN table for addr match */
811       {
812     	if (dc->dc_inaddr.s_addr == ip_addr.s_addr)	/* if found */
813     	    return(dc);		     			/*   return LCN */
814 	dc++;
815       }
816 
817     dc = &(ds->ddn_cb[1]);
818     for(lcn = 1; lcn <= NDDNCH; lcn++)	/* scan LCN table for free entry */
819       {
820     	if (dc->dc_state == LC_IDLE)
821     	    break;
822 	dc++;
823       }
824 
825     if (lcn > NDDNCH)			/* if we didn't find a free entry */
826         return(0);			/*   return empty handed */
827 
828 
829     if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc))
830       {					/*  addr can be converted */
831 	dc->dc_inaddr.s_addr = ip_addr.s_addr;
832     	return(dc);			/*   and return the LCN */
833       }
834     else
835       {
836 	return(0);				/* give up */
837       }
838   }
839 
840 
841 /***********************************************************************\
842 *			convert_ip_addr()				*
843 *************************************************************************
844 *									*
845 *	This routine accepts an internet address and attempts to	*
846 *	translate to an equivalent X25 address.  For DDN this follows	*
847 *	the guidelines in the DDN X25 interface spec.  The resultant	*
848 *	X25 address is stored in the X25 called addr buffer.  The	*
849 *	routine returns TRUE if successfull, FALSE otherwise.		*
850 *									*
851 *	NOTE: Although IF-11/X25 was designed to accept ASCII coded	*
852 *	digits for the address fields, we only supply the binary	*
853 *	values.  The front-end only uses the low four bits to extract	*
854 *	the binary value from the ASCII digits, so this works out.	*
855 *									*
856 \***********************************************************************/
857 
858 static boolean convert_ip_addr(ip_addr, x25addr)
859 struct in_addr ip_addr;
860 u_char x25addr[];
861   {
862     register int temp;
863     union {
864 	struct in_addr ip;
865 	struct {	 /*   (assumes Class A network number) */
866 	    u_char s_net;
867 	    u_char s_host;
868 	    u_char s_lh;
869 	    u_char s_impno;
870 	} imp;
871     } imp_addr;
872 
873     imp_addr.ip = ip_addr;
874     x25addr[0] = 14;		/* set addr length */
875 
876     x25addr[1] = 0;		/* clear DNIC */
877     x25addr[2] = 0;
878     x25addr[3] = 0;
879     x25addr[4] = 0;
880 
881     if (imp_addr.imp.s_host < 64)	/* Physical:  0000 0 IIIHH00 [SS] */
882       {					/*   s_impno -> III, s_host -> HH */
883     	x25addr[5] = 0;		/* set flag bit */
884     	x25addr[6] = imp_addr.imp.s_impno / 100;
885     	x25addr[7] = (imp_addr.imp.s_impno % 100) / 10;
886     	x25addr[8] = imp_addr.imp.s_impno % 10;
887     	x25addr[9] = imp_addr.imp.s_host / 10;
888     	x25addr[10] = imp_addr.imp.s_host % 10;
889       }
890     else			/* Logical:   0000 1 RRRRR00 [SS]	*/
891       {				/*   s_host * 256 + s_impno -> RRRRR	*/
892     	temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
893     	x25addr[5] = 1;
894     	x25addr[6] = temp / 10000;
895     	x25addr[7] = (temp % 10000) / 1000;
896     	x25addr[8] = (temp % 1000) / 100;
897     	x25addr[9] = (temp % 100) / 10;
898     	x25addr[10] = temp % 10;
899       }
900 
901     x25addr[11] = 0;		/* clear rest of addr */
902     x25addr[12] = 0;
903     x25addr[13] = 0;
904     x25addr[14] = 0;
905 
906 #ifdef DDNDEBUG
907 if (ddn_debug > 4)
908   {
909 printf("convert_ip_addr():  ");
910 prt_addr(ip_addr);
911 printf(" ==> ");
912 prt_bytes(x25addr, 14);
913 printf("\n");
914   }
915 #endif DDNDEBUG
916 
917     return(1);
918   }
919 
920 
921 /***********************************************************************\
922 *			convert_x25_addr()				*
923 *************************************************************************
924 *									*
925 *	This routine accepts an X25 address and attempts to translate	*
926 *	to an equivalent internet address.  For DDN this follows the	*
927 *	guidelines in the DDN X25 interface spec.  The resultant	*
928 *	internet address is returned to the caller.			*
929 *									*
930 \***********************************************************************/
931 
932 static int convert_x25_addr(x25addr)
933 u_char x25addr[];
934   {
935     register int cnt, temp;
936     union {
937 	struct in_addr ip;
938 	struct {	 /*   (assumes Class A network number) */
939 	    u_char s_net;
940 	    u_char s_host;
941 	    u_char s_lh;
942 	    u_char s_impno;
943 	} imp;
944     } imp_addr;
945 
946     if (((cnt = x25addr[0]) < 12) || (cnt > 14))
947       {
948     	printf("DDN: illegal X25 address length!\n");
949     	return(0);
950       }
951 
952     switch(x25addr[5] & 0x0f)
953       {
954     case 0:			/* Physical:  0000 0 IIIHH00 [SS]	*/
955 	imp_addr.imp.s_impno =
956 		((int)(x25addr[6] & 0x0f) * 100) +
957 		((int)(x25addr[7] & 0x0f) * 10)  +
958 		((int)(x25addr[8] & 0x0f));
959 
960 
961     	imp_addr.imp.s_host =
962     		((int)(x25addr[9] & 0x0f) * 10) +
963 		((int)(x25addr[10] & 0x0f));
964         break;
965     case 1:			/* Logical:   0000 1 RRRRR00 [SS]	*/
966     	temp =    ((int)(x25addr[6] & 0x0f) * 10000)
967 		+ ((int)(x25addr[7] & 0x0f) * 1000)
968 		+ ((int)(x25addr[8] & 0x0f) * 100)
969     		+ ((int)(x25addr[9] & 0x0f) * 10)
970 		+ ((int)(x25addr[10] & 0x0f));
971 
972     	imp_addr.imp.s_host = temp >> 8;
973     	imp_addr.imp.s_impno = temp & 0xff;
974     	break;
975     default:
976     	printf("DDN: illegal X25 address format!\n");
977     	return(0);
978       }
979 
980     imp_addr.imp.s_lh = 0;
981     imp_addr.imp.s_net = 0;
982 
983 #ifdef DDNDEBUG
984 if (ddn_debug > 4)
985   {
986 printf("convert_x25_addr():  ");
987 prt_bytes(&x25addr[1], cnt);
988 printf(" ==> ");
989 prt_addr(imp_addr.ip);
990 printf("\n");
991   }
992 #endif DDNDEBUG
993 
994     return(imp_addr.ip.s_addr);
995   }
996 
997 
998 /***********************************************************************\
999 *			make_x25_call()					*
1000 *************************************************************************
1001 *									*
1002 *	This routine places an X25 call using the X25 Call Msg		*
1003 *	buffer.  The calling LCN is placed in the appropriate state	*
1004 *	and a timer is started.						*
1005 *									*
1006 \***********************************************************************/
1007 
1008 static boolean make_x25_call(ds, dc)
1009 register struct ddn_softc *ds;
1010 register struct ddn_cb *dc;
1011   {
1012     register struct mbuf *m_callbfr;
1013     register caddr_t cb;
1014 
1015     MGET(m_callbfr, M_DONTWAIT, MT_DATA);  /* try to get call cmnd buffer */
1016     if (m_callbfr == 0)
1017 	return(0);
1018 
1019     cb = mtod(m_callbfr, caddr_t);
1020 
1021     (void)convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
1022 
1023     cb_protocol[0] = 4;
1024     cb_protocol[1] = X25_PROTO_IP;	/* protocol = IP */
1025     cb_protocol[2] = 0;
1026     cb_protocol[3] = 0;
1027     cb_protocol[4] = 0;
1028 
1029     cb_facilities[0] = 4;		/* number facility bytes */
1030     cb_facilities[1] = 0;		/*  options marker */
1031     cb_facilities[2] = 0;
1032     cb_facilities[3] = X25_FACIL_DDN;	/*  DDN standard mode */
1033     cb_facilities[4] = FAC_DDNSTD;
1034 
1035     cb_user_data[0] = 0;		/* no user data */
1036 
1037     cb_cmnd[0] = CALL;			/* set command code */
1038     cb_cmnd[1] = dc->dc_lcn << 1;	/* set channel id */
1039     cb_cmnd[2] = 0;
1040     cb_cmnd[3] = (cb_called_addr[0] + 1) +	/* tally up cmnd ext length */
1041 		 (cb_calling_addr[0] + 1) +
1042 		 (cb_protocol[0] + 1) +
1043 		 (cb_facilities[0] + 1) +
1044 		 (cb_user_data[0] + 1);
1045 
1046     m_callbfr->m_len = cb_cmnd[3] + 4;
1047 
1048     /* copy command header */
1049     bcopy((caddr_t)cb_cmnd, cb, 4);
1050     cb += 4;
1051 
1052     /* copy called address */
1053     bcopy((caddr_t)cb_called_addr, cb, cb_called_addr[0] + 1);
1054     cb += (cb_called_addr[0] + 1);
1055 
1056     /* copy calling address */
1057     bcopy((caddr_t)cb_calling_addr, cb, cb_calling_addr[0] + 1);
1058     cb += (cb_calling_addr[0] + 1);
1059 
1060     /* copy protocol */
1061     bcopy((caddr_t)cb_protocol, cb, cb_protocol[0] + 1);
1062     cb += (cb_protocol[0] + 1);
1063 
1064     /* copy facilities */
1065     bcopy((caddr_t)cb_facilities, cb, cb_facilities[0] + 1);
1066     cb += (cb_facilities[0] + 1);
1067 
1068     /* copy user data */
1069     bcopy((caddr_t)cb_user_data, cb, cb_user_data[0] + 1);
1070     cb += (cb_user_data[0] + 1);
1071 
1072     dc->dc_state = LC_CALL_PENDING;		/* set state */
1073     dc->dc_timer = TMO_CALL_PENDING;		/* start call timeout */
1074 
1075 #ifdef DDNDEBUG
1076 if (ddn_debug > 3)
1077   {
1078 printf("make_x25_call(): call_bfr = ");
1079 prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
1080 printf("\n");
1081   }
1082 #endif DDNDEBUG
1083 
1084     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr);
1085     ddn_start(ds, &(ds->ddn_cb[0]));
1086 
1087     return(1);
1088   }
1089 
1090 
1091 /***********************************************************************\
1092 *				ddn_start()				*
1093 *************************************************************************
1094 *									*
1095 *	This routine attempts to start output of data queued on	a	*
1096 *	specific LCN.  If the LCN was not already busy and data is	*
1097 *	available for output, the data is copied into the LCN's I/O	*
1098 *	buffer and an I/O request queued to the UMC.			*
1099 *									*
1100 \***********************************************************************/
1101 
1102 static void ddn_start(ds, dc)
1103 register struct ddn_softc *ds;
1104 register struct ddn_cb *dc;
1105   {
1106     register struct mbuf *m;
1107     int len;
1108 
1109     /*
1110      * If output isn't active, attempt to
1111      * start sending a new packet.
1112      */
1113 
1114     if ((dc->dc_flags & DC_OBUSY) ||
1115     	(dc->dc_oq.ifq_len == 0) ||
1116     	((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE)))
1117       {
1118     	return;
1119       }
1120 
1121     IF_DEQUEUE(&dc->dc_oq, m);
1122 
1123     len = if_wubaput(&dc->dc_ifuba, m);	/* copy data to mapped mem */
1124     dc->dc_flags |= DC_OBUSY;
1125 
1126     ddn_iorq(ds, dc, len, DDNWRT+DDNEOS);
1127   }
1128 
1129 
1130 /***********************************************************************\
1131 *				ddn_iorq()				*
1132 *************************************************************************
1133 *									*
1134 *	This routine builds UMC I/O requests and queues them for	*
1135 *	delivery to the UMC. If the UMC I/O request comm regs are	*
1136 *	not busy, the I/O request is passed to the UMC.			*
1137 *									*
1138 \***********************************************************************/
1139 
1140 static void ddn_iorq(ds, dc, len, func)
1141 struct ddn_softc *ds;
1142 struct ddn_cb *dc;
1143 int len, func;
1144   {
1145     register struct hdx_chan *hc;
1146     register int info;
1147 
1148 
1149     /* get appropriate UNIBUS mapping info */
1150 
1151     if (func & DDNRDB)		/* read or write? */
1152       {
1153     	hc = &dc->dc_rchan;
1154     	info = dc->dc_ifuba.ifu_r.ifrw_info;
1155       }
1156     else
1157       {
1158     	hc = &dc->dc_wchan;
1159     	info = dc->dc_ifuba.ifu_w.ifrw_info;
1160       }
1161 
1162     /* set channel info */
1163 
1164     hc->hc_adx = (u_char)((info & 0x30000) >> 12);
1165     hc->hc_addr = (u_short)(info & 0xffff);
1166     hc->hc_cnt = len;
1167     hc->hc_func = (u_char)func;
1168     hc->hc_sbfc = 0;
1169 
1170     /*
1171      * If UMC comm regs busy, queue start i/o for later.
1172      */
1173     if (ds->ddn_sioq.sq_head)
1174       {
1175     	(ds->ddn_sioq.sq_tail)->hc_next = hc;
1176     	ds->ddn_sioq.sq_tail = hc;
1177     	hc->hc_next = 0;
1178     	return;
1179       }
1180 
1181     /* start i/o on channel now */
1182 
1183     ds->ddn_sioq.sq_head = hc;
1184     ds->ddn_sioq.sq_tail = hc;
1185     hc->hc_next = 0;
1186     start_chn(ds);
1187   }
1188 
1189 
1190 /***********************************************************************\
1191 *				start_chn()				*
1192 *************************************************************************
1193 *									*
1194 *	This routine copies UMC I/O requests into the UMC comm regs	*
1195 *	and notifies the UMC.						*
1196 *									*
1197 \***********************************************************************/
1198 
1199 static void start_chn(ds)
1200 struct ddn_softc *ds;
1201   {
1202     register struct hdx_chan *hc = ds->ddn_sioq.sq_head;
1203     register struct ddnregs *addr =
1204     	(struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr;
1205 
1206     /*
1207      * Set up comm regs.
1208      */
1209     addr->iochn = hc->hc_chan;
1210     addr->ioadx = hc->hc_adx;
1211     addr->ioadl = hc->hc_addr;
1212     addr->iocnt = hc->hc_cnt;
1213     addr->iofcn = hc->hc_func;
1214     addr->iosbf = hc->hc_sbfc;
1215     addr->ioini = 1;
1216 
1217     /* signal UMC if necessary */
1218 
1219     if (!(addr->ionmi))
1220       {
1221     	addr->ionmi = 1;
1222     	addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
1223       }
1224   }
1225 
1226 
1227 /***********************************************************************\
1228 *				ddn_data()				*
1229 *************************************************************************
1230 *									*
1231 *	This routine is called when a data channel I/O completes.	*
1232 *	If the completion was for a write, an attempt is made to	*
1233 *	start output on the next packet waiting for output on that	*
1234 *	LCN.  If the completion was for a read, the received packet	*
1235 *	is sent to the IP input queue (if no error) and another read	*
1236 *	is started on the LCN.						*
1237 *									*
1238 \***********************************************************************/
1239 
1240 static void ddn_data(unit, chan, cc, rcnt)
1241 int unit, chan, cc, rcnt;
1242 {
1243     register struct ddn_softc *ds = &ddn_softc[unit];
1244     register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]);
1245     register struct ifqueue *inq = &ipintrq;
1246     register struct mbuf *m;
1247 
1248     if (chan & 0x01)			/* was it read or write? */
1249       {					/*   write, fire up next output */
1250     	ds->ddn_if.if_opackets++;
1251     	dc->dc_flags &= ~DC_OBUSY;
1252     	ddn_start(ds, dc);
1253       }
1254     else				/*   read, process rcvd packet */
1255       {
1256     	if (cc == DDNIOCOK)
1257     	  {				/* Queue good packet for input */
1258     	    ds->ddn_if.if_ipackets++;
1259 	    dc->dc_state = LC_DATA_IDLE;
1260 	    dc->dc_timer = TMO_DATA_IDLE;
1261     	    m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
1262     	    if (m)
1263     	      {
1264     		if (IF_QFULL(inq))
1265     		  {
1266     		    IF_DROP(inq);
1267     		    m_freem(m);
1268     		  }
1269     		else
1270     		  {
1271     		    IF_ENQUEUE(inq, m);
1272     		    schednetisr(NETISR_IP);
1273     		  }
1274     	      }
1275     	  }
1276 
1277     	/* hang a new data read */
1278 
1279     	ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
1280 
1281       }
1282   }
1283 
1284 
1285 /***********************************************************************\
1286 *				ddn_supr()				*
1287 *************************************************************************
1288 *									*
1289 *	This routine is called when a supervisor I/O completes.		*
1290 *	If the completion was for a write, an attempt is made to	*
1291 *	start output on the next supervisor command waiting for		*
1292 *	output.  If the completion was for a read, the received		*
1293 *	supervisor message is processed and another read is started.	*
1294 *									*
1295 \***********************************************************************/
1296 
1297 static void ddn_supr(unit, chan, cc)
1298 int unit, chan, cc;
1299 {
1300     register struct ddn_softc *ds = &ddn_softc[unit];
1301     u_char *p;
1302 
1303     /* was it read or write? */
1304 
1305     if (chan & 0x01)
1306       {
1307     	ds->ddn_cb[0].dc_flags &= ~DC_OBUSY;
1308     	ddn_start(ds, &(ds->ddn_cb[0]));
1309       }
1310     else
1311       {
1312     	if (cc == DDNIOCOK)
1313     	  {
1314     	    p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr);
1315 
1316     	    /* process supervisor message */
1317 
1318     	    supr_msg(ds, p);
1319 
1320     	  }
1321 
1322     	/* hang a new supr read */
1323 
1324     	ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR);
1325       }
1326   }
1327 
1328 
1329 /***********************************************************************\
1330 *				supr_msg()				*
1331 *************************************************************************
1332 *									*
1333 *	This routine processes received supervisor messages.		*
1334 *	Depending on the message type, the appropriate action is	*
1335 *	taken.
1336 *									*
1337 \***********************************************************************/
1338 
1339 static void supr_msg(ds, p)
1340 struct ddn_softc *ds;
1341 u_char p[];
1342   {
1343     register struct ddn_cb *dc;
1344     register int lcn;
1345     register struct mbuf *m;
1346 
1347 #ifdef DDNDEBUG
1348 if (ddn_debug > 5)
1349   {
1350 printf("supr_msg():  ");
1351 prt_bytes(p, 4+p[3]);
1352 printf("\n");
1353   }
1354 #endif DDNDEBUG
1355 
1356     switch (p[0])
1357       {
1358     case LINE_STATUS:			/*   link status msg */
1359 	if (p[2] == LINK_UP)		/*   if link came up */
1360 	  {
1361     	    send_restart(ds);		/*     send restart msg */
1362 	  }
1363 	else				/*   if link went down */
1364 	  {
1365     	    ds->ddn_if.if_flags &= ~IFF_UP;
1366     	    dc = ds->ddn_cb;
1367     	    for(lcn = 0; lcn <= NDDNCH; lcn++) /*    for all LCN's */
1368     	      {
1369     		dc->dc_state = LC_DOWN;  /* set state */
1370     		dc->dc_timer = TMO_OFF;  /* stop timer */
1371 		dc++;
1372     	      }
1373 	  }
1374     	break;
1375 
1376     case RESTART:			/* restart received */
1377     	if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */
1378     	    send_supr(ds, RSTRT_ACK, 0, 0);    /*   send restart ack */
1379 	/* fall thru */
1380     case RSTRT_ACK:			/* restart ack */
1381     	ds->ddn_if.if_flags |= IFF_UP;
1382     	dc = ds->ddn_cb;
1383     	for(lcn = 0; lcn <= NDDNCH; lcn++)	/* for all LCN's */
1384     	  {
1385     	    dc->dc_state = LC_IDLE;   /* set state */
1386     	    dc->dc_timer = TMO_OFF;   /* stop timer */
1387     	    dc->dc_inaddr.s_addr = 0; /* forget address */
1388     	    while (dc->dc_oq.ifq_len) /* drop pending data */
1389     	      {
1390     		IF_DEQUEUE(&dc->dc_oq, m);
1391     		m_freem(m);
1392     	      }
1393 	    dc++;
1394     	  }
1395     	break;
1396 
1397     case ANSWER:			/* call answered */
1398     	lcn = p[1] / 2;
1399     	dc = &(ds->ddn_cb[lcn]);
1400     	if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */
1401     	  {
1402     	    dc->dc_state = LC_DATA_IDLE;  /* set state */
1403     	    dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1404     	    ddn_start(ds, dc);		  /* try to send data */
1405     	  }
1406     	break;
1407 
1408     case RING:				/* incoming call */
1409     	for(lcn = NDDNCH; lcn > 0; lcn--)	/* search LCN's */
1410     	  {
1411     	    if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */
1412     	    	break;
1413     	  }
1414 
1415     	if (lcn && decode_ring(p))	/* if a free LCN found */
1416 					/*   and ring looks ok */
1417     	  {
1418     	    dc = &(ds->ddn_cb[lcn]);
1419     	    dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr);
1420     	    dc->dc_state = LC_DATA_IDLE;  /* set state */
1421     	    dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1422     	    send_supr(ds, ANSWER, lcn * 2, (int)p[2]); /* send answer */
1423     	  }
1424     	else				/* if no free LCN's */
1425     	  {
1426     	    send_supr(ds, CLEARVC, (int)p[2], 0); /* clear call */
1427     	  }
1428     	break;
1429 
1430     case CLEARLC:			/* clear by LCN */
1431     	lcn = p[1] / 2;			/* get LCN */
1432     	dc = &(ds->ddn_cb[lcn]);
1433     	if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */
1434     	  {
1435     	    send_supr(ds, CLEARLC, (int)p[1], 0);      /*   ack the clear */
1436     	  }
1437     	dc->dc_state = LC_IDLE; /* set state */
1438     	dc->dc_timer = TMO_OFF; /* stop timer */
1439     	dc->dc_inaddr.s_addr = 0; /* forget address */
1440     	while (dc->dc_oq.ifq_len) /* drop pending data */
1441     	  {
1442     	    IF_DEQUEUE(&dc->dc_oq, m);
1443     	    m_freem(m);
1444     	  }
1445     	break;
1446 
1447     case CLEARVC:			/* clear by VCN */
1448     	send_supr(ds, CLEARVC, (int)p[1], 0); /* send clear ack */
1449     	break;
1450 
1451     case RESET:				/* X25 reset */
1452 	send_supr(ds, RESET_ACK, (int)p[1], 0); /* send reset ack */
1453     	printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */
1454 	break;
1455 
1456     case INTERRUPT:			/* X25 interrupt */
1457     	printf("X25 INTERRUPT on lcn = %d, code = %d\n",	/* log it */
1458     	    p[1] / 2, p[2]);
1459 	break;
1460 
1461     default:
1462     	printf("ddn%d: supervisor error, code=%x\n",
1463 	   ds->ddn_if.if_unit, p[0]);
1464       }
1465   }
1466 
1467 
1468 /***********************************************************************\
1469 *				decode_ring()				*
1470 *************************************************************************
1471 *									*
1472 *	This routine parses and validates the incoming call msg.	*
1473 *									*
1474 \***********************************************************************/
1475 
1476 static boolean decode_ring(p)
1477 register u_char *p;
1478   {
1479     register int cnt;
1480 
1481 #ifdef DDNDEBUG
1482 if (ddn_debug > 3)
1483   {
1484 printf("decode_ring()\n");
1485   }
1486 #endif DDNDEBUG
1487 
1488 
1489     p += 3;			/* skip to cmnd ext length */
1490     if (*p++ < 5)		/* is count appropriate */
1491 	return(0);		/*   return false if not */
1492 
1493     /* called address */
1494     if ((cnt = *p + 1) > 16)	/* is called addr len legal? */
1495 	return(0);		/*   return false if not */
1496     bcopy((caddr_t)p, (caddr_t)cb_called_addr, (unsigned)cnt); /* copy field */
1497     p += cnt;
1498 
1499     /* calling address */
1500     if ((cnt = *p + 1) > 16)	/* is calling addr len legal? */
1501 	return(0);		/*   return false if not */
1502     bcopy((caddr_t)p, (caddr_t)cb_calling_addr, (unsigned)cnt); /* copy field */
1503     p += cnt;
1504 
1505     /* protocol part of user data */
1506     if ((cnt = *p + 1) > 5)	/* is protocol len legal? */
1507 	return(0);		/*   return false if not */
1508     bcopy((caddr_t)p, (caddr_t)cb_protocol, (unsigned)cnt); /* copy field */
1509     p += cnt;
1510 
1511     /* facilities */
1512     if ((cnt = *p + 1) > 64)	/* is facilities len legal? */
1513 	return(0);		/*   return false if not */
1514     bcopy((caddr_t)p, (caddr_t)cb_facilities, (unsigned)cnt); /* copy field */
1515     p += cnt;
1516 
1517     /* ignore rest of user data for now */
1518 
1519     if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP))
1520 	return(0);		/* bad if not IP */
1521 
1522     return(1);			/* looks ok */
1523   }
1524 
1525 
1526 /***********************************************************************\
1527 *				clear_lcn()				*
1528 *************************************************************************
1529 *									*
1530 *	This routine clears an X25 circuit and releases any buffers	*
1531 *	queued for transmission.					*
1532 *									*
1533 \***********************************************************************/
1534 
1535 static void clear_lcn(ds, dc)
1536 struct ddn_softc *ds;
1537 struct ddn_cb *dc;
1538   {
1539     register struct mbuf *m;
1540 
1541 #ifdef DDNDEBUG
1542 if (ddn_debug > 3)
1543   {
1544 printf("clear_lcn(%d)\n", dc->dc_lcn);
1545   }
1546 #endif DDNDEBUG
1547 
1548     dc->dc_state = LC_CLR_PENDING;  /* set state */
1549     dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
1550     dc->dc_inaddr.s_addr = 0;	    /* clear associated address */
1551     while (dc->dc_oq.ifq_len)	    /* drop any pending data */
1552       {
1553     	IF_DEQUEUE(&dc->dc_oq, m);
1554     	m_freem(m);
1555       }
1556     send_supr(ds, CLEARLC, (int)dc->dc_lcn * 2, 0);    /* send clear msg */
1557   }
1558 
1559 
1560 /***********************************************************************\
1561 *				send_restart()				*
1562 *************************************************************************
1563 *									*
1564 *	This routine marks all LCNs as being in a restarting state	*
1565 *	and sends a restart command to X25.				*
1566 *									*
1567 \***********************************************************************/
1568 
1569 static void send_restart(ds)
1570 struct ddn_softc *ds;
1571   {
1572     register struct ddn_cb *dc;
1573     register int lcn;
1574     struct mbuf *m;
1575 
1576 #ifdef DDNDEBUG
1577 if (ddn_debug > 1)
1578   {
1579 printf("send_restart()\n");
1580   }
1581 #endif DDNDEBUG
1582     dc = ds->ddn_cb;
1583     for(lcn = 0; lcn <= NDDNCH; lcn++)	    /* for all LCN's */
1584       {
1585     	dc->dc_state = LC_RESTART;  /* set state */
1586     	dc->dc_timer = TMO_RESTART; /* start restart timeout */
1587     	dc->dc_inaddr.s_addr = 0;     /* forget address */
1588     	while (dc->dc_oq.ifq_len)	/* drop any pending data */
1589     	  {
1590     	    IF_DEQUEUE(&dc->dc_oq, m);
1591     	    m_freem(m);
1592     	  }
1593 	dc++;
1594       }
1595 
1596     send_supr(ds, RESTART, 0, 0);	    /* send restart msg */
1597   }
1598 
1599 
1600 /***********************************************************************\
1601 *				send_supr()				*
1602 *************************************************************************
1603 *									*
1604 *	This routine is used to send short (4 bytes only) supervisor	*
1605 *	commands.							*
1606 *									*
1607 \***********************************************************************/
1608 
1609 static void send_supr(ds, cmd, p1, p2)
1610 struct ddn_softc *ds;
1611 int cmd, p1, p2;
1612   {
1613     struct mbuf *m;
1614     register u_char *cp;
1615 
1616 #ifdef DDNDEBUG
1617 if (ddn_debug > 6)
1618   {
1619 printf("send_supr():  %x %x %x\n", cmd, p1, p2);
1620   }
1621 #endif DDNDEBUG
1622 
1623     MGET(m, M_DONTWAIT, MT_DATA);
1624 
1625     if (m == 0)
1626       {
1627     	printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit);
1628     	return;
1629       }
1630 
1631     cp = mtod(m, u_char *);
1632 
1633     /* build supervisor message */
1634 
1635     *cp++ = (byte)cmd;
1636     *cp++ = (byte)p1;
1637     *cp++ = (byte)p2;
1638     *cp++ = 0;
1639 
1640     m->m_len = 4;
1641 
1642     IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
1643     ddn_start(ds, &(ds->ddn_cb[0]));
1644 
1645   }
1646 
1647 
1648 #ifdef DDNDEBUG
1649 
1650 /***********************************************************************\
1651 *				prt_addr()				*
1652 *************************************************************************
1653 *									*
1654 *	This routine is used to print internet addresses in the		*
1655 *	standard A.B.C.D format.					*
1656 *									*
1657 \***********************************************************************/
1658 
1659 static void prt_addr(addr)
1660 struct in_addr addr;
1661   {
1662     printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
1663   }
1664 
1665 /***********************************************************************\
1666 *				prt_bytes()				*
1667 *************************************************************************
1668 *									*
1669 *	This routine is used to print a string of bytes in hex.		*
1670 *									*
1671 \***********************************************************************/
1672 
1673 static void prt_bytes(bp, cnt)
1674 u_char *bp;
1675 int cnt;
1676   {
1677     while(cnt--)
1678       {
1679 	printf(" %x", *bp++ & 0xff);
1680       }
1681   }
1682 
1683 #endif DDNDEBUG
1684 
1685 #endif NDDN
1686