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.7 2006/12/20 18:14:43 dillon 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);
198 bzero(sc, sizeof(*sc));
200 callout_init(&sc->timeout);
201 if ((error = ng_make_node_common(&typestruct, nodep))) {
202 FREE(sc, M_NETGRAPH);
205 (*nodep)->private = sc;
206 sc->protoname = NAME_NONE;
208 sc->liv_per_full = NG_LMI_SEQ_PER_FULL; /* make this dynamic */
209 sc->liv_rate = NG_LMI_KEEPALIVE_RATE;
214 * The LMI channel has a private pointer which is the same as the
215 * node private pointer. The debug channel has a NULL private pointer.
218 nglmi_newhook(node_p node, hook_p hook, const char *name)
220 sc_p sc = node->private;
222 if (strcmp(name, NG_LMI_HOOK_DEBUG) == 0) {
223 hook->private = NULL;
226 if (sc->flags & SCF_CONNECTED) {
227 /* already connected, return an error */
230 if (strcmp(name, NG_LMI_HOOK_ANNEXA) == 0) {
231 sc->lmi_annexA = hook;
232 hook->private = node->private;
234 SETLMITYPE(sc, SCF_ANNEX_A);
235 sc->protoname = NAME_ANNEXA;
236 nglmi_startup_fixed(sc, hook);
237 } else if (strcmp(name, NG_LMI_HOOK_ANNEXD) == 0) {
238 sc->lmi_annexD = hook;
239 hook->private = node->private;
241 SETLMITYPE(sc, SCF_ANNEX_D);
242 sc->protoname = NAME_ANNEXD;
243 nglmi_startup_fixed(sc, hook);
244 } else if (strcmp(name, NG_LMI_HOOK_GROUPOF4) == 0) {
245 sc->lmi_group4 = hook;
246 hook->private = node->private;
248 SETLMITYPE(sc, SCF_GROUP4);
249 sc->protoname = NAME_GROUP4;
250 nglmi_startup_fixed(sc, hook);
251 } else if (strcmp(name, NG_LMI_HOOK_AUTO0) == 0) {
252 /* Note this, and if B is already installed, we're complete */
253 sc->lmi_channel0 = hook;
254 sc->protoname = NAME_NONE;
255 hook->private = node->private;
256 if (sc->lmi_channel1023)
257 nglmi_startup_auto(sc);
258 } else if (strcmp(name, NG_LMI_HOOK_AUTO1023) == 0) {
259 /* Note this, and if A is already installed, we're complete */
260 sc->lmi_channel1023 = hook;
261 sc->protoname = NAME_NONE;
262 hook->private = node->private;
263 if (sc->lmi_channel0)
264 nglmi_startup_auto(sc);
266 return (EINVAL); /* unknown hook */
271 * We have just attached to a live (we hope) node.
272 * Fire out a LMI inquiry, and then start up the timers.
275 LMI_ticker(void *arg)
280 if (sc->flags & SCF_AUTO) {
281 ngauto_state_machine(sc);
282 callout_reset(&sc->timeout, NG_LMI_POLL_RATE * hz,
285 if (sc->livs++ >= sc->liv_per_full) {
286 nglmi_inquire(sc, 1);
287 /* sc->livs = 0; *//* do this when we get the answer! */
289 nglmi_inquire(sc, 0);
291 callout_reset(&sc->timeout, sc->liv_rate * hz, LMI_ticker, sc);
297 nglmi_startup_fixed(sc_p sc, hook_p hook)
299 sc->flags |= (SCF_FIXED | SCF_CONNECTED);
300 sc->lmi_channel = hook;
305 nglmi_startup_auto(sc_p sc)
307 sc->flags |= (SCF_AUTO | SCF_CONNECTED);
308 sc->poll_state = 0; /* reset state machine */
314 nglmi_startup(sc_p sc)
319 sc->livs = sc->liv_per_full - 1;
320 /* start off the ticker in 1 sec */
321 callout_reset(&sc->timeout, hz, LMI_ticker, sc);
326 nglmi_inquire(sc_p sc, int full)
333 if (sc->lmi_channel == NULL)
335 MGETHDR(m, MB_DONTWAIT, MT_DATA);
337 log(LOG_ERR, "nglmi: unable to start up LMI processing\n");
340 m->m_pkthdr.rcvif = NULL;
341 /* Allocate a meta struct (and leave some slop for options to be
342 * added by other modules). */
343 /* MALLOC(meta, meta_p, sizeof( struct ng_meta) + META_PAD,
344 * M_NETGRAPH, M_NOWAIT); */
345 MALLOC(meta, meta_p, sizeof(*meta) + META_PAD, M_NETGRAPH, M_NOWAIT);
346 if (meta != NULL) { /* if it failed, well, it was optional anyhow */
347 meta->used_len = (u_short) sizeof(struct ng_meta);
349 = (u_short) sizeof(struct ng_meta) + META_PAD;
351 meta->priority = NG_LMI_LMI_PRIORITY;
352 meta->discardability = -1;
354 m->m_data += 4; /* leave some room for a header */
355 cptr = start = mtod(m, char *);
356 /* add in the header for an LMI inquiry. */
357 *cptr++ = 0x03; /* UI frame */
359 *cptr++ = 0x09; /* proto discriminator */
361 *cptr++ = 0x08; /* proto discriminator */
362 *cptr++ = 0x00; /* call reference */
363 *cptr++ = 0x75; /* inquiry */
365 /* If we are Annex-D, there is this extra thing.. */
367 *cptr++ = 0x95; /* ??? */
368 /* Add a request type */
370 *cptr++ = 0x51; /* report type */
372 *cptr++ = 0x01; /* report type */
373 *cptr++ = 0x01; /* size = 1 */
375 *cptr++ = 0x00; /* full */
377 *cptr++ = 0x01; /* partial */
379 /* Add a link verification IE */
381 *cptr++ = 0x53; /* verification IE */
383 *cptr++ = 0x03; /* verification IE */
384 *cptr++ = 0x02; /* 2 extra bytes */
385 *cptr++ = sc->local_seq;
386 *cptr++ = sc->remote_seq;
390 m->m_len = m->m_pkthdr.len = cptr - start;
391 NG_SEND_DATA(error, sc->lmi_channel, m, meta);
393 /* If we've been sending requests for long enough, and there has
394 * been no response, then mark as DOWN, any DLCIs that are UP. */
395 if (sc->seq_retries == LMI_PATIENCE) {
398 for (count = 0; count < MAXDLCI; count++)
399 if (sc->dlci_state[count] == DLCI_UP)
400 sc->dlci_state[count] = DLCI_DOWN;
405 * State machine for LMI auto-detect. The transitions are ordered
406 * to try the more likely possibilities first.
409 ngauto_state_machine(sc_p sc)
411 if ((sc->poll_count <= 0) || (sc->poll_count > LMIPOLLSIZE)) {
412 /* time to change states in the auto probe machine */
413 /* capture wild values of poll_count while we are at it */
414 sc->poll_count = LMIPOLLSIZE;
417 switch (sc->poll_state) {
419 log(LOG_WARNING, "nglmi: no response from exchange\n");
420 default: /* capture bad states */
423 sc->lmi_channel = sc->lmi_channel0;
424 SETLMITYPE(sc, SCF_ANNEX_D);
427 sc->lmi_channel = sc->lmi_channel1023;
428 SETLMITYPE(sc, SCF_ANNEX_D);
431 sc->lmi_channel = sc->lmi_channel0;
432 SETLMITYPE(sc, SCF_ANNEX_A);
435 sc->lmi_channel = sc->lmi_channel1023;
436 SETLMITYPE(sc, SCF_GROUP4);
439 sc->lmi_channel = sc->lmi_channel1023;
440 SETLMITYPE(sc, SCF_ANNEX_A);
443 sc->lmi_channel = sc->lmi_channel0;
444 SETLMITYPE(sc, SCF_GROUP4);
448 /* send an inquirey encoded appropriatly */
449 nglmi_inquire(sc, 0);
454 * Receive a netgraph control message.
457 nglmi_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
458 struct ng_mesg **resp)
461 sc_p sc = node->private;
463 switch (msg->header.typecookie) {
464 case NGM_GENERIC_COOKIE:
465 switch (msg->header.cmd) {
466 case NGM_TEXT_STATUS:
471 NG_MKRESPONSE(*resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
477 pos = ksprintf(arg, "protocol %s ", sc->protoname);
478 if (sc->flags & SCF_FIXED)
479 pos += ksprintf(arg + pos, "fixed\n");
480 else if (sc->flags & SCF_AUTO)
481 pos += ksprintf(arg + pos, "auto-detecting\n");
483 pos += ksprintf(arg + pos, "auto on dlci %d\n",
484 (sc->lmi_channel == sc->lmi_channel0) ?
486 pos += ksprintf(arg + pos,
487 "keepalive period: %d seconds\n", sc->liv_rate);
488 pos += ksprintf(arg + pos,
489 "unacknowledged keepalives: %ld\n",
493 && (pos < (NG_TEXTRESPONSE - 20)));
495 if (sc->dlci_state[count]) {
496 pos += ksprintf(arg + pos,
497 "dlci %d %s\n", count,
498 (sc->dlci_state[count]
499 == DLCI_UP) ? "up" : "down");
502 (*resp)->header.arglen = pos + 1;
511 switch (msg->header.cmd) {
512 case NGM_LMI_GET_STATUS:
514 struct nglmistat *stat;
517 NG_MKRESPONSE(*resp, msg, sizeof(*stat), M_NOWAIT);
522 stat = (struct nglmistat *) (*resp)->data;
524 sc->protoname, sizeof(stat->proto) - 1);
526 sc->protoname, sizeof(stat->hook) - 1);
527 stat->autod = !!(sc->flags & SCF_AUTO);
528 stat->fixed = !!(sc->flags & SCF_FIXED);
529 for (k = 0; k <= MAXDLCI; k++) {
530 switch (sc->dlci_state[k]) {
532 stat->up[k / 8] |= (1 << (k % 8));
535 stat->seen[k / 8] |= (1 << (k % 8));
550 FREE(msg, M_NETGRAPH);
554 #define STEPBY(stepsize) \
556 packetlen -= (stepsize); \
557 data += (stepsize); \
561 * receive data, and use it to update our status.
562 * Anything coming in on the debug port is discarded.
565 nglmi_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
567 sc_p sc = hook->node->private;
571 int resptype_seen = 0;
574 if (hook->private == NULL) {
577 packetlen = m->m_hdr.mh_len;
579 /* XXX what if it's more than 1 mbuf? */
580 if ((packetlen > MHLEN) && !(m->m_flags & M_EXT)) {
581 log(LOG_WARNING, "nglmi: packetlen (%d) too big\n", packetlen);
584 if (m->m_len < packetlen && (m = m_pullup(m, packetlen)) == NULL) {
586 "nglmi: m_pullup failed for %d bytes\n", packetlen);
590 if (nglmi_checkdata(hook, m, meta) == 0)
593 /* pass the first 4 bytes (already checked in the nglmi_checkdata()) */
594 data = mtod(m, const u_char *);
597 /* Now check if there is a 'locking shift'. This is only seen in
598 * Annex D frames. don't bother checking, we already did that. Don't
599 * increment immediatly as it might not be there. */
603 /* If we get this far we should consider that it is a legitimate
604 * frame and we know what it is. */
605 if (sc->flags & SCF_AUTO) {
606 /* note the hook that this valid channel came from and drop
607 * out of auto probe mode. */
609 sc->protoname = NAME_ANNEXA;
611 sc->protoname = NAME_ANNEXD;
613 sc->protoname = NAME_GROUP4;
615 log(LOG_ERR, "nglmi: No known type\n");
618 sc->lmi_channel = hook;
619 sc->flags &= ~SCF_AUTO;
620 log(LOG_INFO, "nglmi: auto-detected %s LMI on DLCI %d\n",
621 sc->protoname, hook == sc->lmi_channel0 ? 0 : 1023);
624 /* While there is more data in the status packet, keep processing
625 * status items. First make sure there is enough data for the
626 * segment descriptor's length field. */
627 while (packetlen >= 2) {
628 u_int segtype = data[0];
629 u_int segsize = data[1];
631 /* Now that we know how long it claims to be, make sure
632 * there is enough data for the next seg. */
633 if (packetlen < segsize + 2)
639 log(LOG_WARNING, "nglmi: dup MSGTYPE\n");
643 /* The remote end tells us what kind of response
644 * this is. Only expect a type 0 or 1. if we are a
645 * full status, invalidate a few DLCIs just to see
646 * that they are still ok. */
651 /* partial status, do no extra processing */
656 int idx = sc->invalidx;
658 for (count = 0; count < 10; count++) {
661 if (sc->dlci_state[idx] == DLCI_UP)
662 sc->dlci_state[idx] = DLCI_DOWN;
666 /* we got and we wanted one. relax
667 * now.. but don't reset to 0 if it
668 * was unrequested. */
669 if (sc->livs > sc->liv_per_full)
677 /* The remote tells us what it thinks the sequence
678 * numbers are. If it's not size 2, it must be a
679 * duplicate to have gotten this far, skip it. */
680 if (seq_seen != 0) /* already seen seq numbers */
684 sc->remote_seq = data[2];
685 if (sc->local_seq == data[3]) {
688 /* Note that all 3 Frame protocols seem to
689 * not like 0 as a sequence number. */
690 if (sc->local_seq == 0)
696 /* The remote tells us about a DLCI that it knows
697 * about. There may be many of these in a single
700 case 6:/* only on 'group of 4' */
701 dlci = ((u_short) data[2] & 0xff) << 8;
702 dlci |= (data[3] & 0xff);
703 if ((dlci < 1024) && (dlci > 0)) {
708 dlci = ((u_short) data[2] & 0x3f) << 4;
709 dlci |= ((data[3] & 0x78) >> 3);
710 if ((dlci < 1024) && (dlci > 0)) {
711 /* set up the bottom half of the
712 * support for that dlci if it's not
713 * already been done */
714 /* store this information somewhere */
720 if (sc->dlci_state[dlci] != DLCI_UP) {
721 /* bring new DLCI to life */
722 /* may do more here some day */
723 if (sc->dlci_state[dlci] != DLCI_DOWN)
725 "nglmi: DLCI %d became active\n",
727 sc->dlci_state[dlci] = DLCI_UP;
734 NG_FREE_DATA(m, meta);
738 NG_FREE_DATA(m, meta);
743 * Check that a packet is entirely kosha.
744 * return 1 of ok, and 0 if not.
745 * All data is discarded if a 0 is returned.
748 nglmi_checkdata(hook_p hook, struct mbuf *m, meta_p meta)
750 sc_p sc = hook->node->private;
757 int resptype_seen = 0; /* 0 , 1 (partial) or 2 (full) */
758 int highest_dlci = 0;
760 packetlen = m->m_hdr.mh_len;
761 data = mtod(m, const u_char *);
763 log(LOG_WARNING, "nglmi: unexpected value in LMI(%d)\n", 1);
768 /* look at the protocol ID */
770 if (sc->flags & SCF_AUTO) {
771 SETLMITYPE(sc, SCF_NOLMI); /* start with a clean slate */
777 SETLMITYPE(sc, SCF_GROUP4);
781 log(LOG_WARNING, "nglmi: bad Protocol ID(%d)\n",
786 if (nextbyte != sc->protoID) {
787 log(LOG_WARNING, "nglmi: unexpected Protocol ID(%d)\n",
794 /* check call reference (always null in non ISDN frame relay) */
796 log(LOG_WARNING, "nglmi: unexpected Call Reference (0x%x)\n",
802 /* check message type */
803 switch ((type = *data)) {
804 case 0x75: /* Status enquiry */
805 log(LOG_WARNING, "nglmi: unexpected message type(0x%x)\n",
808 case 0x7D: /* Status message */
812 "nglmi: unexpected msg type(0x%x) \n", (int) type);
817 /* Now check if there is a 'locking shift'. This is only seen in
818 * Annex D frames. Don't increment immediately as it might not be
821 if (sc->flags & SCF_AUTO) {
823 if (nextbyte == 0x95) {
824 SETLMITYPE(sc, SCF_ANNEX_D);
827 SETLMITYPE(sc, SCF_ANNEX_A);
828 } else if (nextbyte == 0x95) {
829 log(LOG_WARNING, "nglmi: locking shift seen in G4\n");
838 "nglmi: locking shift missing\n");
841 } else if (*data == 0x95) {
842 log(LOG_WARNING, "nglmi: locking shift seen\n");
847 /* While there is more data in the status packet, keep processing
848 * status items. First make sure there is enough data for the
849 * segment descriptor's length field. */
850 while (packetlen >= 2) {
851 u_int segtype = data[0];
852 u_int segsize = data[1];
854 /* Now that we know how long it claims to be, make sure
855 * there is enough data for the next seg. */
856 if (packetlen < (segsize + 2)) {
857 log(LOG_WARNING, "nglmi: IE longer than packet\n");
863 /* According to MCI's HP analyser, we should just
864 * ignore if there is mor ethan one of these (?). */
866 log(LOG_WARNING, "nglmi: dup MSGTYPE\n");
870 log(LOG_WARNING, "nglmi: MSGTYPE wrong size\n");
873 /* The remote end tells us what kind of response
874 * this is. Only expect a type 0 or 1. if it was a
875 * full (type 0) check we just asked for a type
879 if (sc->livs > sc->liv_per_full) {
881 "nglmi: LIV when FULL expected\n");
882 goto reject; /* need full */
887 /* Full response is always acceptable */
892 "nglmi: Unknown report type %d\n", data[2]);
898 /* The remote tells us what it thinks the sequence
899 * numbers are. I would have thought that there
900 * needs to be one and only one of these, but MCI
901 * want us to just ignore extras. (?) */
902 if (resptype_seen == 0) {
903 log(LOG_WARNING, "nglmi: no TYPE before SEQ\n");
906 if (seq_seen != 0) /* already seen seq numbers */
909 log(LOG_WARNING, "nglmi: bad SEQ sts size\n");
912 if (sc->local_seq != data[3]) {
913 log(LOG_WARNING, "nglmi: unexpected SEQ\n");
920 /* The remote tells us about a DLCI that it knows
921 * about. There may be many of these in a single
923 if (seq_seen != 1) { /* already seen seq numbers? */
925 "nglmi: No sequence before DLCI\n");
928 if (resptype_seen != 2) { /* must be full */
930 "nglmi: No resp type before DLCI\n");
936 "nglmi: wrong IE segsize\n");
939 dlci = ((u_short) data[2] & 0xff) << 8;
940 dlci |= (data[3] & 0xff);
944 "nglmi: DLCI headersize of %d"
945 " not supported\n", segsize - 1);
948 dlci = ((u_short) data[2] & 0x3f) << 4;
949 dlci |= ((data[3] & 0x78) >> 3);
951 /* async can only have one of these */
952 #if 0 /* async not yet accepted */
953 if (async && highest_dlci) {
955 "nglmi: Async with > 1 DLCI\n");
959 /* Annex D says these will always be Ascending, but
960 * the HP test for G4 says we should accept
961 * duplicates, so for now allow that. ( <= vs. < ) */
963 /* MCI tests want us to accept out of order for AnxD */
964 if ((!GROUP4(sc)) && (dlci < highest_dlci)) {
965 /* duplicate or mis-ordered dlci */
966 /* (spec says they will increase in number) */
967 log(LOG_WARNING, "nglmi: DLCI out of order\n");
972 log(LOG_WARNING, "nglmi: DLCI out of range\n");
979 "nglmi: unknown LMI segment type %d\n", segtype);
984 if (packetlen != 0) { /* partial junk at end? */
986 "nglmi: %d bytes extra at end of packet\n", packetlen);
989 if (resptype_seen == 0) {
990 log(LOG_WARNING, "nglmi: No response type seen\n");
991 goto reject; /* had no response type */
994 log(LOG_WARNING, "nglmi: No sequence numbers seen\n");
995 goto reject; /* had no sequence numbers */
1004 const u_char *bp = mtod(m, const u_char *);
1007 loc = (m->m_hdr.mh_len - packetlen);
1008 log(LOG_WARNING, "nglmi: error at location %d\n", loc);
1009 while (k < m->m_hdr.mh_len) {
1012 while ((j++ < 16) && k < m->m_hdr.mh_len) {
1013 pos += ksprintf(buf + pos, "%c%02x",
1014 ((loc == k) ? '>' : ' '),
1019 log(LOG_WARNING, "nglmi: packet data:%s\n", buf);
1021 log(LOG_WARNING, "%04d :%s\n", k, buf);
1031 const u_char *bp = mtod(m, const u_char *);
1034 loc = (m->m_hdr.mh_len - packetlen);
1035 log(LOG_WARNING, "nglmi: error at location %d\n", loc);
1036 while (k < m->m_hdr.mh_len) {
1039 while ((j++ < 16) && k < m->m_hdr.mh_len) {
1040 pos += ksprintf(buf + pos, "%c%02x",
1041 ((loc == k) ? '>' : ' '),
1046 log(LOG_WARNING, "nglmi: packet data:%s\n", buf);
1048 log(LOG_WARNING, "%04d :%s\n", k, buf);
1052 NG_FREE_DATA(m, meta);
1057 * Do local shutdown processing..
1058 * Cut any remaining links and free our local resources.
1061 nglmi_rmnode(node_p node)
1063 const sc_p sc = node->private;
1065 node->flags |= NG_INVALID;
1068 node->private = NULL;
1070 FREE(sc, M_NETGRAPH);
1075 * Hook disconnection
1076 * For this type, removal of any link except "debug" destroys the node.
1079 nglmi_disconnect(hook_p hook)
1081 const sc_p sc = hook->node->private;
1083 /* OK to remove debug hook(s) */
1084 if (hook->private == NULL)
1087 /* Stop timer if it's currently active */
1088 if (sc->flags & SCF_CONNECTED)
1089 callout_stop(&sc->timeout);
1092 ng_rmnode(hook->node);