From dc9a24e5fa24af15022eb5ccfb420d0c55bc476e Mon Sep 17 00:00:00 2001 From: julian Date: Sun, 13 Jun 2004 15:44:00 +0000 Subject: Add the capacity for the rfc1490 node to handle cisco style encasulation which is often used alongside rfc1490 in frame relay links. Submitted by: Gleb Smirnoff --- sys/netgraph/ng_rfc1490.c | 168 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 147 insertions(+), 21 deletions(-) (limited to 'sys/netgraph/ng_rfc1490.c') diff --git a/sys/netgraph/ng_rfc1490.c b/sys/netgraph/ng_rfc1490.c index 01589c3..451828d 100644 --- a/sys/netgraph/ng_rfc1490.c +++ b/sys/netgraph/ng_rfc1490.c @@ -61,6 +61,7 @@ #include #include +#include #include /* @@ -78,12 +79,34 @@ #define NLPID_ESIS 0x82 #define NLPID_ISIS 0x83 +#define ERROUT(x) do { error = (x); goto done; } while (0) + +/* Encapsulation methods we understand */ +enum { + NG_RFC1490_ENCAP_IETF_IP = 1, /* see RFC2427, chapter 7, table 1 */ + NG_RFC1490_ENCAP_IETF_SNAP, /* see RFC2427, chapter 7, table 2 */ + NG_RFC1490_ENCAP_CISCO, /* Cisco's proprietary encapsulation */ +}; + +struct ng_rfc1490_encap_t { + u_int8_t method; + const char *name; +}; + +static const struct ng_rfc1490_encap_t ng_rfc1490_encaps[] = { + { NG_RFC1490_ENCAP_IETF_IP, "ietf-ip" }, + { NG_RFC1490_ENCAP_IETF_SNAP, "ietf-snap" }, + { NG_RFC1490_ENCAP_CISCO, "cisco" }, + { 0, NULL}, +}; + /* Node private data */ struct ng_rfc1490_private { hook_p downlink; hook_p ppp; hook_p inet; hook_p ethernet; + const struct ng_rfc1490_encap_t *enc; }; typedef struct ng_rfc1490_private *priv_p; @@ -95,6 +118,25 @@ static ng_newhook_t ng_rfc1490_newhook; static ng_rcvdata_t ng_rfc1490_rcvdata; static ng_disconnect_t ng_rfc1490_disconnect; +/* List of commands and how to convert arguments to/from ASCII */ +static const struct ng_cmdlist ng_rfc1490_cmds[] = { + { + NGM_RFC1490_COOKIE, + NGM_RFC1490_SET_ENCAP, + "setencap", + &ng_parse_string_type, + NULL + }, + { + NGM_RFC1490_COOKIE, + NGM_RFC1490_GET_ENCAP, + "getencap", + NULL, + &ng_parse_string_type + }, + { 0 } +}; + /* Node type descriptor */ static struct ng_type typestruct = { .version = NG_ABI_VERSION, @@ -105,6 +147,7 @@ static struct ng_type typestruct = { .newhook = ng_rfc1490_newhook, .rcvdata = ng_rfc1490_rcvdata, .disconnect = ng_rfc1490_disconnect, + .cmdlist = ng_rfc1490_cmds, }; NETGRAPH_INIT(rfc1490, &typestruct); @@ -125,6 +168,9 @@ ng_rfc1490_constructor(node_p node) if (priv == NULL) return (ENOMEM); + /* Initialize to default encapsulation method - ietf-ip */ + priv->enc = ng_rfc1490_encaps; + NG_NODE_SET_PRIVATE(node, priv); /* Done */ @@ -161,13 +207,65 @@ ng_rfc1490_newhook(node_p node, hook_p hook, const char *name) } /* - * Receive a control message. We don't support any special ones. + * Receive a control message. */ static int ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook) { - NG_FREE_ITEM(item); - return (EINVAL); + const priv_p priv = NG_NODE_PRIVATE(node); + struct ng_mesg *msg; + struct ng_mesg *resp = NULL; + int error = 0; + + NGI_GET_MSG(item, msg); + + if (msg->header.typecookie == NGM_RFC1490_COOKIE) { + switch (msg->header.cmd) { + case NGM_RFC1490_SET_ENCAP: + { + const struct ng_rfc1490_encap_t *enc; + char *s; + size_t len; + + if (msg->header.arglen == 0) + ERROUT(EINVAL); + + s = (char *)msg->data; + len = msg->header.arglen - 1; + + /* Search for matching encapsulation method */ + for (enc = ng_rfc1490_encaps; enc->method != 0; enc++ ) + if ((strlen(enc->name) == len) && + !strncmp(enc->name, s, len)) + break; /* found */ + + if (enc->method != 0) + priv->enc = enc; + else + error = EINVAL; + break; + } + case NGM_RFC1490_GET_ENCAP: + + NG_MKRESPONSE(resp, msg, strlen(priv->enc->name) + 1, M_NOWAIT); + if (resp == NULL) + ERROUT(ENOMEM); + + strlcpy((char *)resp->data, priv->enc->name, + strlen(priv->enc->name) + 1); + break; + + default: + error = EINVAL; + break; + } + } else + error = EINVAL; + +done: + NG_RESPOND_MSG(error, node, item, resp); + NG_FREE_MSG(msg); + return (error); } /* @@ -177,15 +275,15 @@ ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook) * Q.922 control * | * | - * -------------------------------------------- - * | 0x03 | - * UI I Frame - * | | - * --------------------------------- -------------- - * | 0x08 | 0x81 |0xCC |0xCF | 0x00 |..01.... |..10.... - * | | | | | 0x80 | | - * Q.933 CLNP IP(*) PPP(*) SNAP ISO 8208 ISO 8208 - * | (rfc1973) | Modulo 8 Modulo 128 + * --------------------------------------------------------------------- + * | 0x03 | | + * UI I Frame Cisco + * | | Encapsulation + * --------------------------------- -------------- | + * | 0x08 | 0x81 |0xCC |0xCF | 0x00 |..01.... |..10.... -------------- + * | | | | | 0x80 | | |0x800 | + * Q.933 CLNP IP(*) PPP(*) SNAP ISO 8208 ISO 8208 | | + * | (rfc1973) | Modulo 8 Modulo 128 IP(*) Others * | | * -------------------- OUI * | | | @@ -197,13 +295,12 @@ ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook) * ------------------- -----------------... ---------- * |0x51 |0x4E | |0x4C |0x7 |0xB | |0x806 | * | | | | | | | | | - * 7776 Q.922 Others 802.2 802.3(*) 802.6 Others ARP(*) Others + * 7776 Q.922 Others 802.2 802.3(*) 802.6 Others IP(*) Others * * */ #define MAX_ENCAPS_HDR 8 -#define ERROUT(x) do { error = (x); goto done; } while (0) #define OUICMP(P,A,B,C) ((P)[0]==(A) && (P)[1]==(B) && (P)[2]==(C)) static int @@ -224,6 +321,9 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item) ERROUT(ENOBUFS); ptr = start = mtod(m, const u_char *); + if (priv->enc->method == NG_RFC1490_ENCAP_CISCO) + goto switch_on_etype; + /* Must be UI frame */ if (*ptr++ != HDLC_UI) ERROUT(0); @@ -239,7 +339,7 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item) u_int16_t etype; ptr += 3; - etype = ntohs(*((const u_int16_t *)ptr)); +switch_on_etype: etype = ntohs(*((const u_int16_t *)ptr)); ptr += 2; m_adj(m, ptr - start); switch (etype) { @@ -256,7 +356,7 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item) /* 802.1 bridging */ ptr += 3; if (*ptr++ != 0x00) - ERROUT(0); /* unknown PID octet 0 */ + ERROUT(0); /* unknown PID octet 0 */ if (*ptr++ != 0x07) ERROUT(0); /* not FCS-less 802.3 */ m_adj(m, ptr - start); @@ -293,11 +393,37 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item) mtod(m, u_char *)[1] = NLPID_PPP; NG_FWD_NEW_DATA(error, item, priv->downlink, m); } else if (hook == priv->inet) { - M_PREPEND(m, 2, M_DONTWAIT); /* Prepend IP NLPID */ - if (!m) - ERROUT(ENOBUFS); - mtod(m, u_char *)[0] = HDLC_UI; - mtod(m, u_char *)[1] = NLPID_IP; + switch (priv->enc->method) { + case NG_RFC1490_ENCAP_IETF_IP: + M_PREPEND(m, 2, M_DONTWAIT); /* Prepend IP NLPID */ + if (!m) + ERROUT(ENOBUFS); + mtod(m, u_char *)[0] = HDLC_UI; + mtod(m, u_char *)[1] = NLPID_IP; + break; + case NG_RFC1490_ENCAP_IETF_SNAP: + /* + * According to RFC2427 frame should begin with + * HDLC_UI PAD NLIPID OUI PID + * 03 00 80 00 00 00 08 00 + */ + M_PREPEND(m, 8, M_DONTWAIT); + if (!m) + ERROUT(ENOBUFS); + mtod(m, u_char *)[0] = HDLC_UI; + mtod(m, u_char *)[1] = 0x00; /* PAD */ + mtod(m, u_char *)[2] = NLPID_SNAP; + bzero((char *)(mtod(m, u_char *) + 3), 3); /* OUI 0-0-0 */ + *((u_int16_t *)mtod(m, u_int16_t *) + 6/sizeof(u_int16_t)) + = htons(ETHERTYPE_IP); /* PID */ + break; + case NG_RFC1490_ENCAP_CISCO: + M_PREPEND(m, 2, M_DONTWAIT); /* Prepend IP ethertype */ + if (!m) + ERROUT(ENOBUFS); + *((u_int16_t *)mtod(m, u_int16_t *)) = htons(ETHERTYPE_IP); + break; + } NG_FWD_NEW_DATA(error, item, priv->downlink, m); } else if (hook == priv->ethernet) { M_PREPEND(m, 8, M_DONTWAIT); /* Prepend NLPID, OUI, PID */ -- cgit v1.1