ng_lmi.c revision 184205
152419Sjulian/* 252419Sjulian * ng_lmi.c 3139823Simp */ 4139823Simp 5139823Simp/*- 652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 752419Sjulian * All rights reserved. 852419Sjulian * 952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 1052419Sjulian * redistribution of this software, in source or object code forms, with or 1152419Sjulian * without modifications are expressly permitted by Whistle Communications; 1252419Sjulian * provided, however, that: 1352419Sjulian * 1. Any and all reproductions of the source or object code must include the 1452419Sjulian * copyright notice above and the following disclaimer of warranties; and 1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1652419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1752419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1852419Sjulian * such appears in the above copyright notice or in the software. 1952419Sjulian * 2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3652419Sjulian * OF SUCH DAMAGE. 3752419Sjulian * 3867506Sjulian * Author: Julian Elischer <julian@freebsd.org> 3952419Sjulian * 4052419Sjulian * $FreeBSD: head/sys/netgraph/ng_lmi.c 184205 2008-10-23 15:53:51Z des $ 4152752Sjulian * $Whistle: ng_lmi.c,v 1.38 1999/11/01 09:24:52 julian Exp $ 4252419Sjulian */ 4352419Sjulian 4452419Sjulian/* 4552419Sjulian * This node performs the frame relay LMI protocol. It knows how 4652419Sjulian * to do ITU Annex A, ANSI Annex D, and "Group-of-Four" variants 4752419Sjulian * of the protocol. 4852419Sjulian * 4952419Sjulian * A specific protocol can be forced by connecting the corresponding 5052419Sjulian * hook to DLCI 0 or 1023 (as appropriate) of a frame relay link. 5152419Sjulian * 5252419Sjulian * Alternately, this node can do auto-detection of the LMI protocol 5352419Sjulian * by connecting hook "auto0" to DLCI 0 and "auto1023" to DLCI 1023. 5452419Sjulian */ 5552419Sjulian 5652419Sjulian#include <sys/param.h> 5752419Sjulian#include <sys/systm.h> 5852419Sjulian#include <sys/errno.h> 5952419Sjulian#include <sys/kernel.h> 6052419Sjulian#include <sys/malloc.h> 6152419Sjulian#include <sys/mbuf.h> 6252419Sjulian#include <sys/syslog.h> 6352419Sjulian#include <netgraph/ng_message.h> 6452419Sjulian#include <netgraph/netgraph.h> 6552419Sjulian#include <netgraph/ng_lmi.h> 6652419Sjulian 6752419Sjulian/* 6852419Sjulian * Human readable names for LMI 6952419Sjulian */ 7052419Sjulian#define NAME_ANNEXA NG_LMI_HOOK_ANNEXA 7152419Sjulian#define NAME_ANNEXD NG_LMI_HOOK_ANNEXD 7252419Sjulian#define NAME_GROUP4 NG_LMI_HOOK_GROUPOF4 7352419Sjulian#define NAME_NONE "None" 7452419Sjulian 7552419Sjulian#define MAX_DLCIS 128 7652419Sjulian#define MAXDLCI 1023 7752419Sjulian 7852419Sjulian/* 7952419Sjulian * DLCI states 8052419Sjulian */ 8152419Sjulian#define DLCI_NULL 0 8252419Sjulian#define DLCI_UP 1 8352419Sjulian#define DLCI_DOWN 2 8452419Sjulian 8552419Sjulian/* 8652419Sjulian * Any received LMI frame should be at least this long 8752419Sjulian */ 8852419Sjulian#define LMI_MIN_LENGTH 8 /* XXX verify */ 8952419Sjulian 9052419Sjulian/* 9152419Sjulian * Netgraph node methods and type descriptor 9252419Sjulian */ 9352752Sjulianstatic ng_constructor_t nglmi_constructor; 9452752Sjulianstatic ng_rcvmsg_t nglmi_rcvmsg; 9570700Sjulianstatic ng_shutdown_t nglmi_shutdown; 9652752Sjulianstatic ng_newhook_t nglmi_newhook; 9752752Sjulianstatic ng_rcvdata_t nglmi_rcvdata; 9852752Sjulianstatic ng_disconnect_t nglmi_disconnect; 9970700Sjulianstatic int nglmi_checkdata(hook_p hook, struct mbuf *m); 10052419Sjulian 10152419Sjulianstatic struct ng_type typestruct = { 102129823Sjulian .version = NG_ABI_VERSION, 103129823Sjulian .name = NG_LMI_NODE_TYPE, 104129823Sjulian .constructor = nglmi_constructor, 105129823Sjulian .rcvmsg = nglmi_rcvmsg, 106129823Sjulian .shutdown = nglmi_shutdown, 107129823Sjulian .newhook = nglmi_newhook, 108129823Sjulian .rcvdata = nglmi_rcvdata, 109129823Sjulian .disconnect = nglmi_disconnect, 11052419Sjulian}; 11152419SjulianNETGRAPH_INIT(lmi, &typestruct); 11252419Sjulian 11352419Sjulian/* 11452419Sjulian * Info and status per node 11552419Sjulian */ 11652419Sjulianstruct nglmi_softc { 11752419Sjulian node_p node; /* netgraph node */ 11852419Sjulian int flags; /* state */ 11952419Sjulian int poll_count; /* the count of times for autolmi */ 12052419Sjulian int poll_state; /* state of auto detect machine */ 12152419Sjulian u_char remote_seq; /* sequence number the remote sent */ 12252419Sjulian u_char local_seq; /* last sequence number we sent */ 12352419Sjulian u_char protoID; /* 9 for group of 4, 8 otherwise */ 12452419Sjulian u_long seq_retries; /* sent this how many time so far */ 125140066Sglebius struct callout handle; /* see timeout(9) */ 12652419Sjulian int liv_per_full; 12752419Sjulian int liv_rate; 12852419Sjulian int livs; 12952419Sjulian int need_full; 13052419Sjulian hook_p lmi_channel; /* whatever we ended up using */ 13152419Sjulian hook_p lmi_annexA; 13252419Sjulian hook_p lmi_annexD; 13352419Sjulian hook_p lmi_group4; 13452419Sjulian hook_p lmi_channel0; /* auto-detect on DLCI 0 */ 13552419Sjulian hook_p lmi_channel1023;/* auto-detect on DLCI 1023 */ 13652419Sjulian char *protoname; /* cache protocol name */ 13752419Sjulian u_char dlci_state[MAXDLCI + 1]; 13852419Sjulian int invalidx; /* next dlci's to invalidate */ 13952419Sjulian}; 14052419Sjuliantypedef struct nglmi_softc *sc_p; 14152419Sjulian 14252419Sjulian/* 14352419Sjulian * Other internal functions 14452419Sjulian */ 145140066Sglebiusstatic void LMI_ticker(node_p node, hook_p hook, void *arg1, int arg2); 14652419Sjulianstatic void nglmi_startup_fixed(sc_p sc, hook_p hook); 14752419Sjulianstatic void nglmi_startup_auto(sc_p sc); 14852419Sjulianstatic void nglmi_startup(sc_p sc); 14952419Sjulianstatic void nglmi_inquire(sc_p sc, int full); 15052419Sjulianstatic void ngauto_state_machine(sc_p sc); 15152419Sjulian 15252419Sjulian/* 15352419Sjulian * Values for 'flags' field 15452419Sjulian * NB: the SCF_CONNECTED flag is set if and only if the timer is running. 15552419Sjulian */ 15652419Sjulian#define SCF_CONNECTED 0x01 /* connected to something */ 15752419Sjulian#define SCF_AUTO 0x02 /* we are auto-detecting */ 15852419Sjulian#define SCF_FIXED 0x04 /* we are fixed from the start */ 15952419Sjulian 16052419Sjulian#define SCF_LMITYPE 0x18 /* mask for determining Annex mode */ 16152419Sjulian#define SCF_NOLMI 0x00 /* no LMI type selected yet */ 16252419Sjulian#define SCF_ANNEX_A 0x08 /* running annex A mode */ 16352419Sjulian#define SCF_ANNEX_D 0x10 /* running annex D mode */ 16452419Sjulian#define SCF_GROUP4 0x18 /* running group of 4 */ 16552419Sjulian 16652419Sjulian#define SETLMITYPE(sc, annex) \ 16752419Sjuliando { \ 16852419Sjulian (sc)->flags &= ~SCF_LMITYPE; \ 16952419Sjulian (sc)->flags |= (annex); \ 17052419Sjulian} while (0) 17152419Sjulian 17252419Sjulian#define NOPROTO(sc) (((sc)->flags & SCF_LMITYPE) == SCF_NOLMI) 17352419Sjulian#define ANNEXA(sc) (((sc)->flags & SCF_LMITYPE) == SCF_ANNEX_A) 17452419Sjulian#define ANNEXD(sc) (((sc)->flags & SCF_LMITYPE) == SCF_ANNEX_D) 17552419Sjulian#define GROUP4(sc) (((sc)->flags & SCF_LMITYPE) == SCF_GROUP4) 17652419Sjulian 17752419Sjulian#define LMIPOLLSIZE 3 17852419Sjulian#define LMI_PATIENCE 8 /* declare all DLCI DOWN after N LMI failures */ 17952419Sjulian 18052419Sjulian/* 18152419Sjulian * Node constructor 18252419Sjulian */ 18352419Sjulianstatic int 18470700Sjuliannglmi_constructor(node_p node) 18552419Sjulian{ 18652419Sjulian sc_p sc; 18752419Sjulian 188184205Sdes sc = malloc(sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO); 18952419Sjulian if (sc == NULL) 19052419Sjulian return (ENOMEM); 191140066Sglebius 19270784Sjulian NG_NODE_SET_PRIVATE(node, sc); 193140066Sglebius sc->node = node; 194140066Sglebius 195140066Sglebius ng_callout_init(&sc->handle); 19652419Sjulian sc->protoname = NAME_NONE; 19752419Sjulian sc->liv_per_full = NG_LMI_SEQ_PER_FULL; /* make this dynamic */ 19852419Sjulian sc->liv_rate = NG_LMI_KEEPALIVE_RATE; 19952419Sjulian return (0); 20052419Sjulian} 20152419Sjulian 20252419Sjulian/* 20352419Sjulian * The LMI channel has a private pointer which is the same as the 20452419Sjulian * node private pointer. The debug channel has a NULL private pointer. 20552419Sjulian */ 20652419Sjulianstatic int 20752419Sjuliannglmi_newhook(node_p node, hook_p hook, const char *name) 20852419Sjulian{ 20970784Sjulian sc_p sc = NG_NODE_PRIVATE(node); 21052419Sjulian 21152419Sjulian if (strcmp(name, NG_LMI_HOOK_DEBUG) == 0) { 21270784Sjulian NG_HOOK_SET_PRIVATE(hook, NULL); 21352419Sjulian return (0); 21452419Sjulian } 21552419Sjulian if (sc->flags & SCF_CONNECTED) { 21652419Sjulian /* already connected, return an error */ 21752419Sjulian return (EINVAL); 21852419Sjulian } 21952419Sjulian if (strcmp(name, NG_LMI_HOOK_ANNEXA) == 0) { 22052419Sjulian sc->lmi_annexA = hook; 22170784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 22252419Sjulian sc->protoID = 8; 22352419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 22452419Sjulian sc->protoname = NAME_ANNEXA; 22552419Sjulian nglmi_startup_fixed(sc, hook); 22652419Sjulian } else if (strcmp(name, NG_LMI_HOOK_ANNEXD) == 0) { 22752419Sjulian sc->lmi_annexD = hook; 22870784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 22952419Sjulian sc->protoID = 8; 23052419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 23152419Sjulian sc->protoname = NAME_ANNEXD; 23252419Sjulian nglmi_startup_fixed(sc, hook); 23352419Sjulian } else if (strcmp(name, NG_LMI_HOOK_GROUPOF4) == 0) { 23452419Sjulian sc->lmi_group4 = hook; 23570784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 23652419Sjulian sc->protoID = 9; 23752419Sjulian SETLMITYPE(sc, SCF_GROUP4); 23852419Sjulian sc->protoname = NAME_GROUP4; 23952419Sjulian nglmi_startup_fixed(sc, hook); 24052419Sjulian } else if (strcmp(name, NG_LMI_HOOK_AUTO0) == 0) { 24152419Sjulian /* Note this, and if B is already installed, we're complete */ 24252419Sjulian sc->lmi_channel0 = hook; 24352419Sjulian sc->protoname = NAME_NONE; 24470784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 24552419Sjulian if (sc->lmi_channel1023) 24652419Sjulian nglmi_startup_auto(sc); 24752419Sjulian } else if (strcmp(name, NG_LMI_HOOK_AUTO1023) == 0) { 24852419Sjulian /* Note this, and if A is already installed, we're complete */ 24952419Sjulian sc->lmi_channel1023 = hook; 25052419Sjulian sc->protoname = NAME_NONE; 25170784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 25252419Sjulian if (sc->lmi_channel0) 25352419Sjulian nglmi_startup_auto(sc); 25452419Sjulian } else 25552419Sjulian return (EINVAL); /* unknown hook */ 25652419Sjulian return (0); 25752419Sjulian} 25852419Sjulian 25952419Sjulian/* 26052419Sjulian * We have just attached to a live (we hope) node. 26152419Sjulian * Fire out a LMI inquiry, and then start up the timers. 26252419Sjulian */ 26352419Sjulianstatic void 264140066SglebiusLMI_ticker(node_p node, hook_p hook, void *arg1, int arg2) 26552419Sjulian{ 266140066Sglebius sc_p sc = NG_NODE_PRIVATE(node); 26752419Sjulian 26852419Sjulian if (sc->flags & SCF_AUTO) { 26952419Sjulian ngauto_state_machine(sc); 270140066Sglebius ng_callout(&sc->handle, node, NULL, NG_LMI_POLL_RATE * hz, 271140066Sglebius LMI_ticker, NULL, 0); 27252419Sjulian } else { 27352419Sjulian if (sc->livs++ >= sc->liv_per_full) { 27452419Sjulian nglmi_inquire(sc, 1); 27552419Sjulian /* sc->livs = 0; *//* do this when we get the answer! */ 27652419Sjulian } else { 27752419Sjulian nglmi_inquire(sc, 0); 27852419Sjulian } 279140066Sglebius ng_callout(&sc->handle, node, NULL, sc->liv_rate * hz, 280140066Sglebius LMI_ticker, NULL, 0); 28152419Sjulian } 28252419Sjulian} 28352419Sjulian 28452419Sjulianstatic void 28552419Sjuliannglmi_startup_fixed(sc_p sc, hook_p hook) 28652419Sjulian{ 28752419Sjulian sc->flags |= (SCF_FIXED | SCF_CONNECTED); 28852419Sjulian sc->lmi_channel = hook; 28952419Sjulian nglmi_startup(sc); 29052419Sjulian} 29152419Sjulian 29252419Sjulianstatic void 29352419Sjuliannglmi_startup_auto(sc_p sc) 29452419Sjulian{ 29552419Sjulian sc->flags |= (SCF_AUTO | SCF_CONNECTED); 29652419Sjulian sc->poll_state = 0; /* reset state machine */ 29752419Sjulian sc->poll_count = 0; 29852419Sjulian nglmi_startup(sc); 29952419Sjulian} 30052419Sjulian 30152419Sjulianstatic void 30252419Sjuliannglmi_startup(sc_p sc) 30352419Sjulian{ 30452419Sjulian sc->remote_seq = 0; 30552419Sjulian sc->local_seq = 1; 30652419Sjulian sc->seq_retries = 0; 30752419Sjulian sc->livs = sc->liv_per_full - 1; 30852419Sjulian /* start off the ticker in 1 sec */ 309140066Sglebius ng_callout(&sc->handle, sc->node, NULL, hz, LMI_ticker, NULL, 0); 31052419Sjulian} 31152419Sjulian 31252419Sjulianstatic void 31352419Sjuliannglmi_inquire(sc_p sc, int full) 31452419Sjulian{ 31552419Sjulian struct mbuf *m; 316131108Sjulian struct ng_tag_prio *ptag; 31752419Sjulian char *cptr, *start; 31852419Sjulian int error; 31952419Sjulian 32052419Sjulian if (sc->lmi_channel == NULL) 32152419Sjulian return; 322111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 32352419Sjulian if (m == NULL) { 32452419Sjulian log(LOG_ERR, "nglmi: unable to start up LMI processing\n"); 32552419Sjulian return; 32652419Sjulian } 32753284Sarchie m->m_pkthdr.rcvif = NULL; 328131108Sjulian 329131108Sjulian /* Attach a tag to packet, marking it of link level state priority, so 330131108Sjulian * that device driver would put it in the beginning of queue */ 331131108Sjulian 332131108Sjulian ptag = (struct ng_tag_prio *)m_tag_alloc(NGM_GENERIC_COOKIE, NG_TAG_PRIO, 333131108Sjulian (sizeof(struct ng_tag_prio) - sizeof(struct m_tag)), M_NOWAIT); 334131108Sjulian if (ptag != NULL) { /* if it failed, well, it was optional anyhow */ 335131108Sjulian ptag->priority = NG_PRIO_LINKSTATE; 336131108Sjulian ptag->discardability = -1; 337131108Sjulian m_tag_prepend(m, &ptag->tag); 33852419Sjulian } 339131108Sjulian 34052419Sjulian m->m_data += 4; /* leave some room for a header */ 34152419Sjulian cptr = start = mtod(m, char *); 34252419Sjulian /* add in the header for an LMI inquiry. */ 34352419Sjulian *cptr++ = 0x03; /* UI frame */ 34452419Sjulian if (GROUP4(sc)) 34552419Sjulian *cptr++ = 0x09; /* proto discriminator */ 34652419Sjulian else 34752419Sjulian *cptr++ = 0x08; /* proto discriminator */ 34852419Sjulian *cptr++ = 0x00; /* call reference */ 34952419Sjulian *cptr++ = 0x75; /* inquiry */ 35052419Sjulian 351140365Srik /* If we are Annex-D, add locking shift to codeset 5. */ 35252419Sjulian if (ANNEXD(sc)) 353140358Srik *cptr++ = 0x95; /* locking shift */ 35452419Sjulian /* Add a request type */ 35552419Sjulian if (ANNEXA(sc)) 35652419Sjulian *cptr++ = 0x51; /* report type */ 35752419Sjulian else 35852419Sjulian *cptr++ = 0x01; /* report type */ 35952419Sjulian *cptr++ = 0x01; /* size = 1 */ 36052419Sjulian if (full) 36152419Sjulian *cptr++ = 0x00; /* full */ 36252419Sjulian else 36352419Sjulian *cptr++ = 0x01; /* partial */ 36452419Sjulian 36552419Sjulian /* Add a link verification IE */ 36652419Sjulian if (ANNEXA(sc)) 36752419Sjulian *cptr++ = 0x53; /* verification IE */ 36852419Sjulian else 36952419Sjulian *cptr++ = 0x03; /* verification IE */ 37052419Sjulian *cptr++ = 0x02; /* 2 extra bytes */ 37152419Sjulian *cptr++ = sc->local_seq; 37252419Sjulian *cptr++ = sc->remote_seq; 37352419Sjulian sc->seq_retries++; 37452419Sjulian 37552419Sjulian /* Send it */ 37652419Sjulian m->m_len = m->m_pkthdr.len = cptr - start; 377131108Sjulian NG_SEND_DATA_ONLY(error, sc->lmi_channel, m); 37852419Sjulian 37952419Sjulian /* If we've been sending requests for long enough, and there has 38052419Sjulian * been no response, then mark as DOWN, any DLCIs that are UP. */ 38152419Sjulian if (sc->seq_retries == LMI_PATIENCE) { 38252419Sjulian int count; 38352419Sjulian 38452419Sjulian for (count = 0; count < MAXDLCI; count++) 38552419Sjulian if (sc->dlci_state[count] == DLCI_UP) 38652419Sjulian sc->dlci_state[count] = DLCI_DOWN; 38752419Sjulian } 38852419Sjulian} 38952419Sjulian 39052419Sjulian/* 39152419Sjulian * State machine for LMI auto-detect. The transitions are ordered 39252419Sjulian * to try the more likely possibilities first. 39352419Sjulian */ 39452419Sjulianstatic void 39552419Sjulianngauto_state_machine(sc_p sc) 39652419Sjulian{ 39752419Sjulian if ((sc->poll_count <= 0) || (sc->poll_count > LMIPOLLSIZE)) { 39852419Sjulian /* time to change states in the auto probe machine */ 39952419Sjulian /* capture wild values of poll_count while we are at it */ 40052419Sjulian sc->poll_count = LMIPOLLSIZE; 40152419Sjulian sc->poll_state++; 40252419Sjulian } 40352419Sjulian switch (sc->poll_state) { 40452419Sjulian case 7: 40552419Sjulian log(LOG_WARNING, "nglmi: no response from exchange\n"); 40652419Sjulian default: /* capture bad states */ 40752419Sjulian sc->poll_state = 1; 40852419Sjulian case 1: 40952419Sjulian sc->lmi_channel = sc->lmi_channel0; 41052419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 41152419Sjulian break; 41252419Sjulian case 2: 41352419Sjulian sc->lmi_channel = sc->lmi_channel1023; 41452419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 41552419Sjulian break; 41652419Sjulian case 3: 41752419Sjulian sc->lmi_channel = sc->lmi_channel0; 41852419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 41952419Sjulian break; 42052419Sjulian case 4: 42152419Sjulian sc->lmi_channel = sc->lmi_channel1023; 42252419Sjulian SETLMITYPE(sc, SCF_GROUP4); 42352419Sjulian break; 42452419Sjulian case 5: 42552419Sjulian sc->lmi_channel = sc->lmi_channel1023; 42652419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 42752419Sjulian break; 42852419Sjulian case 6: 42952419Sjulian sc->lmi_channel = sc->lmi_channel0; 43052419Sjulian SETLMITYPE(sc, SCF_GROUP4); 43152419Sjulian break; 43252419Sjulian } 43352419Sjulian 43452419Sjulian /* send an inquirey encoded appropriatly */ 43552419Sjulian nglmi_inquire(sc, 0); 43652419Sjulian sc->poll_count--; 43752419Sjulian} 43852419Sjulian 43952419Sjulian/* 44052419Sjulian * Receive a netgraph control message. 44152419Sjulian */ 44252419Sjulianstatic int 44370700Sjuliannglmi_rcvmsg(node_p node, item_p item, hook_p lasthook) 44452419Sjulian{ 44570784Sjulian sc_p sc = NG_NODE_PRIVATE(node); 44670159Sjulian struct ng_mesg *resp = NULL; 44752419Sjulian int error = 0; 44870700Sjulian struct ng_mesg *msg; 44952419Sjulian 45070700Sjulian NGI_GET_MSG(item, msg); 45152419Sjulian switch (msg->header.typecookie) { 45252419Sjulian case NGM_GENERIC_COOKIE: 45352419Sjulian switch (msg->header.cmd) { 45452419Sjulian case NGM_TEXT_STATUS: 45552419Sjulian { 45652419Sjulian char *arg; 45752419Sjulian int pos, count; 45852419Sjulian 45970159Sjulian NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 46070159Sjulian if (resp == NULL) { 46152419Sjulian error = ENOMEM; 46252419Sjulian break; 46352419Sjulian } 46470159Sjulian arg = resp->data; 46552419Sjulian pos = sprintf(arg, "protocol %s ", sc->protoname); 46652419Sjulian if (sc->flags & SCF_FIXED) 46752419Sjulian pos += sprintf(arg + pos, "fixed\n"); 46852419Sjulian else if (sc->flags & SCF_AUTO) 46952419Sjulian pos += sprintf(arg + pos, "auto-detecting\n"); 47052419Sjulian else 47152419Sjulian pos += sprintf(arg + pos, "auto on dlci %d\n", 47252419Sjulian (sc->lmi_channel == sc->lmi_channel0) ? 47352419Sjulian 0 : 1023); 47452419Sjulian pos += sprintf(arg + pos, 47552419Sjulian "keepalive period: %d seconds\n", sc->liv_rate); 47652419Sjulian pos += sprintf(arg + pos, 47752419Sjulian "unacknowledged keepalives: %ld\n", 47852419Sjulian sc->seq_retries); 47952419Sjulian for (count = 0; 48052419Sjulian ((count <= MAXDLCI) 48152419Sjulian && (pos < (NG_TEXTRESPONSE - 20))); 48252419Sjulian count++) { 48352419Sjulian if (sc->dlci_state[count]) { 48452419Sjulian pos += sprintf(arg + pos, 48552419Sjulian "dlci %d %s\n", count, 48652419Sjulian (sc->dlci_state[count] 48752419Sjulian == DLCI_UP) ? "up" : "down"); 48852419Sjulian } 48952419Sjulian } 49070159Sjulian resp->header.arglen = pos + 1; 49152419Sjulian break; 49252419Sjulian } 49352419Sjulian default: 49452419Sjulian error = EINVAL; 49552419Sjulian break; 49652419Sjulian } 49752419Sjulian break; 49852419Sjulian case NGM_LMI_COOKIE: 49952419Sjulian switch (msg->header.cmd) { 50052419Sjulian case NGM_LMI_GET_STATUS: 50152419Sjulian { 50252419Sjulian struct nglmistat *stat; 50352419Sjulian int k; 50452419Sjulian 50570159Sjulian NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT); 50670159Sjulian if (!resp) { 50752419Sjulian error = ENOMEM; 50852419Sjulian break; 50952419Sjulian } 51070159Sjulian stat = (struct nglmistat *) resp->data; 51152419Sjulian strncpy(stat->proto, 51252419Sjulian sc->protoname, sizeof(stat->proto) - 1); 51352419Sjulian strncpy(stat->hook, 51452419Sjulian sc->protoname, sizeof(stat->hook) - 1); 51552419Sjulian stat->autod = !!(sc->flags & SCF_AUTO); 51652419Sjulian stat->fixed = !!(sc->flags & SCF_FIXED); 51752419Sjulian for (k = 0; k <= MAXDLCI; k++) { 51852419Sjulian switch (sc->dlci_state[k]) { 51952419Sjulian case DLCI_UP: 52052419Sjulian stat->up[k / 8] |= (1 << (k % 8)); 52152419Sjulian /* fall through */ 52252419Sjulian case DLCI_DOWN: 52352419Sjulian stat->seen[k / 8] |= (1 << (k % 8)); 52452419Sjulian break; 52552419Sjulian } 52652419Sjulian } 52752419Sjulian break; 52852419Sjulian } 52952419Sjulian default: 53052419Sjulian error = EINVAL; 53152419Sjulian break; 53252419Sjulian } 53352419Sjulian break; 53452419Sjulian default: 53552419Sjulian error = EINVAL; 53652419Sjulian break; 53752419Sjulian } 53870159Sjulian 53970700Sjulian NG_RESPOND_MSG(error, node, item, resp); 54070700Sjulian NG_FREE_MSG(msg); 54152419Sjulian return (error); 54252419Sjulian} 54352419Sjulian 54452419Sjulian#define STEPBY(stepsize) \ 54552419Sjulian do { \ 54652419Sjulian packetlen -= (stepsize); \ 54752419Sjulian data += (stepsize); \ 54852419Sjulian } while (0) 54952419Sjulian 55052419Sjulian/* 55152419Sjulian * receive data, and use it to update our status. 55252419Sjulian * Anything coming in on the debug port is discarded. 55352419Sjulian */ 55452419Sjulianstatic int 55570700Sjuliannglmi_rcvdata(hook_p hook, item_p item) 55652419Sjulian{ 55770784Sjulian sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 55897897Sarchie const u_char *data; 55952419Sjulian unsigned short dlci; 56052419Sjulian u_short packetlen; 56152419Sjulian int resptype_seen = 0; 56270700Sjulian struct mbuf *m; 56352419Sjulian 56470700Sjulian NGI_GET_M(item, m); 56570700Sjulian NG_FREE_ITEM(item); 56670784Sjulian if (NG_HOOK_PRIVATE(hook) == NULL) { 56752419Sjulian goto drop; 56852419Sjulian } 569147163Sru packetlen = m->m_len; 57052419Sjulian 57152419Sjulian /* XXX what if it's more than 1 mbuf? */ 57252419Sjulian if ((packetlen > MHLEN) && !(m->m_flags & M_EXT)) { 57352419Sjulian log(LOG_WARNING, "nglmi: packetlen (%d) too big\n", packetlen); 57452419Sjulian goto drop; 57552419Sjulian } 57652539Sjulian if (m->m_len < packetlen && (m = m_pullup(m, packetlen)) == NULL) { 57752539Sjulian log(LOG_WARNING, 57852539Sjulian "nglmi: m_pullup failed for %d bytes\n", packetlen); 57952419Sjulian return (0); 58052419Sjulian } 58170700Sjulian if (nglmi_checkdata(hook, m) == 0) 58252419Sjulian return (0); 58352419Sjulian 58452419Sjulian /* pass the first 4 bytes (already checked in the nglmi_checkdata()) */ 58597897Sarchie data = mtod(m, const u_char *); 58652419Sjulian STEPBY(4); 58752419Sjulian 58852419Sjulian /* Now check if there is a 'locking shift'. This is only seen in 58952419Sjulian * Annex D frames. don't bother checking, we already did that. Don't 59052419Sjulian * increment immediatly as it might not be there. */ 59152419Sjulian if (ANNEXD(sc)) 59252419Sjulian STEPBY(1); 59352419Sjulian 59452419Sjulian /* If we get this far we should consider that it is a legitimate 59552419Sjulian * frame and we know what it is. */ 59652419Sjulian if (sc->flags & SCF_AUTO) { 59752419Sjulian /* note the hook that this valid channel came from and drop 59852419Sjulian * out of auto probe mode. */ 59952419Sjulian if (ANNEXA(sc)) 60052419Sjulian sc->protoname = NAME_ANNEXA; 60152419Sjulian else if (ANNEXD(sc)) 60252419Sjulian sc->protoname = NAME_ANNEXD; 60352419Sjulian else if (GROUP4(sc)) 60452419Sjulian sc->protoname = NAME_GROUP4; 60552419Sjulian else { 60652419Sjulian log(LOG_ERR, "nglmi: No known type\n"); 60752419Sjulian goto drop; 60852419Sjulian } 60952419Sjulian sc->lmi_channel = hook; 61052419Sjulian sc->flags &= ~SCF_AUTO; 61152419Sjulian log(LOG_INFO, "nglmi: auto-detected %s LMI on DLCI %d\n", 61252419Sjulian sc->protoname, hook == sc->lmi_channel0 ? 0 : 1023); 61352419Sjulian } 61452419Sjulian 61552419Sjulian /* While there is more data in the status packet, keep processing 61652419Sjulian * status items. First make sure there is enough data for the 61752419Sjulian * segment descriptor's length field. */ 61852419Sjulian while (packetlen >= 2) { 61952419Sjulian u_int segtype = data[0]; 62052419Sjulian u_int segsize = data[1]; 62152419Sjulian 62252419Sjulian /* Now that we know how long it claims to be, make sure 62352419Sjulian * there is enough data for the next seg. */ 62452419Sjulian if (packetlen < segsize + 2) 62552419Sjulian break; 62652419Sjulian switch (segtype) { 62752419Sjulian case 0x01: 62852419Sjulian case 0x51: 62952419Sjulian if (resptype_seen) { 63052419Sjulian log(LOG_WARNING, "nglmi: dup MSGTYPE\n"); 63152419Sjulian goto nextIE; 63252419Sjulian } 63352419Sjulian resptype_seen++; 63452419Sjulian /* The remote end tells us what kind of response 63552419Sjulian * this is. Only expect a type 0 or 1. if we are a 63652419Sjulian * full status, invalidate a few DLCIs just to see 63752419Sjulian * that they are still ok. */ 63852419Sjulian if (segsize != 1) 63952419Sjulian goto nextIE; 64052419Sjulian switch (data[2]) { 64152419Sjulian case 1: 64252419Sjulian /* partial status, do no extra processing */ 64352419Sjulian break; 64452419Sjulian case 0: 64552419Sjulian { 64652419Sjulian int count = 0; 64752419Sjulian int idx = sc->invalidx; 64852419Sjulian 64952419Sjulian for (count = 0; count < 10; count++) { 65052419Sjulian if (idx > MAXDLCI) 65152419Sjulian idx = 0; 65252419Sjulian if (sc->dlci_state[idx] == DLCI_UP) 65352419Sjulian sc->dlci_state[idx] = DLCI_DOWN; 65452419Sjulian idx++; 65552419Sjulian } 65652419Sjulian sc->invalidx = idx; 65752419Sjulian /* we got and we wanted one. relax 65852419Sjulian * now.. but don't reset to 0 if it 65952419Sjulian * was unrequested. */ 66052419Sjulian if (sc->livs > sc->liv_per_full) 66152419Sjulian sc->livs = 0; 66252419Sjulian break; 66352419Sjulian } 66452419Sjulian } 66552419Sjulian break; 66652419Sjulian case 0x03: 66752419Sjulian case 0x53: 66852419Sjulian /* The remote tells us what it thinks the sequence 66952419Sjulian * numbers are. If it's not size 2, it must be a 67052419Sjulian * duplicate to have gotten this far, skip it. */ 67152419Sjulian if (segsize != 2) 67252419Sjulian goto nextIE; 67352419Sjulian sc->remote_seq = data[2]; 67452419Sjulian if (sc->local_seq == data[3]) { 67552419Sjulian sc->local_seq++; 67652419Sjulian sc->seq_retries = 0; 67752419Sjulian /* Note that all 3 Frame protocols seem to 67852419Sjulian * not like 0 as a sequence number. */ 67952419Sjulian if (sc->local_seq == 0) 68052419Sjulian sc->local_seq = 1; 68152419Sjulian } 68252419Sjulian break; 68352419Sjulian case 0x07: 68452419Sjulian case 0x57: 68552419Sjulian /* The remote tells us about a DLCI that it knows 68652419Sjulian * about. There may be many of these in a single 68752419Sjulian * status response */ 68852419Sjulian switch (segsize) { 68952419Sjulian case 6:/* only on 'group of 4' */ 69052419Sjulian dlci = ((u_short) data[2] & 0xff) << 8; 69152419Sjulian dlci |= (data[3] & 0xff); 69252419Sjulian if ((dlci < 1024) && (dlci > 0)) { 69352419Sjulian /* XXX */ 69452419Sjulian } 69552419Sjulian break; 69652419Sjulian case 3: 69752419Sjulian dlci = ((u_short) data[2] & 0x3f) << 4; 69852419Sjulian dlci |= ((data[3] & 0x78) >> 3); 69952419Sjulian if ((dlci < 1024) && (dlci > 0)) { 70052419Sjulian /* set up the bottom half of the 70152419Sjulian * support for that dlci if it's not 70252419Sjulian * already been done */ 70352419Sjulian /* store this information somewhere */ 70452419Sjulian } 70552419Sjulian break; 70652419Sjulian default: 70752419Sjulian goto nextIE; 70852419Sjulian } 70952419Sjulian if (sc->dlci_state[dlci] != DLCI_UP) { 71052419Sjulian /* bring new DLCI to life */ 71152419Sjulian /* may do more here some day */ 71252419Sjulian if (sc->dlci_state[dlci] != DLCI_DOWN) 71352419Sjulian log(LOG_INFO, 71452419Sjulian "nglmi: DLCI %d became active\n", 71552419Sjulian dlci); 71652419Sjulian sc->dlci_state[dlci] = DLCI_UP; 71752419Sjulian } 71852419Sjulian break; 71952419Sjulian } 72052419SjuliannextIE: 72152419Sjulian STEPBY(segsize + 2); 72252419Sjulian } 72370700Sjulian NG_FREE_M(m); 72452419Sjulian return (0); 72552419Sjulian 72652419Sjuliandrop: 72770700Sjulian NG_FREE_M(m); 72852419Sjulian return (EINVAL); 72952419Sjulian} 73052419Sjulian 73152419Sjulian/* 73252419Sjulian * Check that a packet is entirely kosha. 73352419Sjulian * return 1 of ok, and 0 if not. 73452419Sjulian * All data is discarded if a 0 is returned. 73552419Sjulian */ 73652419Sjulianstatic int 73770700Sjuliannglmi_checkdata(hook_p hook, struct mbuf *m) 73852419Sjulian{ 73970784Sjulian sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 74097897Sarchie const u_char *data; 74152419Sjulian u_short packetlen; 74252419Sjulian unsigned short dlci; 74352419Sjulian u_char type; 74452419Sjulian u_char nextbyte; 74552419Sjulian int seq_seen = 0; 74652419Sjulian int resptype_seen = 0; /* 0 , 1 (partial) or 2 (full) */ 74752419Sjulian int highest_dlci = 0; 74852419Sjulian 749147163Sru packetlen = m->m_len; 75097897Sarchie data = mtod(m, const u_char *); 75152419Sjulian if (*data != 0x03) { 75252419Sjulian log(LOG_WARNING, "nglmi: unexpected value in LMI(%d)\n", 1); 75352419Sjulian goto reject; 75452419Sjulian } 75552419Sjulian STEPBY(1); 75652419Sjulian 75752419Sjulian /* look at the protocol ID */ 75852419Sjulian nextbyte = *data; 75952419Sjulian if (sc->flags & SCF_AUTO) { 76052419Sjulian SETLMITYPE(sc, SCF_NOLMI); /* start with a clean slate */ 76152419Sjulian switch (nextbyte) { 76252419Sjulian case 0x8: 76352419Sjulian sc->protoID = 8; 76452419Sjulian break; 76552419Sjulian case 0x9: 76652419Sjulian SETLMITYPE(sc, SCF_GROUP4); 76752419Sjulian sc->protoID = 9; 76852419Sjulian break; 76952419Sjulian default: 77052419Sjulian log(LOG_WARNING, "nglmi: bad Protocol ID(%d)\n", 77152419Sjulian (int) nextbyte); 77252419Sjulian goto reject; 77352419Sjulian } 77452419Sjulian } else { 77552419Sjulian if (nextbyte != sc->protoID) { 77652419Sjulian log(LOG_WARNING, "nglmi: unexpected Protocol ID(%d)\n", 77752419Sjulian (int) nextbyte); 77852419Sjulian goto reject; 77952419Sjulian } 78052419Sjulian } 78152419Sjulian STEPBY(1); 78252419Sjulian 78352419Sjulian /* check call reference (always null in non ISDN frame relay) */ 78452419Sjulian if (*data != 0x00) { 78552419Sjulian log(LOG_WARNING, "nglmi: unexpected Call Reference (0x%x)\n", 78652419Sjulian data[-1]); 78752419Sjulian goto reject; 78852419Sjulian } 78952419Sjulian STEPBY(1); 79052419Sjulian 79152419Sjulian /* check message type */ 79252419Sjulian switch ((type = *data)) { 79352419Sjulian case 0x75: /* Status enquiry */ 79452419Sjulian log(LOG_WARNING, "nglmi: unexpected message type(0x%x)\n", 79552419Sjulian data[-1]); 79652419Sjulian goto reject; 79752419Sjulian case 0x7D: /* Status message */ 79852419Sjulian break; 79952419Sjulian default: 80052419Sjulian log(LOG_WARNING, 80152419Sjulian "nglmi: unexpected msg type(0x%x) \n", (int) type); 80252419Sjulian goto reject; 80352419Sjulian } 80452419Sjulian STEPBY(1); 80552419Sjulian 80652419Sjulian /* Now check if there is a 'locking shift'. This is only seen in 80752419Sjulian * Annex D frames. Don't increment immediately as it might not be 80852419Sjulian * there. */ 80952419Sjulian nextbyte = *data; 81052419Sjulian if (sc->flags & SCF_AUTO) { 81152419Sjulian if (!(GROUP4(sc))) { 81252419Sjulian if (nextbyte == 0x95) { 81352419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 81452419Sjulian STEPBY(1); 81552419Sjulian } else 81652419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 81752419Sjulian } else if (nextbyte == 0x95) { 81852419Sjulian log(LOG_WARNING, "nglmi: locking shift seen in G4\n"); 81952419Sjulian goto reject; 82052419Sjulian } 82152419Sjulian } else { 82252419Sjulian if (ANNEXD(sc)) { 82352419Sjulian if (*data == 0x95) 82452419Sjulian STEPBY(1); 82552419Sjulian else { 82652419Sjulian log(LOG_WARNING, 82752419Sjulian "nglmi: locking shift missing\n"); 82852419Sjulian goto reject; 82952419Sjulian } 83052419Sjulian } else if (*data == 0x95) { 83152419Sjulian log(LOG_WARNING, "nglmi: locking shift seen\n"); 83252419Sjulian goto reject; 83352419Sjulian } 83452419Sjulian } 83552419Sjulian 83652419Sjulian /* While there is more data in the status packet, keep processing 83752419Sjulian * status items. First make sure there is enough data for the 83852419Sjulian * segment descriptor's length field. */ 83952419Sjulian while (packetlen >= 2) { 84052419Sjulian u_int segtype = data[0]; 84152419Sjulian u_int segsize = data[1]; 84252419Sjulian 84352419Sjulian /* Now that we know how long it claims to be, make sure 84452419Sjulian * there is enough data for the next seg. */ 84552419Sjulian if (packetlen < (segsize + 2)) { 84652419Sjulian log(LOG_WARNING, "nglmi: IE longer than packet\n"); 84752419Sjulian break; 84852419Sjulian } 84952419Sjulian switch (segtype) { 85052419Sjulian case 0x01: 85152419Sjulian case 0x51: 85252419Sjulian /* According to MCI's HP analyser, we should just 85352419Sjulian * ignore if there is mor ethan one of these (?). */ 85452419Sjulian if (resptype_seen) { 85552419Sjulian log(LOG_WARNING, "nglmi: dup MSGTYPE\n"); 85652419Sjulian goto nextIE; 85752419Sjulian } 85852419Sjulian if (segsize != 1) { 85952419Sjulian log(LOG_WARNING, "nglmi: MSGTYPE wrong size\n"); 86052419Sjulian goto reject; 86152419Sjulian } 86252419Sjulian /* The remote end tells us what kind of response 86352419Sjulian * this is. Only expect a type 0 or 1. if it was a 86452419Sjulian * full (type 0) check we just asked for a type 86552419Sjulian * full. */ 86652419Sjulian switch (data[2]) { 86752419Sjulian case 1:/* partial */ 86852419Sjulian if (sc->livs > sc->liv_per_full) { 86952419Sjulian log(LOG_WARNING, 87052419Sjulian "nglmi: LIV when FULL expected\n"); 87152419Sjulian goto reject; /* need full */ 87252419Sjulian } 87352419Sjulian resptype_seen = 1; 87452419Sjulian break; 87552419Sjulian case 0:/* full */ 87652419Sjulian /* Full response is always acceptable */ 87752419Sjulian resptype_seen = 2; 87852419Sjulian break; 87952419Sjulian default: 88052419Sjulian log(LOG_WARNING, 88152419Sjulian "nglmi: Unknown report type %d\n", data[2]); 88252419Sjulian goto reject; 88352419Sjulian } 88452419Sjulian break; 88552419Sjulian case 0x03: 88652419Sjulian case 0x53: 88752419Sjulian /* The remote tells us what it thinks the sequence 88852419Sjulian * numbers are. I would have thought that there 88952419Sjulian * needs to be one and only one of these, but MCI 89052419Sjulian * want us to just ignore extras. (?) */ 89152419Sjulian if (resptype_seen == 0) { 89252419Sjulian log(LOG_WARNING, "nglmi: no TYPE before SEQ\n"); 89352419Sjulian goto reject; 89452419Sjulian } 89552419Sjulian if (seq_seen != 0) /* already seen seq numbers */ 89652419Sjulian goto nextIE; 89752419Sjulian if (segsize != 2) { 89852419Sjulian log(LOG_WARNING, "nglmi: bad SEQ sts size\n"); 89952419Sjulian goto reject; 90052419Sjulian } 90152419Sjulian if (sc->local_seq != data[3]) { 90252419Sjulian log(LOG_WARNING, "nglmi: unexpected SEQ\n"); 90352419Sjulian goto reject; 90452419Sjulian } 90552419Sjulian seq_seen = 1; 90652419Sjulian break; 90752419Sjulian case 0x07: 90852419Sjulian case 0x57: 90952419Sjulian /* The remote tells us about a DLCI that it knows 91052419Sjulian * about. There may be many of these in a single 91152419Sjulian * status response */ 91252419Sjulian if (seq_seen != 1) { /* already seen seq numbers? */ 91352419Sjulian log(LOG_WARNING, 91452419Sjulian "nglmi: No sequence before DLCI\n"); 91552419Sjulian goto reject; 91652419Sjulian } 91752419Sjulian if (resptype_seen != 2) { /* must be full */ 91852419Sjulian log(LOG_WARNING, 91952419Sjulian "nglmi: No resp type before DLCI\n"); 92052419Sjulian goto reject; 92152419Sjulian } 92252419Sjulian if (GROUP4(sc)) { 92352419Sjulian if (segsize != 6) { 92452419Sjulian log(LOG_WARNING, 92552419Sjulian "nglmi: wrong IE segsize\n"); 92652419Sjulian goto reject; 92752419Sjulian } 92852419Sjulian dlci = ((u_short) data[2] & 0xff) << 8; 92952419Sjulian dlci |= (data[3] & 0xff); 93052419Sjulian } else { 93152419Sjulian if (segsize != 3) { 93252419Sjulian log(LOG_WARNING, 93352419Sjulian "nglmi: DLCI headersize of %d" 93452419Sjulian " not supported\n", segsize - 1); 93552419Sjulian goto reject; 93652419Sjulian } 93752419Sjulian dlci = ((u_short) data[2] & 0x3f) << 4; 93852419Sjulian dlci |= ((data[3] & 0x78) >> 3); 93952419Sjulian } 94052419Sjulian /* async can only have one of these */ 94152419Sjulian#if 0 /* async not yet accepted */ 94252419Sjulian if (async && highest_dlci) { 94352419Sjulian log(LOG_WARNING, 94452419Sjulian "nglmi: Async with > 1 DLCI\n"); 94552419Sjulian goto reject; 94652419Sjulian } 94752419Sjulian#endif 94852419Sjulian /* Annex D says these will always be Ascending, but 94952419Sjulian * the HP test for G4 says we should accept 95052419Sjulian * duplicates, so for now allow that. ( <= vs. < ) */ 95152419Sjulian#if 0 95252419Sjulian /* MCI tests want us to accept out of order for AnxD */ 95352419Sjulian if ((!GROUP4(sc)) && (dlci < highest_dlci)) { 95452419Sjulian /* duplicate or mis-ordered dlci */ 95552419Sjulian /* (spec says they will increase in number) */ 95652419Sjulian log(LOG_WARNING, "nglmi: DLCI out of order\n"); 95752419Sjulian goto reject; 95852419Sjulian } 95952419Sjulian#endif 96052419Sjulian if (dlci > 1023) { 96152419Sjulian log(LOG_WARNING, "nglmi: DLCI out of range\n"); 96252419Sjulian goto reject; 96352419Sjulian } 96452419Sjulian highest_dlci = dlci; 96552419Sjulian break; 96652419Sjulian default: 96752419Sjulian log(LOG_WARNING, 96852419Sjulian "nglmi: unknown LMI segment type %d\n", segtype); 96952419Sjulian } 97052419SjuliannextIE: 97152419Sjulian STEPBY(segsize + 2); 97252419Sjulian } 97352419Sjulian if (packetlen != 0) { /* partial junk at end? */ 97452419Sjulian log(LOG_WARNING, 97552419Sjulian "nglmi: %d bytes extra at end of packet\n", packetlen); 97652419Sjulian goto print; 97752419Sjulian } 97852419Sjulian if (resptype_seen == 0) { 97952419Sjulian log(LOG_WARNING, "nglmi: No response type seen\n"); 98052419Sjulian goto reject; /* had no response type */ 98152419Sjulian } 98252419Sjulian if (seq_seen == 0) { 98352419Sjulian log(LOG_WARNING, "nglmi: No sequence numbers seen\n"); 98452419Sjulian goto reject; /* had no sequence numbers */ 98552419Sjulian } 98652419Sjulian return (1); 98752419Sjulian 98852419Sjulianprint: 98952419Sjulian { 99052419Sjulian int i, j, k, pos; 99152419Sjulian char buf[100]; 99252419Sjulian int loc; 99397897Sarchie const u_char *bp = mtod(m, const u_char *); 99452419Sjulian 99552419Sjulian k = i = 0; 996147163Sru loc = (m->m_len - packetlen); 99752419Sjulian log(LOG_WARNING, "nglmi: error at location %d\n", loc); 998147163Sru while (k < m->m_len) { 99952419Sjulian pos = 0; 100052419Sjulian j = 0; 1001147163Sru while ((j++ < 16) && k < m->m_len) { 100252419Sjulian pos += sprintf(buf + pos, "%c%02x", 100352419Sjulian ((loc == k) ? '>' : ' '), 100452419Sjulian bp[k]); 100552419Sjulian k++; 100652419Sjulian } 100752419Sjulian if (i == 0) 100852419Sjulian log(LOG_WARNING, "nglmi: packet data:%s\n", buf); 100952419Sjulian else 101052419Sjulian log(LOG_WARNING, "%04d :%s\n", k, buf); 101152419Sjulian i++; 101252419Sjulian } 101352419Sjulian } 101452419Sjulian return (1); 101552419Sjulianreject: 101652419Sjulian { 101752419Sjulian int i, j, k, pos; 101852419Sjulian char buf[100]; 101952419Sjulian int loc; 102097897Sarchie const u_char *bp = mtod(m, const u_char *); 102152419Sjulian 102252419Sjulian k = i = 0; 1023147163Sru loc = (m->m_len - packetlen); 102452419Sjulian log(LOG_WARNING, "nglmi: error at location %d\n", loc); 1025147163Sru while (k < m->m_len) { 102652419Sjulian pos = 0; 102752419Sjulian j = 0; 1028147163Sru while ((j++ < 16) && k < m->m_len) { 102952419Sjulian pos += sprintf(buf + pos, "%c%02x", 103052419Sjulian ((loc == k) ? '>' : ' '), 103152419Sjulian bp[k]); 103252419Sjulian k++; 103352419Sjulian } 103452419Sjulian if (i == 0) 103552419Sjulian log(LOG_WARNING, "nglmi: packet data:%s\n", buf); 103652419Sjulian else 103752419Sjulian log(LOG_WARNING, "%04d :%s\n", k, buf); 103852419Sjulian i++; 103952419Sjulian } 104052419Sjulian } 104170700Sjulian NG_FREE_M(m); 104252419Sjulian return (0); 104352419Sjulian} 104452419Sjulian 104552419Sjulian/* 104652419Sjulian * Do local shutdown processing.. 104752419Sjulian * Cut any remaining links and free our local resources. 104852419Sjulian */ 104952419Sjulianstatic int 105070700Sjuliannglmi_shutdown(node_p node) 105152419Sjulian{ 105270784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 105352419Sjulian 105470784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 105570784Sjulian NG_NODE_UNREF(sc->node); 1056184205Sdes free(sc, M_NETGRAPH); 105752419Sjulian return (0); 105852419Sjulian} 105952419Sjulian 106052419Sjulian/* 106152419Sjulian * Hook disconnection 106252419Sjulian * For this type, removal of any link except "debug" destroys the node. 106352419Sjulian */ 106452419Sjulianstatic int 106552419Sjuliannglmi_disconnect(hook_p hook) 106652419Sjulian{ 106770784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 106852419Sjulian 106952419Sjulian /* OK to remove debug hook(s) */ 107070784Sjulian if (NG_HOOK_PRIVATE(hook) == NULL) 107152419Sjulian return (0); 107252419Sjulian 107352419Sjulian /* Stop timer if it's currently active */ 107452419Sjulian if (sc->flags & SCF_CONNECTED) 1075140066Sglebius ng_uncallout(&sc->handle, sc->node); 107652419Sjulian 107752419Sjulian /* Self-destruct */ 107870784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 107970784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 108052419Sjulian return (0); 108152419Sjulian} 108252419Sjulian 1083