5 * Copyright (c) 1996-1999 Whistle Communications, Inc.
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
37 * Author: Julian Elischer <julian@freebsd.org>
39 * $FreeBSD: src/sys/netgraph/ng_lmi.c,v 1.5.2.3 2002/07/02 22:17:18 archie Exp $
40 * $DragonFly: src/sys/netgraph/lmi/ng_lmi.c,v 1.8 2008/01/05 14:02:39 swildner Exp $
41 * $Whistle: ng_lmi.c,v 1.38 1999/11/01 09:24:52 julian Exp $
45 * This node performs the frame relay LMI protocol. It knows how
46 * to do ITU Annex A, ANSI Annex D, and "Group-of-Four" variants
49 * A specific protocol can be forced by connecting the corresponding
50 * hook to DLCI 0 or 1023 (as appropriate) of a frame relay link.
52 * Alternately, this node can do auto-detection of the LMI protocol
53 * by connecting hook "auto0" to DLCI 0 and "auto1023" to DLCI 1023.
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/errno.h>
59 #include <sys/kernel.h>
60 #include <sys/malloc.h>
62 #include <sys/syslog.h>
63 #include <sys/thread2.h>
64 #include <netgraph/ng_message.h>
65 #include <netgraph/netgraph.h>
69 * Human readable names for LMI
71 #define NAME_ANNEXA NG_LMI_HOOK_ANNEXA
72 #define NAME_ANNEXD NG_LMI_HOOK_ANNEXD
73 #define NAME_GROUP4 NG_LMI_HOOK_GROUPOF4
74 #define NAME_NONE "None"
87 * Any received LMI frame should be at least this long
89 #define LMI_MIN_LENGTH 8 /* XXX verify */
92 * Netgraph node methods and type descriptor
94 static ng_constructor_t nglmi_constructor
;
95 static ng_rcvmsg_t nglmi_rcvmsg
;
96 static ng_shutdown_t nglmi_rmnode
;
97 static ng_newhook_t nglmi_newhook
;
98 static ng_rcvdata_t nglmi_rcvdata
;
99 static ng_disconnect_t nglmi_disconnect
;
100 static int nglmi_checkdata(hook_p hook
, struct mbuf
*m
, meta_p meta
);
102 static struct ng_type typestruct
= {
117 NETGRAPH_INIT(lmi
, &typestruct
);
120 * Info and status per node
123 node_p node
; /* netgraph node */
124 int flags
; /* state */
125 int poll_count
; /* the count of times for autolmi */
126 int poll_state
; /* state of auto detect machine */
127 u_char remote_seq
; /* sequence number the remote sent */
128 u_char local_seq
; /* last sequence number we sent */
129 u_char protoID
; /* 9 for group of 4, 8 otherwise */
130 u_long seq_retries
; /* sent this how many time so far */
131 struct callout timeout
; /* see timeout(9) */
136 hook_p lmi_channel
; /* whatever we ended up using */
140 hook_p lmi_channel0
; /* auto-detect on DLCI 0 */
141 hook_p lmi_channel1023
;/* auto-detect on DLCI 1023 */
142 char *protoname
; /* cache protocol name */
143 u_char dlci_state
[MAXDLCI
+ 1];
144 int invalidx
; /* next dlci's to invalidate */
146 typedef struct nglmi_softc
*sc_p
;
149 * Other internal functions
151 static void LMI_ticker(void *arg
);
152 static void nglmi_startup_fixed(sc_p sc
, hook_p hook
);
153 static void nglmi_startup_auto(sc_p sc
);
154 static void nglmi_startup(sc_p sc
);
155 static void nglmi_inquire(sc_p sc
, int full
);
156 static void ngauto_state_machine(sc_p sc
);
159 * Values for 'flags' field
160 * NB: the SCF_CONNECTED flag is set if and only if the timer is running.
162 #define SCF_CONNECTED 0x01 /* connected to something */
163 #define SCF_AUTO 0x02 /* we are auto-detecting */
164 #define SCF_FIXED 0x04 /* we are fixed from the start */
166 #define SCF_LMITYPE 0x18 /* mask for determining Annex mode */
167 #define SCF_NOLMI 0x00 /* no LMI type selected yet */
168 #define SCF_ANNEX_A 0x08 /* running annex A mode */
169 #define SCF_ANNEX_D 0x10 /* running annex D mode */
170 #define SCF_GROUP4 0x18 /* running group of 4 */
172 #define SETLMITYPE(sc, annex) \
174 (sc)->flags &= ~SCF_LMITYPE; \
175 (sc)->flags |= (annex); \
178 #define NOPROTO(sc) (((sc)->flags & SCF_LMITYPE) == SCF_NOLMI)
179 #define ANNEXA(sc) (((sc)->flags & SCF_LMITYPE) == SCF_ANNEX_A)
180 #define ANNEXD(sc) (((sc)->flags & SCF_LMITYPE) == SCF_ANNEX_D)
181 #define GROUP4(sc) (((sc)->flags & SCF_LMITYPE) == SCF_GROUP4)
183 #define LMIPOLLSIZE 3
184 #define LMI_PATIENCE 8 /* declare all DLCI DOWN after N LMI failures */
190 nglmi_constructor(node_p
*nodep
)
195 MALLOC(sc
, sc_p
, sizeof(*sc
), M_NETGRAPH
, M_NOWAIT
| M_ZERO
);
199 callout_init(&sc
->timeout
);
200 if ((error
= ng_make_node_common(&typestruct
, nodep
))) {
201 FREE(sc
, M_NETGRAPH
);
204 (*nodep
)->private = sc
;
205 sc
->protoname
= NAME_NONE
;
207 sc
->liv_per_full
= NG_LMI_SEQ_PER_FULL
; /* make this dynamic */
208 sc
->liv_rate
= NG_LMI_KEEPALIVE_RATE
;
213 * The LMI channel has a private pointer which is the same as the
214 * node private pointer. The debug channel has a NULL private pointer.
217 nglmi_newhook(node_p node
, hook_p hook
, const char *name
)
219 sc_p sc
= node
->private;
221 if (strcmp(name
, NG_LMI_HOOK_DEBUG
) == 0) {
222 hook
->private = NULL
;
225 if (sc
->flags
& SCF_CONNECTED
) {
226 /* already connected, return an error */
229 if (strcmp(name
, NG_LMI_HOOK_ANNEXA
) == 0) {
230 sc
->lmi_annexA
= hook
;
231 hook
->private = node
->private;
233 SETLMITYPE(sc
, SCF_ANNEX_A
);
234 sc
->protoname
= NAME_ANNEXA
;
235 nglmi_startup_fixed(sc
, hook
);
236 } else if (strcmp(name
, NG_LMI_HOOK_ANNEXD
) == 0) {
237 sc
->lmi_annexD
= hook
;
238 hook
->private = node
->private;
240 SETLMITYPE(sc
, SCF_ANNEX_D
);
241 sc
->protoname
= NAME_ANNEXD
;
242 nglmi_startup_fixed(sc
, hook
);
243 } else if (strcmp(name
, NG_LMI_HOOK_GROUPOF4
) == 0) {
244 sc
->lmi_group4
= hook
;
245 hook
->private = node
->private;
247 SETLMITYPE(sc
, SCF_GROUP4
);
248 sc
->protoname
= NAME_GROUP4
;
249 nglmi_startup_fixed(sc
, hook
);
250 } else if (strcmp(name
, NG_LMI_HOOK_AUTO0
) == 0) {
251 /* Note this, and if B is already installed, we're complete */
252 sc
->lmi_channel0
= hook
;
253 sc
->protoname
= NAME_NONE
;
254 hook
->private = node
->private;
255 if (sc
->lmi_channel1023
)
256 nglmi_startup_auto(sc
);
257 } else if (strcmp(name
, NG_LMI_HOOK_AUTO1023
) == 0) {
258 /* Note this, and if A is already installed, we're complete */
259 sc
->lmi_channel1023
= hook
;
260 sc
->protoname
= NAME_NONE
;
261 hook
->private = node
->private;
262 if (sc
->lmi_channel0
)
263 nglmi_startup_auto(sc
);
265 return (EINVAL
); /* unknown hook */
270 * We have just attached to a live (we hope) node.
271 * Fire out a LMI inquiry, and then start up the timers.
274 LMI_ticker(void *arg
)
279 if (sc
->flags
& SCF_AUTO
) {
280 ngauto_state_machine(sc
);
281 callout_reset(&sc
->timeout
, NG_LMI_POLL_RATE
* hz
,
284 if (sc
->livs
++ >= sc
->liv_per_full
) {
285 nglmi_inquire(sc
, 1);
286 /* sc->livs = 0; *//* do this when we get the answer! */
288 nglmi_inquire(sc
, 0);
290 callout_reset(&sc
->timeout
, sc
->liv_rate
* hz
, LMI_ticker
, sc
);
296 nglmi_startup_fixed(sc_p sc
, hook_p hook
)
298 sc
->flags
|= (SCF_FIXED
| SCF_CONNECTED
);
299 sc
->lmi_channel
= hook
;
304 nglmi_startup_auto(sc_p sc
)
306 sc
->flags
|= (SCF_AUTO
| SCF_CONNECTED
);
307 sc
->poll_state
= 0; /* reset state machine */
313 nglmi_startup(sc_p sc
)
318 sc
->livs
= sc
->liv_per_full
- 1;
319 /* start off the ticker in 1 sec */
320 callout_reset(&sc
->timeout
, hz
, LMI_ticker
, sc
);
325 nglmi_inquire(sc_p sc
, int full
)
332 if (sc
->lmi_channel
== NULL
)
334 MGETHDR(m
, MB_DONTWAIT
, MT_DATA
);
336 log(LOG_ERR
, "nglmi: unable to start up LMI processing\n");
339 m
->m_pkthdr
.rcvif
= NULL
;
340 /* Allocate a meta struct (and leave some slop for options to be
341 * added by other modules). */
342 /* MALLOC(meta, meta_p, sizeof( struct ng_meta) + META_PAD,
343 * M_NETGRAPH, M_NOWAIT); */
344 MALLOC(meta
, meta_p
, sizeof(*meta
) + META_PAD
, M_NETGRAPH
, M_NOWAIT
);
345 if (meta
!= NULL
) { /* if it failed, well, it was optional anyhow */
346 meta
->used_len
= (u_short
) sizeof(struct ng_meta
);
348 = (u_short
) sizeof(struct ng_meta
) + META_PAD
;
350 meta
->priority
= NG_LMI_LMI_PRIORITY
;
351 meta
->discardability
= -1;
353 m
->m_data
+= 4; /* leave some room for a header */
354 cptr
= start
= mtod(m
, char *);
355 /* add in the header for an LMI inquiry. */
356 *cptr
++ = 0x03; /* UI frame */
358 *cptr
++ = 0x09; /* proto discriminator */
360 *cptr
++ = 0x08; /* proto discriminator */
361 *cptr
++ = 0x00; /* call reference */
362 *cptr
++ = 0x75; /* inquiry */
364 /* If we are Annex-D, there is this extra thing.. */
366 *cptr
++ = 0x95; /* ??? */
367 /* Add a request type */
369 *cptr
++ = 0x51; /* report type */
371 *cptr
++ = 0x01; /* report type */
372 *cptr
++ = 0x01; /* size = 1 */
374 *cptr
++ = 0x00; /* full */
376 *cptr
++ = 0x01; /* partial */
378 /* Add a link verification IE */
380 *cptr
++ = 0x53; /* verification IE */
382 *cptr
++ = 0x03; /* verification IE */
383 *cptr
++ = 0x02; /* 2 extra bytes */
384 *cptr
++ = sc
->local_seq
;
385 *cptr
++ = sc
->remote_seq
;
389 m
->m_len
= m
->m_pkthdr
.len
= cptr
- start
;
390 NG_SEND_DATA(error
, sc
->lmi_channel
, m
, meta
);
392 /* If we've been sending requests for long enough, and there has
393 * been no response, then mark as DOWN, any DLCIs that are UP. */
394 if (sc
->seq_retries
== LMI_PATIENCE
) {
397 for (count
= 0; count
< MAXDLCI
; count
++)
398 if (sc
->dlci_state
[count
] == DLCI_UP
)
399 sc
->dlci_state
[count
] = DLCI_DOWN
;
404 * State machine for LMI auto-detect. The transitions are ordered
405 * to try the more likely possibilities first.
408 ngauto_state_machine(sc_p sc
)
410 if ((sc
->poll_count
<= 0) || (sc
->poll_count
> LMIPOLLSIZE
)) {
411 /* time to change states in the auto probe machine */
412 /* capture wild values of poll_count while we are at it */
413 sc
->poll_count
= LMIPOLLSIZE
;
416 switch (sc
->poll_state
) {
418 log(LOG_WARNING
, "nglmi: no response from exchange\n");
419 default: /* capture bad states */
422 sc
->lmi_channel
= sc
->lmi_channel0
;
423 SETLMITYPE(sc
, SCF_ANNEX_D
);
426 sc
->lmi_channel
= sc
->lmi_channel1023
;
427 SETLMITYPE(sc
, SCF_ANNEX_D
);
430 sc
->lmi_channel
= sc
->lmi_channel0
;
431 SETLMITYPE(sc
, SCF_ANNEX_A
);
434 sc
->lmi_channel
= sc
->lmi_channel1023
;
435 SETLMITYPE(sc
, SCF_GROUP4
);
438 sc
->lmi_channel
= sc
->lmi_channel1023
;
439 SETLMITYPE(sc
, SCF_ANNEX_A
);
442 sc
->lmi_channel
= sc
->lmi_channel0
;
443 SETLMITYPE(sc
, SCF_GROUP4
);
447 /* send an inquirey encoded appropriatly */
448 nglmi_inquire(sc
, 0);
453 * Receive a netgraph control message.
456 nglmi_rcvmsg(node_p node
, struct ng_mesg
*msg
, const char *retaddr
,
457 struct ng_mesg
**resp
)
460 sc_p sc
= node
->private;
462 switch (msg
->header
.typecookie
) {
463 case NGM_GENERIC_COOKIE
:
464 switch (msg
->header
.cmd
) {
465 case NGM_TEXT_STATUS
:
470 NG_MKRESPONSE(*resp
, msg
, NG_TEXTRESPONSE
, M_NOWAIT
);
476 pos
= ksprintf(arg
, "protocol %s ", sc
->protoname
);
477 if (sc
->flags
& SCF_FIXED
)
478 pos
+= ksprintf(arg
+ pos
, "fixed\n");
479 else if (sc
->flags
& SCF_AUTO
)
480 pos
+= ksprintf(arg
+ pos
, "auto-detecting\n");
482 pos
+= ksprintf(arg
+ pos
, "auto on dlci %d\n",
483 (sc
->lmi_channel
== sc
->lmi_channel0
) ?
485 pos
+= ksprintf(arg
+ pos
,
486 "keepalive period: %d seconds\n", sc
->liv_rate
);
487 pos
+= ksprintf(arg
+ pos
,
488 "unacknowledged keepalives: %ld\n",
492 && (pos
< (NG_TEXTRESPONSE
- 20)));
494 if (sc
->dlci_state
[count
]) {
495 pos
+= ksprintf(arg
+ pos
,
496 "dlci %d %s\n", count
,
497 (sc
->dlci_state
[count
]
498 == DLCI_UP
) ? "up" : "down");
501 (*resp
)->header
.arglen
= pos
+ 1;
510 switch (msg
->header
.cmd
) {
511 case NGM_LMI_GET_STATUS
:
513 struct nglmistat
*stat
;
516 NG_MKRESPONSE(*resp
, msg
, sizeof(*stat
), M_NOWAIT
);
521 stat
= (struct nglmistat
*) (*resp
)->data
;
523 sc
->protoname
, sizeof(stat
->proto
) - 1);
525 sc
->protoname
, sizeof(stat
->hook
) - 1);
526 stat
->autod
= !!(sc
->flags
& SCF_AUTO
);
527 stat
->fixed
= !!(sc
->flags
& SCF_FIXED
);
528 for (k
= 0; k
<= MAXDLCI
; k
++) {
529 switch (sc
->dlci_state
[k
]) {
531 stat
->up
[k
/ 8] |= (1 << (k
% 8));
534 stat
->seen
[k
/ 8] |= (1 << (k
% 8));
549 FREE(msg
, M_NETGRAPH
);
553 #define STEPBY(stepsize) \
555 packetlen -= (stepsize); \
556 data += (stepsize); \
560 * receive data, and use it to update our status.
561 * Anything coming in on the debug port is discarded.
564 nglmi_rcvdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
566 sc_p sc
= hook
->node
->private;
570 int resptype_seen
= 0;
573 if (hook
->private == NULL
) {
576 packetlen
= m
->m_hdr
.mh_len
;
578 /* XXX what if it's more than 1 mbuf? */
579 if ((packetlen
> MHLEN
) && !(m
->m_flags
& M_EXT
)) {
580 log(LOG_WARNING
, "nglmi: packetlen (%d) too big\n", packetlen
);
583 if (m
->m_len
< packetlen
&& (m
= m_pullup(m
, packetlen
)) == NULL
) {
585 "nglmi: m_pullup failed for %d bytes\n", packetlen
);
589 if (nglmi_checkdata(hook
, m
, meta
) == 0)
592 /* pass the first 4 bytes (already checked in the nglmi_checkdata()) */
593 data
= mtod(m
, const u_char
*);
596 /* Now check if there is a 'locking shift'. This is only seen in
597 * Annex D frames. don't bother checking, we already did that. Don't
598 * increment immediatly as it might not be there. */
602 /* If we get this far we should consider that it is a legitimate
603 * frame and we know what it is. */
604 if (sc
->flags
& SCF_AUTO
) {
605 /* note the hook that this valid channel came from and drop
606 * out of auto probe mode. */
608 sc
->protoname
= NAME_ANNEXA
;
610 sc
->protoname
= NAME_ANNEXD
;
612 sc
->protoname
= NAME_GROUP4
;
614 log(LOG_ERR
, "nglmi: No known type\n");
617 sc
->lmi_channel
= hook
;
618 sc
->flags
&= ~SCF_AUTO
;
619 log(LOG_INFO
, "nglmi: auto-detected %s LMI on DLCI %d\n",
620 sc
->protoname
, hook
== sc
->lmi_channel0
? 0 : 1023);
623 /* While there is more data in the status packet, keep processing
624 * status items. First make sure there is enough data for the
625 * segment descriptor's length field. */
626 while (packetlen
>= 2) {
627 u_int segtype
= data
[0];
628 u_int segsize
= data
[1];
630 /* Now that we know how long it claims to be, make sure
631 * there is enough data for the next seg. */
632 if (packetlen
< segsize
+ 2)
638 log(LOG_WARNING
, "nglmi: dup MSGTYPE\n");
642 /* The remote end tells us what kind of response
643 * this is. Only expect a type 0 or 1. if we are a
644 * full status, invalidate a few DLCIs just to see
645 * that they are still ok. */
650 /* partial status, do no extra processing */
655 int idx
= sc
->invalidx
;
657 for (count
= 0; count
< 10; count
++) {
660 if (sc
->dlci_state
[idx
] == DLCI_UP
)
661 sc
->dlci_state
[idx
] = DLCI_DOWN
;
665 /* we got and we wanted one. relax
666 * now.. but don't reset to 0 if it
667 * was unrequested. */
668 if (sc
->livs
> sc
->liv_per_full
)
676 /* The remote tells us what it thinks the sequence
677 * numbers are. If it's not size 2, it must be a
678 * duplicate to have gotten this far, skip it. */
679 if (seq_seen
!= 0) /* already seen seq numbers */
683 sc
->remote_seq
= data
[2];
684 if (sc
->local_seq
== data
[3]) {
687 /* Note that all 3 Frame protocols seem to
688 * not like 0 as a sequence number. */
689 if (sc
->local_seq
== 0)
695 /* The remote tells us about a DLCI that it knows
696 * about. There may be many of these in a single
699 case 6:/* only on 'group of 4' */
700 dlci
= ((u_short
) data
[2] & 0xff) << 8;
701 dlci
|= (data
[3] & 0xff);
702 if ((dlci
< 1024) && (dlci
> 0)) {
707 dlci
= ((u_short
) data
[2] & 0x3f) << 4;
708 dlci
|= ((data
[3] & 0x78) >> 3);
709 if ((dlci
< 1024) && (dlci
> 0)) {
710 /* set up the bottom half of the
711 * support for that dlci if it's not
712 * already been done */
713 /* store this information somewhere */
719 if (sc
->dlci_state
[dlci
] != DLCI_UP
) {
720 /* bring new DLCI to life */
721 /* may do more here some day */
722 if (sc
->dlci_state
[dlci
] != DLCI_DOWN
)
724 "nglmi: DLCI %d became active\n",
726 sc
->dlci_state
[dlci
] = DLCI_UP
;
733 NG_FREE_DATA(m
, meta
);
737 NG_FREE_DATA(m
, meta
);
742 * Check that a packet is entirely kosha.
743 * return 1 of ok, and 0 if not.
744 * All data is discarded if a 0 is returned.
747 nglmi_checkdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
749 sc_p sc
= hook
->node
->private;
756 int resptype_seen
= 0; /* 0 , 1 (partial) or 2 (full) */
757 int highest_dlci
= 0;
759 packetlen
= m
->m_hdr
.mh_len
;
760 data
= mtod(m
, const u_char
*);
762 log(LOG_WARNING
, "nglmi: unexpected value in LMI(%d)\n", 1);
767 /* look at the protocol ID */
769 if (sc
->flags
& SCF_AUTO
) {
770 SETLMITYPE(sc
, SCF_NOLMI
); /* start with a clean slate */
776 SETLMITYPE(sc
, SCF_GROUP4
);
780 log(LOG_WARNING
, "nglmi: bad Protocol ID(%d)\n",
785 if (nextbyte
!= sc
->protoID
) {
786 log(LOG_WARNING
, "nglmi: unexpected Protocol ID(%d)\n",
793 /* check call reference (always null in non ISDN frame relay) */
795 log(LOG_WARNING
, "nglmi: unexpected Call Reference (0x%x)\n",
801 /* check message type */
802 switch ((type
= *data
)) {
803 case 0x75: /* Status enquiry */
804 log(LOG_WARNING
, "nglmi: unexpected message type(0x%x)\n",
807 case 0x7D: /* Status message */
811 "nglmi: unexpected msg type(0x%x) \n", (int) type
);
816 /* Now check if there is a 'locking shift'. This is only seen in
817 * Annex D frames. Don't increment immediately as it might not be
820 if (sc
->flags
& SCF_AUTO
) {
822 if (nextbyte
== 0x95) {
823 SETLMITYPE(sc
, SCF_ANNEX_D
);
826 SETLMITYPE(sc
, SCF_ANNEX_A
);
827 } else if (nextbyte
== 0x95) {
828 log(LOG_WARNING
, "nglmi: locking shift seen in G4\n");
837 "nglmi: locking shift missing\n");
840 } else if (*data
== 0x95) {
841 log(LOG_WARNING
, "nglmi: locking shift seen\n");
846 /* While there is more data in the status packet, keep processing
847 * status items. First make sure there is enough data for the
848 * segment descriptor's length field. */
849 while (packetlen
>= 2) {
850 u_int segtype
= data
[0];
851 u_int segsize
= data
[1];
853 /* Now that we know how long it claims to be, make sure
854 * there is enough data for the next seg. */
855 if (packetlen
< (segsize
+ 2)) {
856 log(LOG_WARNING
, "nglmi: IE longer than packet\n");
862 /* According to MCI's HP analyser, we should just
863 * ignore if there is mor ethan one of these (?). */
865 log(LOG_WARNING
, "nglmi: dup MSGTYPE\n");
869 log(LOG_WARNING
, "nglmi: MSGTYPE wrong size\n");
872 /* The remote end tells us what kind of response
873 * this is. Only expect a type 0 or 1. if it was a
874 * full (type 0) check we just asked for a type
878 if (sc
->livs
> sc
->liv_per_full
) {
880 "nglmi: LIV when FULL expected\n");
881 goto reject
; /* need full */
886 /* Full response is always acceptable */
891 "nglmi: Unknown report type %d\n", data
[2]);
897 /* The remote tells us what it thinks the sequence
898 * numbers are. I would have thought that there
899 * needs to be one and only one of these, but MCI
900 * want us to just ignore extras. (?) */
901 if (resptype_seen
== 0) {
902 log(LOG_WARNING
, "nglmi: no TYPE before SEQ\n");
905 if (seq_seen
!= 0) /* already seen seq numbers */
908 log(LOG_WARNING
, "nglmi: bad SEQ sts size\n");
911 if (sc
->local_seq
!= data
[3]) {
912 log(LOG_WARNING
, "nglmi: unexpected SEQ\n");
919 /* The remote tells us about a DLCI that it knows
920 * about. There may be many of these in a single
922 if (seq_seen
!= 1) { /* already seen seq numbers? */
924 "nglmi: No sequence before DLCI\n");
927 if (resptype_seen
!= 2) { /* must be full */
929 "nglmi: No resp type before DLCI\n");
935 "nglmi: wrong IE segsize\n");
938 dlci
= ((u_short
) data
[2] & 0xff) << 8;
939 dlci
|= (data
[3] & 0xff);
943 "nglmi: DLCI headersize of %d"
944 " not supported\n", segsize
- 1);
947 dlci
= ((u_short
) data
[2] & 0x3f) << 4;
948 dlci
|= ((data
[3] & 0x78) >> 3);
950 /* async can only have one of these */
951 #if 0 /* async not yet accepted */
952 if (async
&& highest_dlci
) {
954 "nglmi: Async with > 1 DLCI\n");
958 /* Annex D says these will always be Ascending, but
959 * the HP test for G4 says we should accept
960 * duplicates, so for now allow that. ( <= vs. < ) */
962 /* MCI tests want us to accept out of order for AnxD */
963 if ((!GROUP4(sc
)) && (dlci
< highest_dlci
)) {
964 /* duplicate or mis-ordered dlci */
965 /* (spec says they will increase in number) */
966 log(LOG_WARNING
, "nglmi: DLCI out of order\n");
971 log(LOG_WARNING
, "nglmi: DLCI out of range\n");
978 "nglmi: unknown LMI segment type %d\n", segtype
);
983 if (packetlen
!= 0) { /* partial junk at end? */
985 "nglmi: %d bytes extra at end of packet\n", packetlen
);
988 if (resptype_seen
== 0) {
989 log(LOG_WARNING
, "nglmi: No response type seen\n");
990 goto reject
; /* had no response type */
993 log(LOG_WARNING
, "nglmi: No sequence numbers seen\n");
994 goto reject
; /* had no sequence numbers */
1003 const u_char
*bp
= mtod(m
, const u_char
*);
1006 loc
= (m
->m_hdr
.mh_len
- packetlen
);
1007 log(LOG_WARNING
, "nglmi: error at location %d\n", loc
);
1008 while (k
< m
->m_hdr
.mh_len
) {
1011 while ((j
++ < 16) && k
< m
->m_hdr
.mh_len
) {
1012 pos
+= ksprintf(buf
+ pos
, "%c%02x",
1013 ((loc
== k
) ? '>' : ' '),
1018 log(LOG_WARNING
, "nglmi: packet data:%s\n", buf
);
1020 log(LOG_WARNING
, "%04d :%s\n", k
, buf
);
1030 const u_char
*bp
= mtod(m
, const u_char
*);
1033 loc
= (m
->m_hdr
.mh_len
- packetlen
);
1034 log(LOG_WARNING
, "nglmi: error at location %d\n", loc
);
1035 while (k
< m
->m_hdr
.mh_len
) {
1038 while ((j
++ < 16) && k
< m
->m_hdr
.mh_len
) {
1039 pos
+= ksprintf(buf
+ pos
, "%c%02x",
1040 ((loc
== k
) ? '>' : ' '),
1045 log(LOG_WARNING
, "nglmi: packet data:%s\n", buf
);
1047 log(LOG_WARNING
, "%04d :%s\n", k
, buf
);
1051 NG_FREE_DATA(m
, meta
);
1056 * Do local shutdown processing..
1057 * Cut any remaining links and free our local resources.
1060 nglmi_rmnode(node_p node
)
1062 const sc_p sc
= node
->private;
1064 node
->flags
|= NG_INVALID
;
1067 node
->private = NULL
;
1069 FREE(sc
, M_NETGRAPH
);
1074 * Hook disconnection
1075 * For this type, removal of any link except "debug" destroys the node.
1078 nglmi_disconnect(hook_p hook
)
1080 const sc_p sc
= hook
->node
->private;
1082 /* OK to remove debug hook(s) */
1083 if (hook
->private == NULL
)
1086 /* Stop timer if it's currently active */
1087 if (sc
->flags
& SCF_CONNECTED
)
1088 callout_stop(&sc
->timeout
);
1091 ng_rmnode(hook
->node
);