changes for var. length sockaddrs; new routing; mv common ether input
[unix-history] / usr / src / sys / vax / if / if_ddn.c
CommitLineData
4f02060d 1/* @(#)if_ddn.c 7.2 (Berkeley) %G% */
f0ecc930
MK
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
31File:
32 if_ddn.c
33
34Author:
35 Art Berggreen
36
37Project:
38 4.2 DDN X.25 network driver
39
40Function:
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
45Components:
46
47Revision History:
48 16-May-1985: V1.0 - First release.
49 Art Berggreen.
50
51\************************************************************************/
52\f
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
e43e0f32
MK
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"
f0ecc930
MK
77
78#include "../net/if.h"
79#include "../net/netisr.h"
80#include "../net/route.h"
e43e0f32 81
e43e0f32 82#ifdef INET
f0ecc930
MK
83#include "../netinet/in.h"
84#include "../netinet/in_systm.h"
e43e0f32 85#include "../netinet/in_var.h"
f0ecc930 86#include "../netinet/ip.h"
e43e0f32 87#endif
f0ecc930
MK
88
89#include "../vax/cpu.h"
90#include "../vax/mtpr.h"
e43e0f32
MK
91#include "if_ddnreg.h"
92#include "if_ddnvar.h"
93#include "if_uba.h"
f0ecc930
MK
94#include "../vaxuba/ubareg.h"
95#include "../vaxuba/ubavar.h"
96
97\f
98
99/* declare global functions */
100
101int ddnprobe();
102int ddnattach();
103int ddnreset();
104int ddninit();
105int ddnoutput();
106int ddntimer();
107int ddnioctl();
108int ddnintr();
109
110/* declare local functions */
111
112static void x25_init();
113static struct ddn_cb *locate_x25_lcn();
114static boolean convert_ip_addr();
115static int convert_x25_addr();
116static boolean make_x25_call();
117static void ddn_start();
118static void ddn_iorq();
119static void start_chn();
120static void ddn_data();
121static void ddn_supr();
122static void supr_msg();
123static boolean decode_ring();
124static void clear_lcn();
125static void send_restart();
126static void send_supr();
127#ifdef DDNDEBUG
128static void prt_addr();
129static void prt_bytes();
130#endif DDNDEBUG
131\f
132
133struct uba_device *ddninfo[NDDN]; /* ptrs to device info */
134u_short ddnstd[] = { 0766740, 0 }; /* standard addresses */
135struct 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
146static 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
163u_char cb_cmnd[4] =
164 {
165 CALL,
166 0,
167 0,
168 0
169 };
170
171u_char cb_called_addr[16] = {0};
172
173u_char cb_calling_addr[16] = {0};
174
175u_char cb_facilities[64] = {0};
176
177u_char cb_protocol[5] = {0};
178
179u_char cb_user_data[1] = {0};
180
181#ifdef DDNDEBUG
182int ddn_debug = 1; /* values 0-8 cause increasing verbosity */
183#endif DDNDEBUG
184\f
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
205struct 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
211struct 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
222struct 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
235struct 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 */
e43e0f32 242 struct in_addr ddn_ipaddr; /* local IP address */
f0ecc930
MK
243 } ddn_softc[NDDN];
244\f
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
267static int savevec; /* static variable for vector */
268
269ddnprobe(reg)
270caddr_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
58bca61d 277 br = 0; cvec = br; br = cvec; ddnintr(0);
f0ecc930
MK
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\f
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
306ddnattach(ui)
307struct 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 */
e43e0f32 320 if_attach(&ds->ddn_if);
f0ecc930
MK
321 }
322\f
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
333ddnreset(unit, uban)
334int 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\f
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
371ddninit(unit)
372int 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];
f0ecc930
MK
377 int lcn, s;
378
379#ifdef DDNDEBUG
380if (ddn_debug > 0)
381 {
382printf("ddn%d: ddninit()\n", unit);
383 }
384#endif DDNDEBUG
385
e43e0f32 386 if (ds->ddn_if.if_addrlist == 0) /* if we have no internet addr */
f0ecc930
MK
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 */
f0ecc930
MK
448 }
449\f
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
463ddnoutput(ifp, m0, dst)
464struct ifnet *ifp;
465struct mbuf *m0;
466struct 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
494if (ddn_debug > 6)
495 {
496printf("ddnoutput(): dst = ");
497prt_addr(dst->sin_addr.s_addr);
498printf("\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\f
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
545int ddntimer(unit)
546int 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
553if (ddn_debug > 7)
554 {
555printf("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\f
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
595ddnioctl(ifp, cmd, data)
e43e0f32
MK
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;
e43e0f32
MK
602
603 switch (cmd) {
604
605 case SIOCSIFADDR:
4f02060d 606 if (ifa->ifa_addr->sa_family != AF_INET)
e43e0f32
MK
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}
f0ecc930
MK
621\f
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
637ddnintr(unit)
638int 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
9205905c 725 ddn_supr(unit, chan, cc);
f0ecc930
MK
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\f
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
750static void x25_init(ds)
751struct ddn_softc *ds;
752 {
753 struct mbuf *m;
f0ecc930
MK
754
755#ifdef DDNDEBUG
756if (ddn_debug > 0)
757 {
758printf("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
8011f5df 771 bcopy((caddr_t)init_msg, mtod(m, caddr_t), sizeof(init_msg));
f0ecc930
MK
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\f
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
795static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
796struct ddn_softc *ds;
797struct in_addr ip_addr;
798 {
799 register int lcn;
800 register struct ddn_cb *dc;
f0ecc930
MK
801
802#ifdef DDNDEBUG
803if (ddn_debug > 6)
804 {
805printf("locate_x25_lcn()\n");
806 }
807#endif DDNDEBUG
808
f0ecc930
MK
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\f
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
858static boolean convert_ip_addr(ip_addr, x25addr)
859struct in_addr ip_addr;
860u_char x25addr[];
861 {
862 register int temp;
e43e0f32
MK
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;
f0ecc930
MK
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
e43e0f32
MK
881 if (imp_addr.imp.s_host < 64) /* Physical: 0000 0 IIIHH00 [SS] */
882 { /* s_impno -> III, s_host -> HH */
f0ecc930 883 x25addr[5] = 0; /* set flag bit */
e43e0f32
MK
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;
f0ecc930
MK
889 }
890 else /* Logical: 0000 1 RRRRR00 [SS] */
891 { /* s_host * 256 + s_impno -> RRRRR */
e43e0f32 892 temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
f0ecc930
MK
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
907if (ddn_debug > 4)
908 {
909printf("convert_ip_addr(): ");
910prt_addr(ip_addr);
911printf(" ==> ");
912prt_bytes(x25addr, 14);
913printf("\n");
914 }
915#endif DDNDEBUG
916
917 return(1);
918 }
919\f
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
932static int convert_x25_addr(x25addr)
933u_char x25addr[];
934 {
935 register int cnt, temp;
e43e0f32
MK
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;
f0ecc930
MK
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] */
e43e0f32 955 imp_addr.imp.s_impno =
f0ecc930
MK
956 ((int)(x25addr[6] & 0x0f) * 100) +
957 ((int)(x25addr[7] & 0x0f) * 10) +
958 ((int)(x25addr[8] & 0x0f));
959
960
e43e0f32 961 imp_addr.imp.s_host =
f0ecc930
MK
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
e43e0f32
MK
972 imp_addr.imp.s_host = temp >> 8;
973 imp_addr.imp.s_impno = temp & 0xff;
f0ecc930
MK
974 break;
975 default:
976 printf("DDN: illegal X25 address format!\n");
977 return(0);
978 }
979
e43e0f32
MK
980 imp_addr.imp.s_lh = 0;
981 imp_addr.imp.s_net = 0;
f0ecc930
MK
982
983#ifdef DDNDEBUG
984if (ddn_debug > 4)
985 {
986printf("convert_x25_addr(): ");
987prt_bytes(&x25addr[1], cnt);
988printf(" ==> ");
e43e0f32 989prt_addr(imp_addr.ip);
f0ecc930
MK
990printf("\n");
991 }
992#endif DDNDEBUG
993
e43e0f32 994 return(imp_addr.ip.s_addr);
f0ecc930
MK
995 }
996\f
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
1008static boolean make_x25_call(ds, dc)
1009register struct ddn_softc *ds;
1010register struct ddn_cb *dc;
1011 {
1012 register struct mbuf *m_callbfr;
8011f5df 1013 register caddr_t cb;
f0ecc930
MK
1014
1015 MGET(m_callbfr, M_DONTWAIT, MT_DATA); /* try to get call cmnd buffer */
1016 if (m_callbfr == 0)
1017 return(0);
1018
8011f5df 1019 cb = mtod(m_callbfr, caddr_t);
f0ecc930 1020
58bca61d 1021 (void)convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
f0ecc930
MK
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 */
8011f5df 1049 bcopy((caddr_t)cb_cmnd, cb, 4);
f0ecc930
MK
1050 cb += 4;
1051
1052 /* copy called address */
8011f5df 1053 bcopy((caddr_t)cb_called_addr, cb, cb_called_addr[0] + 1);
f0ecc930
MK
1054 cb += (cb_called_addr[0] + 1);
1055
1056 /* copy calling address */
8011f5df 1057 bcopy((caddr_t)cb_calling_addr, cb, cb_calling_addr[0] + 1);
f0ecc930
MK
1058 cb += (cb_calling_addr[0] + 1);
1059
1060 /* copy protocol */
8011f5df 1061 bcopy((caddr_t)cb_protocol, cb, cb_protocol[0] + 1);
f0ecc930
MK
1062 cb += (cb_protocol[0] + 1);
1063
1064 /* copy facilities */
8011f5df 1065 bcopy((caddr_t)cb_facilities, cb, cb_facilities[0] + 1);
f0ecc930
MK
1066 cb += (cb_facilities[0] + 1);
1067
1068 /* copy user data */
8011f5df 1069 bcopy((caddr_t)cb_user_data, cb, cb_user_data[0] + 1);
f0ecc930
MK
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
1076if (ddn_debug > 3)
1077 {
1078printf("make_x25_call(): call_bfr = ");
1079prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
1080printf("\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\f
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
1102static void ddn_start(ds, dc)
1103register struct ddn_softc *ds;
1104register 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\f
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
1140static void ddn_iorq(ds, dc, len, func)
1141struct ddn_softc *ds;
1142struct ddn_cb *dc;
1143int 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\f
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
1199static void start_chn(ds)
1200struct 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\f
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
1240static void ddn_data(unit, chan, cc, rcnt)
1241int 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;
e43e0f32 1261 m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
f0ecc930
MK
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\f
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
9205905c
MK
1297static void ddn_supr(unit, chan, cc)
1298int unit, chan, cc;
f0ecc930
MK
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\f
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
1339static void supr_msg(ds, p)
1340struct ddn_softc *ds;
1341u_char p[];
1342 {
1343 register struct ddn_cb *dc;
1344 register int lcn;
1345 register struct mbuf *m;
1346
1347#ifdef DDNDEBUG
1348if (ddn_debug > 5)
1349 {
1350printf("supr_msg(): ");
1351prt_bytes(p, 4+p[3]);
1352printf("\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 */
58bca61d 1422 send_supr(ds, ANSWER, lcn * 2, (int)p[2]); /* send answer */
f0ecc930
MK
1423 }
1424 else /* if no free LCN's */
1425 {
58bca61d 1426 send_supr(ds, CLEARVC, (int)p[2], 0); /* clear call */
f0ecc930
MK
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 {
58bca61d 1435 send_supr(ds, CLEARLC, (int)p[1], 0); /* ack the clear */
f0ecc930
MK
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 */
58bca61d 1448 send_supr(ds, CLEARVC, (int)p[1], 0); /* send clear ack */
f0ecc930
MK
1449 break;
1450
1451 case RESET: /* X25 reset */
58bca61d 1452 send_supr(ds, RESET_ACK, (int)p[1], 0); /* send reset ack */
f0ecc930
MK
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\f
1467
1468/***********************************************************************\
1469* decode_ring() *
1470*************************************************************************
1471* *
1472* This routine parses and validates the incoming call msg. *
1473* *
1474\***********************************************************************/
1475
1476static boolean decode_ring(p)
1477register u_char *p;
1478 {
1479 register int cnt;
1480
1481#ifdef DDNDEBUG
1482if (ddn_debug > 3)
1483 {
1484printf("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 */
58bca61d 1496 bcopy((caddr_t)p, (caddr_t)cb_called_addr, (unsigned)cnt); /* copy field */
f0ecc930
MK
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 */
58bca61d 1502 bcopy((caddr_t)p, (caddr_t)cb_calling_addr, (unsigned)cnt); /* copy field */
f0ecc930
MK
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 */
58bca61d 1508 bcopy((caddr_t)p, (caddr_t)cb_protocol, (unsigned)cnt); /* copy field */
f0ecc930
MK
1509 p += cnt;
1510
1511 /* facilities */
1512 if ((cnt = *p + 1) > 64) /* is facilities len legal? */
1513 return(0); /* return false if not */
58bca61d 1514 bcopy((caddr_t)p, (caddr_t)cb_facilities, (unsigned)cnt); /* copy field */
f0ecc930
MK
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\f
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
1535static void clear_lcn(ds, dc)
1536struct ddn_softc *ds;
1537struct ddn_cb *dc;
1538 {
1539 register struct mbuf *m;
1540
1541#ifdef DDNDEBUG
1542if (ddn_debug > 3)
1543 {
1544printf("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 }
58bca61d 1556 send_supr(ds, CLEARLC, (int)dc->dc_lcn * 2, 0); /* send clear msg */
f0ecc930
MK
1557 }
1558\f
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
1569static void send_restart(ds)
1570struct ddn_softc *ds;
1571 {
1572 register struct ddn_cb *dc;
1573 register int lcn;
1574 struct mbuf *m;
1575
1576#ifdef DDNDEBUG
1577if (ddn_debug > 1)
1578 {
1579printf("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\f
1599
1600/***********************************************************************\
1601* send_supr() *
1602*************************************************************************
1603* *
1604* This routine is used to send short (4 bytes only) supervisor *
1605* commands. *
1606* *
1607\***********************************************************************/
1608
1609static void send_supr(ds, cmd, p1, p2)
1610struct ddn_softc *ds;
1611int cmd, p1, p2;
1612 {
1613 struct mbuf *m;
1614 register u_char *cp;
1615
1616#ifdef DDNDEBUG
1617if (ddn_debug > 6)
1618 {
1619printf("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\f
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
1659static void prt_addr(addr)
1660struct 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
1673static void prt_bytes(bp, cnt)
1674u_char *bp;
1675int cnt;
1676 {
1677 while(cnt--)
1678 {
1679 printf(" %x", *bp++ & 0xff);
1680 }
1681 }
1682
1683#endif DDNDEBUG
1684
1685#endif NDDN