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$ 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 188220768Sglebius sc = malloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO); 189140066Sglebius 19070784Sjulian NG_NODE_SET_PRIVATE(node, sc); 191140066Sglebius sc->node = node; 192140066Sglebius 193140066Sglebius ng_callout_init(&sc->handle); 19452419Sjulian sc->protoname = NAME_NONE; 19552419Sjulian sc->liv_per_full = NG_LMI_SEQ_PER_FULL; /* make this dynamic */ 19652419Sjulian sc->liv_rate = NG_LMI_KEEPALIVE_RATE; 19752419Sjulian return (0); 19852419Sjulian} 19952419Sjulian 20052419Sjulian/* 20152419Sjulian * The LMI channel has a private pointer which is the same as the 20252419Sjulian * node private pointer. The debug channel has a NULL private pointer. 20352419Sjulian */ 20452419Sjulianstatic int 20552419Sjuliannglmi_newhook(node_p node, hook_p hook, const char *name) 20652419Sjulian{ 20770784Sjulian sc_p sc = NG_NODE_PRIVATE(node); 20852419Sjulian 20952419Sjulian if (strcmp(name, NG_LMI_HOOK_DEBUG) == 0) { 21070784Sjulian NG_HOOK_SET_PRIVATE(hook, NULL); 21152419Sjulian return (0); 21252419Sjulian } 21352419Sjulian if (sc->flags & SCF_CONNECTED) { 21452419Sjulian /* already connected, return an error */ 21552419Sjulian return (EINVAL); 21652419Sjulian } 21752419Sjulian if (strcmp(name, NG_LMI_HOOK_ANNEXA) == 0) { 21852419Sjulian sc->lmi_annexA = hook; 21970784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 22052419Sjulian sc->protoID = 8; 22152419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 22252419Sjulian sc->protoname = NAME_ANNEXA; 22352419Sjulian nglmi_startup_fixed(sc, hook); 22452419Sjulian } else if (strcmp(name, NG_LMI_HOOK_ANNEXD) == 0) { 22552419Sjulian sc->lmi_annexD = hook; 22670784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 22752419Sjulian sc->protoID = 8; 22852419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 22952419Sjulian sc->protoname = NAME_ANNEXD; 23052419Sjulian nglmi_startup_fixed(sc, hook); 23152419Sjulian } else if (strcmp(name, NG_LMI_HOOK_GROUPOF4) == 0) { 23252419Sjulian sc->lmi_group4 = hook; 23370784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 23452419Sjulian sc->protoID = 9; 23552419Sjulian SETLMITYPE(sc, SCF_GROUP4); 23652419Sjulian sc->protoname = NAME_GROUP4; 23752419Sjulian nglmi_startup_fixed(sc, hook); 23852419Sjulian } else if (strcmp(name, NG_LMI_HOOK_AUTO0) == 0) { 23952419Sjulian /* Note this, and if B is already installed, we're complete */ 24052419Sjulian sc->lmi_channel0 = hook; 24152419Sjulian sc->protoname = NAME_NONE; 24270784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 24352419Sjulian if (sc->lmi_channel1023) 24452419Sjulian nglmi_startup_auto(sc); 24552419Sjulian } else if (strcmp(name, NG_LMI_HOOK_AUTO1023) == 0) { 24652419Sjulian /* Note this, and if A is already installed, we're complete */ 24752419Sjulian sc->lmi_channel1023 = hook; 24852419Sjulian sc->protoname = NAME_NONE; 24970784Sjulian NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); 25052419Sjulian if (sc->lmi_channel0) 25152419Sjulian nglmi_startup_auto(sc); 25252419Sjulian } else 25352419Sjulian return (EINVAL); /* unknown hook */ 25452419Sjulian return (0); 25552419Sjulian} 25652419Sjulian 25752419Sjulian/* 25852419Sjulian * We have just attached to a live (we hope) node. 25952419Sjulian * Fire out a LMI inquiry, and then start up the timers. 26052419Sjulian */ 26152419Sjulianstatic void 262140066SglebiusLMI_ticker(node_p node, hook_p hook, void *arg1, int arg2) 26352419Sjulian{ 264140066Sglebius sc_p sc = NG_NODE_PRIVATE(node); 26552419Sjulian 26652419Sjulian if (sc->flags & SCF_AUTO) { 26752419Sjulian ngauto_state_machine(sc); 268140066Sglebius ng_callout(&sc->handle, node, NULL, NG_LMI_POLL_RATE * hz, 269140066Sglebius LMI_ticker, NULL, 0); 27052419Sjulian } else { 27152419Sjulian if (sc->livs++ >= sc->liv_per_full) { 27252419Sjulian nglmi_inquire(sc, 1); 27352419Sjulian /* sc->livs = 0; *//* do this when we get the answer! */ 27452419Sjulian } else { 27552419Sjulian nglmi_inquire(sc, 0); 27652419Sjulian } 277140066Sglebius ng_callout(&sc->handle, node, NULL, sc->liv_rate * hz, 278140066Sglebius LMI_ticker, NULL, 0); 27952419Sjulian } 28052419Sjulian} 28152419Sjulian 28252419Sjulianstatic void 28352419Sjuliannglmi_startup_fixed(sc_p sc, hook_p hook) 28452419Sjulian{ 28552419Sjulian sc->flags |= (SCF_FIXED | SCF_CONNECTED); 28652419Sjulian sc->lmi_channel = hook; 28752419Sjulian nglmi_startup(sc); 28852419Sjulian} 28952419Sjulian 29052419Sjulianstatic void 29152419Sjuliannglmi_startup_auto(sc_p sc) 29252419Sjulian{ 29352419Sjulian sc->flags |= (SCF_AUTO | SCF_CONNECTED); 29452419Sjulian sc->poll_state = 0; /* reset state machine */ 29552419Sjulian sc->poll_count = 0; 29652419Sjulian nglmi_startup(sc); 29752419Sjulian} 29852419Sjulian 29952419Sjulianstatic void 30052419Sjuliannglmi_startup(sc_p sc) 30152419Sjulian{ 30252419Sjulian sc->remote_seq = 0; 30352419Sjulian sc->local_seq = 1; 30452419Sjulian sc->seq_retries = 0; 30552419Sjulian sc->livs = sc->liv_per_full - 1; 30652419Sjulian /* start off the ticker in 1 sec */ 307140066Sglebius ng_callout(&sc->handle, sc->node, NULL, hz, LMI_ticker, NULL, 0); 30852419Sjulian} 30952419Sjulian 31052419Sjulianstatic void 31152419Sjuliannglmi_inquire(sc_p sc, int full) 31252419Sjulian{ 31352419Sjulian struct mbuf *m; 314131108Sjulian struct ng_tag_prio *ptag; 31552419Sjulian char *cptr, *start; 31652419Sjulian int error; 31752419Sjulian 31852419Sjulian if (sc->lmi_channel == NULL) 31952419Sjulian return; 320111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 32152419Sjulian if (m == NULL) { 32252419Sjulian log(LOG_ERR, "nglmi: unable to start up LMI processing\n"); 32352419Sjulian return; 32452419Sjulian } 32553284Sarchie m->m_pkthdr.rcvif = NULL; 326131108Sjulian 327131108Sjulian /* Attach a tag to packet, marking it of link level state priority, so 328131108Sjulian * that device driver would put it in the beginning of queue */ 329131108Sjulian 330131108Sjulian ptag = (struct ng_tag_prio *)m_tag_alloc(NGM_GENERIC_COOKIE, NG_TAG_PRIO, 331131108Sjulian (sizeof(struct ng_tag_prio) - sizeof(struct m_tag)), M_NOWAIT); 332131108Sjulian if (ptag != NULL) { /* if it failed, well, it was optional anyhow */ 333131108Sjulian ptag->priority = NG_PRIO_LINKSTATE; 334131108Sjulian ptag->discardability = -1; 335131108Sjulian m_tag_prepend(m, &ptag->tag); 33652419Sjulian } 337131108Sjulian 33852419Sjulian m->m_data += 4; /* leave some room for a header */ 33952419Sjulian cptr = start = mtod(m, char *); 34052419Sjulian /* add in the header for an LMI inquiry. */ 34152419Sjulian *cptr++ = 0x03; /* UI frame */ 34252419Sjulian if (GROUP4(sc)) 34352419Sjulian *cptr++ = 0x09; /* proto discriminator */ 34452419Sjulian else 34552419Sjulian *cptr++ = 0x08; /* proto discriminator */ 34652419Sjulian *cptr++ = 0x00; /* call reference */ 34752419Sjulian *cptr++ = 0x75; /* inquiry */ 34852419Sjulian 349140365Srik /* If we are Annex-D, add locking shift to codeset 5. */ 35052419Sjulian if (ANNEXD(sc)) 351140358Srik *cptr++ = 0x95; /* locking shift */ 35252419Sjulian /* Add a request type */ 35352419Sjulian if (ANNEXA(sc)) 35452419Sjulian *cptr++ = 0x51; /* report type */ 35552419Sjulian else 35652419Sjulian *cptr++ = 0x01; /* report type */ 35752419Sjulian *cptr++ = 0x01; /* size = 1 */ 35852419Sjulian if (full) 35952419Sjulian *cptr++ = 0x00; /* full */ 36052419Sjulian else 36152419Sjulian *cptr++ = 0x01; /* partial */ 36252419Sjulian 36352419Sjulian /* Add a link verification IE */ 36452419Sjulian if (ANNEXA(sc)) 36552419Sjulian *cptr++ = 0x53; /* verification IE */ 36652419Sjulian else 36752419Sjulian *cptr++ = 0x03; /* verification IE */ 36852419Sjulian *cptr++ = 0x02; /* 2 extra bytes */ 36952419Sjulian *cptr++ = sc->local_seq; 37052419Sjulian *cptr++ = sc->remote_seq; 37152419Sjulian sc->seq_retries++; 37252419Sjulian 37352419Sjulian /* Send it */ 37452419Sjulian m->m_len = m->m_pkthdr.len = cptr - start; 375131108Sjulian NG_SEND_DATA_ONLY(error, sc->lmi_channel, m); 37652419Sjulian 37752419Sjulian /* If we've been sending requests for long enough, and there has 37852419Sjulian * been no response, then mark as DOWN, any DLCIs that are UP. */ 37952419Sjulian if (sc->seq_retries == LMI_PATIENCE) { 38052419Sjulian int count; 38152419Sjulian 38252419Sjulian for (count = 0; count < MAXDLCI; count++) 38352419Sjulian if (sc->dlci_state[count] == DLCI_UP) 38452419Sjulian sc->dlci_state[count] = DLCI_DOWN; 38552419Sjulian } 38652419Sjulian} 38752419Sjulian 38852419Sjulian/* 38952419Sjulian * State machine for LMI auto-detect. The transitions are ordered 39052419Sjulian * to try the more likely possibilities first. 39152419Sjulian */ 39252419Sjulianstatic void 39352419Sjulianngauto_state_machine(sc_p sc) 39452419Sjulian{ 39552419Sjulian if ((sc->poll_count <= 0) || (sc->poll_count > LMIPOLLSIZE)) { 39652419Sjulian /* time to change states in the auto probe machine */ 39752419Sjulian /* capture wild values of poll_count while we are at it */ 39852419Sjulian sc->poll_count = LMIPOLLSIZE; 39952419Sjulian sc->poll_state++; 40052419Sjulian } 40152419Sjulian switch (sc->poll_state) { 40252419Sjulian case 7: 40352419Sjulian log(LOG_WARNING, "nglmi: no response from exchange\n"); 40452419Sjulian default: /* capture bad states */ 40552419Sjulian sc->poll_state = 1; 40652419Sjulian case 1: 40752419Sjulian sc->lmi_channel = sc->lmi_channel0; 40852419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 40952419Sjulian break; 41052419Sjulian case 2: 41152419Sjulian sc->lmi_channel = sc->lmi_channel1023; 41252419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 41352419Sjulian break; 41452419Sjulian case 3: 41552419Sjulian sc->lmi_channel = sc->lmi_channel0; 41652419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 41752419Sjulian break; 41852419Sjulian case 4: 41952419Sjulian sc->lmi_channel = sc->lmi_channel1023; 42052419Sjulian SETLMITYPE(sc, SCF_GROUP4); 42152419Sjulian break; 42252419Sjulian case 5: 42352419Sjulian sc->lmi_channel = sc->lmi_channel1023; 42452419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 42552419Sjulian break; 42652419Sjulian case 6: 42752419Sjulian sc->lmi_channel = sc->lmi_channel0; 42852419Sjulian SETLMITYPE(sc, SCF_GROUP4); 42952419Sjulian break; 43052419Sjulian } 43152419Sjulian 43252419Sjulian /* send an inquirey encoded appropriatly */ 43352419Sjulian nglmi_inquire(sc, 0); 43452419Sjulian sc->poll_count--; 43552419Sjulian} 43652419Sjulian 43752419Sjulian/* 43852419Sjulian * Receive a netgraph control message. 43952419Sjulian */ 44052419Sjulianstatic int 44170700Sjuliannglmi_rcvmsg(node_p node, item_p item, hook_p lasthook) 44252419Sjulian{ 44370784Sjulian sc_p sc = NG_NODE_PRIVATE(node); 44470159Sjulian struct ng_mesg *resp = NULL; 44552419Sjulian int error = 0; 44670700Sjulian struct ng_mesg *msg; 44752419Sjulian 44870700Sjulian NGI_GET_MSG(item, msg); 44952419Sjulian switch (msg->header.typecookie) { 45052419Sjulian case NGM_GENERIC_COOKIE: 45152419Sjulian switch (msg->header.cmd) { 45252419Sjulian case NGM_TEXT_STATUS: 45352419Sjulian { 45452419Sjulian char *arg; 45552419Sjulian int pos, count; 45652419Sjulian 45770159Sjulian NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 45870159Sjulian if (resp == NULL) { 45952419Sjulian error = ENOMEM; 46052419Sjulian break; 46152419Sjulian } 46270159Sjulian arg = resp->data; 46352419Sjulian pos = sprintf(arg, "protocol %s ", sc->protoname); 46452419Sjulian if (sc->flags & SCF_FIXED) 46552419Sjulian pos += sprintf(arg + pos, "fixed\n"); 46652419Sjulian else if (sc->flags & SCF_AUTO) 46752419Sjulian pos += sprintf(arg + pos, "auto-detecting\n"); 46852419Sjulian else 46952419Sjulian pos += sprintf(arg + pos, "auto on dlci %d\n", 47052419Sjulian (sc->lmi_channel == sc->lmi_channel0) ? 47152419Sjulian 0 : 1023); 47252419Sjulian pos += sprintf(arg + pos, 47352419Sjulian "keepalive period: %d seconds\n", sc->liv_rate); 47452419Sjulian pos += sprintf(arg + pos, 47552419Sjulian "unacknowledged keepalives: %ld\n", 47652419Sjulian sc->seq_retries); 47752419Sjulian for (count = 0; 47852419Sjulian ((count <= MAXDLCI) 47952419Sjulian && (pos < (NG_TEXTRESPONSE - 20))); 48052419Sjulian count++) { 48152419Sjulian if (sc->dlci_state[count]) { 48252419Sjulian pos += sprintf(arg + pos, 48352419Sjulian "dlci %d %s\n", count, 48452419Sjulian (sc->dlci_state[count] 48552419Sjulian == DLCI_UP) ? "up" : "down"); 48652419Sjulian } 48752419Sjulian } 48870159Sjulian resp->header.arglen = pos + 1; 48952419Sjulian break; 49052419Sjulian } 49152419Sjulian default: 49252419Sjulian error = EINVAL; 49352419Sjulian break; 49452419Sjulian } 49552419Sjulian break; 49652419Sjulian case NGM_LMI_COOKIE: 49752419Sjulian switch (msg->header.cmd) { 49852419Sjulian case NGM_LMI_GET_STATUS: 49952419Sjulian { 50052419Sjulian struct nglmistat *stat; 50152419Sjulian int k; 50252419Sjulian 50370159Sjulian NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT); 50470159Sjulian if (!resp) { 50552419Sjulian error = ENOMEM; 50652419Sjulian break; 50752419Sjulian } 50870159Sjulian stat = (struct nglmistat *) resp->data; 50952419Sjulian strncpy(stat->proto, 51052419Sjulian sc->protoname, sizeof(stat->proto) - 1); 51152419Sjulian strncpy(stat->hook, 51252419Sjulian sc->protoname, sizeof(stat->hook) - 1); 51352419Sjulian stat->autod = !!(sc->flags & SCF_AUTO); 51452419Sjulian stat->fixed = !!(sc->flags & SCF_FIXED); 51552419Sjulian for (k = 0; k <= MAXDLCI; k++) { 51652419Sjulian switch (sc->dlci_state[k]) { 51752419Sjulian case DLCI_UP: 51852419Sjulian stat->up[k / 8] |= (1 << (k % 8)); 51952419Sjulian /* fall through */ 52052419Sjulian case DLCI_DOWN: 52152419Sjulian stat->seen[k / 8] |= (1 << (k % 8)); 52252419Sjulian break; 52352419Sjulian } 52452419Sjulian } 52552419Sjulian break; 52652419Sjulian } 52752419Sjulian default: 52852419Sjulian error = EINVAL; 52952419Sjulian break; 53052419Sjulian } 53152419Sjulian break; 53252419Sjulian default: 53352419Sjulian error = EINVAL; 53452419Sjulian break; 53552419Sjulian } 53670159Sjulian 53770700Sjulian NG_RESPOND_MSG(error, node, item, resp); 53870700Sjulian NG_FREE_MSG(msg); 53952419Sjulian return (error); 54052419Sjulian} 54152419Sjulian 54252419Sjulian#define STEPBY(stepsize) \ 54352419Sjulian do { \ 54452419Sjulian packetlen -= (stepsize); \ 54552419Sjulian data += (stepsize); \ 54652419Sjulian } while (0) 54752419Sjulian 54852419Sjulian/* 54952419Sjulian * receive data, and use it to update our status. 55052419Sjulian * Anything coming in on the debug port is discarded. 55152419Sjulian */ 55252419Sjulianstatic int 55370700Sjuliannglmi_rcvdata(hook_p hook, item_p item) 55452419Sjulian{ 55570784Sjulian sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 55697897Sarchie const u_char *data; 55752419Sjulian unsigned short dlci; 55852419Sjulian u_short packetlen; 55952419Sjulian int resptype_seen = 0; 56070700Sjulian struct mbuf *m; 56152419Sjulian 56270700Sjulian NGI_GET_M(item, m); 56370700Sjulian NG_FREE_ITEM(item); 56470784Sjulian if (NG_HOOK_PRIVATE(hook) == NULL) { 56552419Sjulian goto drop; 56652419Sjulian } 567147163Sru packetlen = m->m_len; 56852419Sjulian 56952419Sjulian /* XXX what if it's more than 1 mbuf? */ 57052419Sjulian if ((packetlen > MHLEN) && !(m->m_flags & M_EXT)) { 57152419Sjulian log(LOG_WARNING, "nglmi: packetlen (%d) too big\n", packetlen); 57252419Sjulian goto drop; 57352419Sjulian } 57452539Sjulian if (m->m_len < packetlen && (m = m_pullup(m, packetlen)) == NULL) { 57552539Sjulian log(LOG_WARNING, 57652539Sjulian "nglmi: m_pullup failed for %d bytes\n", packetlen); 57752419Sjulian return (0); 57852419Sjulian } 57970700Sjulian if (nglmi_checkdata(hook, m) == 0) 58052419Sjulian return (0); 58152419Sjulian 58252419Sjulian /* pass the first 4 bytes (already checked in the nglmi_checkdata()) */ 58397897Sarchie data = mtod(m, const u_char *); 58452419Sjulian STEPBY(4); 58552419Sjulian 58652419Sjulian /* Now check if there is a 'locking shift'. This is only seen in 58752419Sjulian * Annex D frames. don't bother checking, we already did that. Don't 58852419Sjulian * increment immediatly as it might not be there. */ 58952419Sjulian if (ANNEXD(sc)) 59052419Sjulian STEPBY(1); 59152419Sjulian 59252419Sjulian /* If we get this far we should consider that it is a legitimate 59352419Sjulian * frame and we know what it is. */ 59452419Sjulian if (sc->flags & SCF_AUTO) { 59552419Sjulian /* note the hook that this valid channel came from and drop 59652419Sjulian * out of auto probe mode. */ 59752419Sjulian if (ANNEXA(sc)) 59852419Sjulian sc->protoname = NAME_ANNEXA; 59952419Sjulian else if (ANNEXD(sc)) 60052419Sjulian sc->protoname = NAME_ANNEXD; 60152419Sjulian else if (GROUP4(sc)) 60252419Sjulian sc->protoname = NAME_GROUP4; 60352419Sjulian else { 60452419Sjulian log(LOG_ERR, "nglmi: No known type\n"); 60552419Sjulian goto drop; 60652419Sjulian } 60752419Sjulian sc->lmi_channel = hook; 60852419Sjulian sc->flags &= ~SCF_AUTO; 60952419Sjulian log(LOG_INFO, "nglmi: auto-detected %s LMI on DLCI %d\n", 61052419Sjulian sc->protoname, hook == sc->lmi_channel0 ? 0 : 1023); 61152419Sjulian } 61252419Sjulian 61352419Sjulian /* While there is more data in the status packet, keep processing 61452419Sjulian * status items. First make sure there is enough data for the 61552419Sjulian * segment descriptor's length field. */ 61652419Sjulian while (packetlen >= 2) { 61752419Sjulian u_int segtype = data[0]; 61852419Sjulian u_int segsize = data[1]; 61952419Sjulian 62052419Sjulian /* Now that we know how long it claims to be, make sure 62152419Sjulian * there is enough data for the next seg. */ 62252419Sjulian if (packetlen < segsize + 2) 62352419Sjulian break; 62452419Sjulian switch (segtype) { 62552419Sjulian case 0x01: 62652419Sjulian case 0x51: 62752419Sjulian if (resptype_seen) { 62852419Sjulian log(LOG_WARNING, "nglmi: dup MSGTYPE\n"); 62952419Sjulian goto nextIE; 63052419Sjulian } 63152419Sjulian resptype_seen++; 63252419Sjulian /* The remote end tells us what kind of response 63352419Sjulian * this is. Only expect a type 0 or 1. if we are a 63452419Sjulian * full status, invalidate a few DLCIs just to see 63552419Sjulian * that they are still ok. */ 63652419Sjulian if (segsize != 1) 63752419Sjulian goto nextIE; 63852419Sjulian switch (data[2]) { 63952419Sjulian case 1: 64052419Sjulian /* partial status, do no extra processing */ 64152419Sjulian break; 64252419Sjulian case 0: 64352419Sjulian { 64452419Sjulian int count = 0; 64552419Sjulian int idx = sc->invalidx; 64652419Sjulian 64752419Sjulian for (count = 0; count < 10; count++) { 64852419Sjulian if (idx > MAXDLCI) 64952419Sjulian idx = 0; 65052419Sjulian if (sc->dlci_state[idx] == DLCI_UP) 65152419Sjulian sc->dlci_state[idx] = DLCI_DOWN; 65252419Sjulian idx++; 65352419Sjulian } 65452419Sjulian sc->invalidx = idx; 65552419Sjulian /* we got and we wanted one. relax 65652419Sjulian * now.. but don't reset to 0 if it 65752419Sjulian * was unrequested. */ 65852419Sjulian if (sc->livs > sc->liv_per_full) 65952419Sjulian sc->livs = 0; 66052419Sjulian break; 66152419Sjulian } 66252419Sjulian } 66352419Sjulian break; 66452419Sjulian case 0x03: 66552419Sjulian case 0x53: 66652419Sjulian /* The remote tells us what it thinks the sequence 66752419Sjulian * numbers are. If it's not size 2, it must be a 66852419Sjulian * duplicate to have gotten this far, skip it. */ 66952419Sjulian if (segsize != 2) 67052419Sjulian goto nextIE; 67152419Sjulian sc->remote_seq = data[2]; 67252419Sjulian if (sc->local_seq == data[3]) { 67352419Sjulian sc->local_seq++; 67452419Sjulian sc->seq_retries = 0; 67552419Sjulian /* Note that all 3 Frame protocols seem to 67652419Sjulian * not like 0 as a sequence number. */ 67752419Sjulian if (sc->local_seq == 0) 67852419Sjulian sc->local_seq = 1; 67952419Sjulian } 68052419Sjulian break; 68152419Sjulian case 0x07: 68252419Sjulian case 0x57: 68352419Sjulian /* The remote tells us about a DLCI that it knows 68452419Sjulian * about. There may be many of these in a single 68552419Sjulian * status response */ 68652419Sjulian switch (segsize) { 68752419Sjulian case 6:/* only on 'group of 4' */ 68852419Sjulian dlci = ((u_short) data[2] & 0xff) << 8; 68952419Sjulian dlci |= (data[3] & 0xff); 69052419Sjulian if ((dlci < 1024) && (dlci > 0)) { 69152419Sjulian /* XXX */ 69252419Sjulian } 69352419Sjulian break; 69452419Sjulian case 3: 69552419Sjulian dlci = ((u_short) data[2] & 0x3f) << 4; 69652419Sjulian dlci |= ((data[3] & 0x78) >> 3); 69752419Sjulian if ((dlci < 1024) && (dlci > 0)) { 69852419Sjulian /* set up the bottom half of the 69952419Sjulian * support for that dlci if it's not 70052419Sjulian * already been done */ 70152419Sjulian /* store this information somewhere */ 70252419Sjulian } 70352419Sjulian break; 70452419Sjulian default: 70552419Sjulian goto nextIE; 70652419Sjulian } 70752419Sjulian if (sc->dlci_state[dlci] != DLCI_UP) { 70852419Sjulian /* bring new DLCI to life */ 70952419Sjulian /* may do more here some day */ 71052419Sjulian if (sc->dlci_state[dlci] != DLCI_DOWN) 71152419Sjulian log(LOG_INFO, 71252419Sjulian "nglmi: DLCI %d became active\n", 71352419Sjulian dlci); 71452419Sjulian sc->dlci_state[dlci] = DLCI_UP; 71552419Sjulian } 71652419Sjulian break; 71752419Sjulian } 71852419SjuliannextIE: 71952419Sjulian STEPBY(segsize + 2); 72052419Sjulian } 72170700Sjulian NG_FREE_M(m); 72252419Sjulian return (0); 72352419Sjulian 72452419Sjuliandrop: 72570700Sjulian NG_FREE_M(m); 72652419Sjulian return (EINVAL); 72752419Sjulian} 72852419Sjulian 72952419Sjulian/* 73052419Sjulian * Check that a packet is entirely kosha. 73152419Sjulian * return 1 of ok, and 0 if not. 73252419Sjulian * All data is discarded if a 0 is returned. 73352419Sjulian */ 73452419Sjulianstatic int 73570700Sjuliannglmi_checkdata(hook_p hook, struct mbuf *m) 73652419Sjulian{ 73770784Sjulian sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 73897897Sarchie const u_char *data; 73952419Sjulian u_short packetlen; 74052419Sjulian unsigned short dlci; 74152419Sjulian u_char type; 74252419Sjulian u_char nextbyte; 74352419Sjulian int seq_seen = 0; 74452419Sjulian int resptype_seen = 0; /* 0 , 1 (partial) or 2 (full) */ 74552419Sjulian int highest_dlci = 0; 74652419Sjulian 747147163Sru packetlen = m->m_len; 74897897Sarchie data = mtod(m, const u_char *); 74952419Sjulian if (*data != 0x03) { 75052419Sjulian log(LOG_WARNING, "nglmi: unexpected value in LMI(%d)\n", 1); 75152419Sjulian goto reject; 75252419Sjulian } 75352419Sjulian STEPBY(1); 75452419Sjulian 75552419Sjulian /* look at the protocol ID */ 75652419Sjulian nextbyte = *data; 75752419Sjulian if (sc->flags & SCF_AUTO) { 75852419Sjulian SETLMITYPE(sc, SCF_NOLMI); /* start with a clean slate */ 75952419Sjulian switch (nextbyte) { 76052419Sjulian case 0x8: 76152419Sjulian sc->protoID = 8; 76252419Sjulian break; 76352419Sjulian case 0x9: 76452419Sjulian SETLMITYPE(sc, SCF_GROUP4); 76552419Sjulian sc->protoID = 9; 76652419Sjulian break; 76752419Sjulian default: 76852419Sjulian log(LOG_WARNING, "nglmi: bad Protocol ID(%d)\n", 76952419Sjulian (int) nextbyte); 77052419Sjulian goto reject; 77152419Sjulian } 77252419Sjulian } else { 77352419Sjulian if (nextbyte != sc->protoID) { 77452419Sjulian log(LOG_WARNING, "nglmi: unexpected Protocol ID(%d)\n", 77552419Sjulian (int) nextbyte); 77652419Sjulian goto reject; 77752419Sjulian } 77852419Sjulian } 77952419Sjulian STEPBY(1); 78052419Sjulian 78152419Sjulian /* check call reference (always null in non ISDN frame relay) */ 78252419Sjulian if (*data != 0x00) { 78352419Sjulian log(LOG_WARNING, "nglmi: unexpected Call Reference (0x%x)\n", 78452419Sjulian data[-1]); 78552419Sjulian goto reject; 78652419Sjulian } 78752419Sjulian STEPBY(1); 78852419Sjulian 78952419Sjulian /* check message type */ 79052419Sjulian switch ((type = *data)) { 79152419Sjulian case 0x75: /* Status enquiry */ 79252419Sjulian log(LOG_WARNING, "nglmi: unexpected message type(0x%x)\n", 79352419Sjulian data[-1]); 79452419Sjulian goto reject; 79552419Sjulian case 0x7D: /* Status message */ 79652419Sjulian break; 79752419Sjulian default: 79852419Sjulian log(LOG_WARNING, 79952419Sjulian "nglmi: unexpected msg type(0x%x) \n", (int) type); 80052419Sjulian goto reject; 80152419Sjulian } 80252419Sjulian STEPBY(1); 80352419Sjulian 80452419Sjulian /* Now check if there is a 'locking shift'. This is only seen in 80552419Sjulian * Annex D frames. Don't increment immediately as it might not be 80652419Sjulian * there. */ 80752419Sjulian nextbyte = *data; 80852419Sjulian if (sc->flags & SCF_AUTO) { 80952419Sjulian if (!(GROUP4(sc))) { 81052419Sjulian if (nextbyte == 0x95) { 81152419Sjulian SETLMITYPE(sc, SCF_ANNEX_D); 81252419Sjulian STEPBY(1); 81352419Sjulian } else 81452419Sjulian SETLMITYPE(sc, SCF_ANNEX_A); 81552419Sjulian } else if (nextbyte == 0x95) { 81652419Sjulian log(LOG_WARNING, "nglmi: locking shift seen in G4\n"); 81752419Sjulian goto reject; 81852419Sjulian } 81952419Sjulian } else { 82052419Sjulian if (ANNEXD(sc)) { 82152419Sjulian if (*data == 0x95) 82252419Sjulian STEPBY(1); 82352419Sjulian else { 82452419Sjulian log(LOG_WARNING, 82552419Sjulian "nglmi: locking shift missing\n"); 82652419Sjulian goto reject; 82752419Sjulian } 82852419Sjulian } else if (*data == 0x95) { 82952419Sjulian log(LOG_WARNING, "nglmi: locking shift seen\n"); 83052419Sjulian goto reject; 83152419Sjulian } 83252419Sjulian } 83352419Sjulian 83452419Sjulian /* While there is more data in the status packet, keep processing 83552419Sjulian * status items. First make sure there is enough data for the 83652419Sjulian * segment descriptor's length field. */ 83752419Sjulian while (packetlen >= 2) { 83852419Sjulian u_int segtype = data[0]; 83952419Sjulian u_int segsize = data[1]; 84052419Sjulian 84152419Sjulian /* Now that we know how long it claims to be, make sure 84252419Sjulian * there is enough data for the next seg. */ 84352419Sjulian if (packetlen < (segsize + 2)) { 84452419Sjulian log(LOG_WARNING, "nglmi: IE longer than packet\n"); 84552419Sjulian break; 84652419Sjulian } 84752419Sjulian switch (segtype) { 84852419Sjulian case 0x01: 84952419Sjulian case 0x51: 85052419Sjulian /* According to MCI's HP analyser, we should just 85152419Sjulian * ignore if there is mor ethan one of these (?). */ 85252419Sjulian if (resptype_seen) { 85352419Sjulian log(LOG_WARNING, "nglmi: dup MSGTYPE\n"); 85452419Sjulian goto nextIE; 85552419Sjulian } 85652419Sjulian if (segsize != 1) { 85752419Sjulian log(LOG_WARNING, "nglmi: MSGTYPE wrong size\n"); 85852419Sjulian goto reject; 85952419Sjulian } 86052419Sjulian /* The remote end tells us what kind of response 86152419Sjulian * this is. Only expect a type 0 or 1. if it was a 86252419Sjulian * full (type 0) check we just asked for a type 86352419Sjulian * full. */ 86452419Sjulian switch (data[2]) { 86552419Sjulian case 1:/* partial */ 86652419Sjulian if (sc->livs > sc->liv_per_full) { 86752419Sjulian log(LOG_WARNING, 86852419Sjulian "nglmi: LIV when FULL expected\n"); 86952419Sjulian goto reject; /* need full */ 87052419Sjulian } 87152419Sjulian resptype_seen = 1; 87252419Sjulian break; 87352419Sjulian case 0:/* full */ 87452419Sjulian /* Full response is always acceptable */ 87552419Sjulian resptype_seen = 2; 87652419Sjulian break; 87752419Sjulian default: 87852419Sjulian log(LOG_WARNING, 87952419Sjulian "nglmi: Unknown report type %d\n", data[2]); 88052419Sjulian goto reject; 88152419Sjulian } 88252419Sjulian break; 88352419Sjulian case 0x03: 88452419Sjulian case 0x53: 88552419Sjulian /* The remote tells us what it thinks the sequence 88652419Sjulian * numbers are. I would have thought that there 88752419Sjulian * needs to be one and only one of these, but MCI 88852419Sjulian * want us to just ignore extras. (?) */ 88952419Sjulian if (resptype_seen == 0) { 89052419Sjulian log(LOG_WARNING, "nglmi: no TYPE before SEQ\n"); 89152419Sjulian goto reject; 89252419Sjulian } 89352419Sjulian if (seq_seen != 0) /* already seen seq numbers */ 89452419Sjulian goto nextIE; 89552419Sjulian if (segsize != 2) { 89652419Sjulian log(LOG_WARNING, "nglmi: bad SEQ sts size\n"); 89752419Sjulian goto reject; 89852419Sjulian } 89952419Sjulian if (sc->local_seq != data[3]) { 90052419Sjulian log(LOG_WARNING, "nglmi: unexpected SEQ\n"); 90152419Sjulian goto reject; 90252419Sjulian } 90352419Sjulian seq_seen = 1; 90452419Sjulian break; 90552419Sjulian case 0x07: 90652419Sjulian case 0x57: 90752419Sjulian /* The remote tells us about a DLCI that it knows 90852419Sjulian * about. There may be many of these in a single 90952419Sjulian * status response */ 91052419Sjulian if (seq_seen != 1) { /* already seen seq numbers? */ 91152419Sjulian log(LOG_WARNING, 91252419Sjulian "nglmi: No sequence before DLCI\n"); 91352419Sjulian goto reject; 91452419Sjulian } 91552419Sjulian if (resptype_seen != 2) { /* must be full */ 91652419Sjulian log(LOG_WARNING, 91752419Sjulian "nglmi: No resp type before DLCI\n"); 91852419Sjulian goto reject; 91952419Sjulian } 92052419Sjulian if (GROUP4(sc)) { 92152419Sjulian if (segsize != 6) { 92252419Sjulian log(LOG_WARNING, 92352419Sjulian "nglmi: wrong IE segsize\n"); 92452419Sjulian goto reject; 92552419Sjulian } 92652419Sjulian dlci = ((u_short) data[2] & 0xff) << 8; 92752419Sjulian dlci |= (data[3] & 0xff); 92852419Sjulian } else { 92952419Sjulian if (segsize != 3) { 93052419Sjulian log(LOG_WARNING, 93152419Sjulian "nglmi: DLCI headersize of %d" 93252419Sjulian " not supported\n", segsize - 1); 93352419Sjulian goto reject; 93452419Sjulian } 93552419Sjulian dlci = ((u_short) data[2] & 0x3f) << 4; 93652419Sjulian dlci |= ((data[3] & 0x78) >> 3); 93752419Sjulian } 93852419Sjulian /* async can only have one of these */ 93952419Sjulian#if 0 /* async not yet accepted */ 94052419Sjulian if (async && highest_dlci) { 94152419Sjulian log(LOG_WARNING, 94252419Sjulian "nglmi: Async with > 1 DLCI\n"); 94352419Sjulian goto reject; 94452419Sjulian } 94552419Sjulian#endif 94652419Sjulian /* Annex D says these will always be Ascending, but 94752419Sjulian * the HP test for G4 says we should accept 94852419Sjulian * duplicates, so for now allow that. ( <= vs. < ) */ 94952419Sjulian#if 0 95052419Sjulian /* MCI tests want us to accept out of order for AnxD */ 95152419Sjulian if ((!GROUP4(sc)) && (dlci < highest_dlci)) { 95252419Sjulian /* duplicate or mis-ordered dlci */ 95352419Sjulian /* (spec says they will increase in number) */ 95452419Sjulian log(LOG_WARNING, "nglmi: DLCI out of order\n"); 95552419Sjulian goto reject; 95652419Sjulian } 95752419Sjulian#endif 95852419Sjulian if (dlci > 1023) { 95952419Sjulian log(LOG_WARNING, "nglmi: DLCI out of range\n"); 96052419Sjulian goto reject; 96152419Sjulian } 96252419Sjulian highest_dlci = dlci; 96352419Sjulian break; 96452419Sjulian default: 96552419Sjulian log(LOG_WARNING, 96652419Sjulian "nglmi: unknown LMI segment type %d\n", segtype); 96752419Sjulian } 96852419SjuliannextIE: 96952419Sjulian STEPBY(segsize + 2); 97052419Sjulian } 97152419Sjulian if (packetlen != 0) { /* partial junk at end? */ 97252419Sjulian log(LOG_WARNING, 97352419Sjulian "nglmi: %d bytes extra at end of packet\n", packetlen); 97452419Sjulian goto print; 97552419Sjulian } 97652419Sjulian if (resptype_seen == 0) { 97752419Sjulian log(LOG_WARNING, "nglmi: No response type seen\n"); 97852419Sjulian goto reject; /* had no response type */ 97952419Sjulian } 98052419Sjulian if (seq_seen == 0) { 98152419Sjulian log(LOG_WARNING, "nglmi: No sequence numbers seen\n"); 98252419Sjulian goto reject; /* had no sequence numbers */ 98352419Sjulian } 98452419Sjulian return (1); 98552419Sjulian 98652419Sjulianprint: 98752419Sjulian { 98852419Sjulian int i, j, k, pos; 98952419Sjulian char buf[100]; 99052419Sjulian int loc; 99197897Sarchie const u_char *bp = mtod(m, const u_char *); 99252419Sjulian 99352419Sjulian k = i = 0; 994147163Sru loc = (m->m_len - packetlen); 99552419Sjulian log(LOG_WARNING, "nglmi: error at location %d\n", loc); 996147163Sru while (k < m->m_len) { 99752419Sjulian pos = 0; 99852419Sjulian j = 0; 999147163Sru while ((j++ < 16) && k < m->m_len) { 100052419Sjulian pos += sprintf(buf + pos, "%c%02x", 100152419Sjulian ((loc == k) ? '>' : ' '), 100252419Sjulian bp[k]); 100352419Sjulian k++; 100452419Sjulian } 100552419Sjulian if (i == 0) 100652419Sjulian log(LOG_WARNING, "nglmi: packet data:%s\n", buf); 100752419Sjulian else 100852419Sjulian log(LOG_WARNING, "%04d :%s\n", k, buf); 100952419Sjulian i++; 101052419Sjulian } 101152419Sjulian } 101252419Sjulian return (1); 101352419Sjulianreject: 101452419Sjulian { 101552419Sjulian int i, j, k, pos; 101652419Sjulian char buf[100]; 101752419Sjulian int loc; 101897897Sarchie const u_char *bp = mtod(m, const u_char *); 101952419Sjulian 102052419Sjulian k = i = 0; 1021147163Sru loc = (m->m_len - packetlen); 102252419Sjulian log(LOG_WARNING, "nglmi: error at location %d\n", loc); 1023147163Sru while (k < m->m_len) { 102452419Sjulian pos = 0; 102552419Sjulian j = 0; 1026147163Sru while ((j++ < 16) && k < m->m_len) { 102752419Sjulian pos += sprintf(buf + pos, "%c%02x", 102852419Sjulian ((loc == k) ? '>' : ' '), 102952419Sjulian bp[k]); 103052419Sjulian k++; 103152419Sjulian } 103252419Sjulian if (i == 0) 103352419Sjulian log(LOG_WARNING, "nglmi: packet data:%s\n", buf); 103452419Sjulian else 103552419Sjulian log(LOG_WARNING, "%04d :%s\n", k, buf); 103652419Sjulian i++; 103752419Sjulian } 103852419Sjulian } 103970700Sjulian NG_FREE_M(m); 104052419Sjulian return (0); 104152419Sjulian} 104252419Sjulian 104352419Sjulian/* 104452419Sjulian * Do local shutdown processing.. 104552419Sjulian * Cut any remaining links and free our local resources. 104652419Sjulian */ 104752419Sjulianstatic int 104870700Sjuliannglmi_shutdown(node_p node) 104952419Sjulian{ 105070784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 105152419Sjulian 105270784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 105370784Sjulian NG_NODE_UNREF(sc->node); 1054184205Sdes free(sc, M_NETGRAPH); 105552419Sjulian return (0); 105652419Sjulian} 105752419Sjulian 105852419Sjulian/* 105952419Sjulian * Hook disconnection 106052419Sjulian * For this type, removal of any link except "debug" destroys the node. 106152419Sjulian */ 106252419Sjulianstatic int 106352419Sjuliannglmi_disconnect(hook_p hook) 106452419Sjulian{ 106570784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 106652419Sjulian 106752419Sjulian /* OK to remove debug hook(s) */ 106870784Sjulian if (NG_HOOK_PRIVATE(hook) == NULL) 106952419Sjulian return (0); 107052419Sjulian 107152419Sjulian /* Stop timer if it's currently active */ 107252419Sjulian if (sc->flags & SCF_CONNECTED) 1073140066Sglebius ng_uncallout(&sc->handle, sc->node); 107452419Sjulian 107552419Sjulian /* Self-destruct */ 107670784Sjulian if (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) 107770784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 107852419Sjulian return (0); 107952419Sjulian} 108052419Sjulian 1081