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 <glebius@cell.sick.ru>
This commit is contained in:
parent
04fa3b29f5
commit
a974ba0b70
@ -88,7 +88,25 @@ Transmits and receives raw IP frames.
|
|||||||
Transmits and receives PPP frames.
|
Transmits and receives PPP frames.
|
||||||
.El
|
.El
|
||||||
.Sh CONTROL MESSAGES
|
.Sh CONTROL MESSAGES
|
||||||
This node type only supports the generic control messages.
|
This node type supports the generic control messages, plus the following:
|
||||||
|
.Bl -tag -width foo
|
||||||
|
.It Dv NGM_RFC1490_SETENCAP
|
||||||
|
This command sets encapsulation method for the node.
|
||||||
|
The desired method must be passed as a string message argument,
|
||||||
|
and must be one of the following supported encapsulation modes:
|
||||||
|
.Bl -tag
|
||||||
|
.It Qq ietf-ip
|
||||||
|
IP packets are sent using simple RFC1490/2427 encapsulation.
|
||||||
|
.It Qq ietf-snap
|
||||||
|
IP packets are sent inside SNAP frames.
|
||||||
|
Also conforms to RFC1490/2427.
|
||||||
|
.It Qq cisco
|
||||||
|
IP packets are sent and received using proprietary Cisco encapsulation
|
||||||
|
method.
|
||||||
|
.El
|
||||||
|
.It Dv NGM_RFC1490_GETENCAP
|
||||||
|
This command returns current encapsulation method on the node.
|
||||||
|
.El
|
||||||
.Sh SHUTDOWN
|
.Sh SHUTDOWN
|
||||||
This node shuts down upon receipt of a
|
This node shuts down upon receipt of a
|
||||||
.Dv NGM_SHUTDOWN
|
.Dv NGM_SHUTDOWN
|
||||||
@ -111,6 +129,9 @@ Not all of RFC 1490 is implemented.
|
|||||||
.%T "PPP in Frame Relay"
|
.%T "PPP in Frame Relay"
|
||||||
.%O RFC 1973
|
.%O RFC 1973
|
||||||
.Re
|
.Re
|
||||||
|
.Rs
|
||||||
|
http://www.cisco.com/warp/public/121/frf8modes.pdf
|
||||||
|
.Re
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
|
|
||||||
#include <netgraph/ng_message.h>
|
#include <netgraph/ng_message.h>
|
||||||
#include <netgraph/netgraph.h>
|
#include <netgraph/netgraph.h>
|
||||||
|
#include <netgraph/ng_parse.h>
|
||||||
#include <netgraph/ng_rfc1490.h>
|
#include <netgraph/ng_rfc1490.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -78,12 +79,34 @@
|
|||||||
#define NLPID_ESIS 0x82
|
#define NLPID_ESIS 0x82
|
||||||
#define NLPID_ISIS 0x83
|
#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 */
|
/* Node private data */
|
||||||
struct ng_rfc1490_private {
|
struct ng_rfc1490_private {
|
||||||
hook_p downlink;
|
hook_p downlink;
|
||||||
hook_p ppp;
|
hook_p ppp;
|
||||||
hook_p inet;
|
hook_p inet;
|
||||||
hook_p ethernet;
|
hook_p ethernet;
|
||||||
|
const struct ng_rfc1490_encap_t *enc;
|
||||||
};
|
};
|
||||||
typedef struct ng_rfc1490_private *priv_p;
|
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_rcvdata_t ng_rfc1490_rcvdata;
|
||||||
static ng_disconnect_t ng_rfc1490_disconnect;
|
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 */
|
/* Node type descriptor */
|
||||||
static struct ng_type typestruct = {
|
static struct ng_type typestruct = {
|
||||||
.version = NG_ABI_VERSION,
|
.version = NG_ABI_VERSION,
|
||||||
@ -105,6 +147,7 @@ static struct ng_type typestruct = {
|
|||||||
.newhook = ng_rfc1490_newhook,
|
.newhook = ng_rfc1490_newhook,
|
||||||
.rcvdata = ng_rfc1490_rcvdata,
|
.rcvdata = ng_rfc1490_rcvdata,
|
||||||
.disconnect = ng_rfc1490_disconnect,
|
.disconnect = ng_rfc1490_disconnect,
|
||||||
|
.cmdlist = ng_rfc1490_cmds,
|
||||||
};
|
};
|
||||||
NETGRAPH_INIT(rfc1490, &typestruct);
|
NETGRAPH_INIT(rfc1490, &typestruct);
|
||||||
|
|
||||||
@ -125,6 +168,9 @@ ng_rfc1490_constructor(node_p node)
|
|||||||
if (priv == NULL)
|
if (priv == NULL)
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
|
|
||||||
|
/* Initialize to default encapsulation method - ietf-ip */
|
||||||
|
priv->enc = ng_rfc1490_encaps;
|
||||||
|
|
||||||
NG_NODE_SET_PRIVATE(node, priv);
|
NG_NODE_SET_PRIVATE(node, priv);
|
||||||
|
|
||||||
/* Done */
|
/* 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
|
static int
|
||||||
ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook)
|
ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook)
|
||||||
{
|
{
|
||||||
NG_FREE_ITEM(item);
|
const priv_p priv = NG_NODE_PRIVATE(node);
|
||||||
return (EINVAL);
|
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
|
* Q.922 control
|
||||||
* |
|
* |
|
||||||
* |
|
* |
|
||||||
* --------------------------------------------
|
* ---------------------------------------------------------------------
|
||||||
* | 0x03 |
|
* | 0x03 | |
|
||||||
* UI I Frame
|
* UI I Frame Cisco
|
||||||
* | |
|
* | | Encapsulation
|
||||||
* --------------------------------- --------------
|
* --------------------------------- -------------- |
|
||||||
* | 0x08 | 0x81 |0xCC |0xCF | 0x00 |..01.... |..10....
|
* | 0x08 | 0x81 |0xCC |0xCF | 0x00 |..01.... |..10.... --------------
|
||||||
* | | | | | 0x80 | |
|
* | | | | | 0x80 | | |0x800 |
|
||||||
* Q.933 CLNP IP(*) PPP(*) SNAP ISO 8208 ISO 8208
|
* Q.933 CLNP IP(*) PPP(*) SNAP ISO 8208 ISO 8208 | |
|
||||||
* | (rfc1973) | Modulo 8 Modulo 128
|
* | (rfc1973) | Modulo 8 Modulo 128 IP(*) Others
|
||||||
* | |
|
* | |
|
||||||
* -------------------- OUI
|
* -------------------- OUI
|
||||||
* | | |
|
* | | |
|
||||||
@ -197,13 +295,12 @@ ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook)
|
|||||||
* ------------------- -----------------... ----------
|
* ------------------- -----------------... ----------
|
||||||
* |0x51 |0x4E | |0x4C |0x7 |0xB | |0x806 |
|
* |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 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))
|
#define OUICMP(P,A,B,C) ((P)[0]==(A) && (P)[1]==(B) && (P)[2]==(C))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -224,6 +321,9 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item)
|
|||||||
ERROUT(ENOBUFS);
|
ERROUT(ENOBUFS);
|
||||||
ptr = start = mtod(m, const u_char *);
|
ptr = start = mtod(m, const u_char *);
|
||||||
|
|
||||||
|
if (priv->enc->method == NG_RFC1490_ENCAP_CISCO)
|
||||||
|
goto switch_on_etype;
|
||||||
|
|
||||||
/* Must be UI frame */
|
/* Must be UI frame */
|
||||||
if (*ptr++ != HDLC_UI)
|
if (*ptr++ != HDLC_UI)
|
||||||
ERROUT(0);
|
ERROUT(0);
|
||||||
@ -239,7 +339,7 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item)
|
|||||||
u_int16_t etype;
|
u_int16_t etype;
|
||||||
|
|
||||||
ptr += 3;
|
ptr += 3;
|
||||||
etype = ntohs(*((const u_int16_t *)ptr));
|
switch_on_etype: etype = ntohs(*((const u_int16_t *)ptr));
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
m_adj(m, ptr - start);
|
m_adj(m, ptr - start);
|
||||||
switch (etype) {
|
switch (etype) {
|
||||||
@ -293,11 +393,37 @@ ng_rfc1490_rcvdata(hook_p hook, item_p item)
|
|||||||
mtod(m, u_char *)[1] = NLPID_PPP;
|
mtod(m, u_char *)[1] = NLPID_PPP;
|
||||||
NG_FWD_NEW_DATA(error, item, priv->downlink, m);
|
NG_FWD_NEW_DATA(error, item, priv->downlink, m);
|
||||||
} else if (hook == priv->inet) {
|
} else if (hook == priv->inet) {
|
||||||
|
switch (priv->enc->method) {
|
||||||
|
case NG_RFC1490_ENCAP_IETF_IP:
|
||||||
M_PREPEND(m, 2, M_DONTWAIT); /* Prepend IP NLPID */
|
M_PREPEND(m, 2, M_DONTWAIT); /* Prepend IP NLPID */
|
||||||
if (!m)
|
if (!m)
|
||||||
ERROUT(ENOBUFS);
|
ERROUT(ENOBUFS);
|
||||||
mtod(m, u_char *)[0] = HDLC_UI;
|
mtod(m, u_char *)[0] = HDLC_UI;
|
||||||
mtod(m, u_char *)[1] = NLPID_IP;
|
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);
|
NG_FWD_NEW_DATA(error, item, priv->downlink, m);
|
||||||
} else if (hook == priv->ethernet) {
|
} else if (hook == priv->ethernet) {
|
||||||
M_PREPEND(m, 8, M_DONTWAIT); /* Prepend NLPID, OUI, PID */
|
M_PREPEND(m, 8, M_DONTWAIT); /* Prepend NLPID, OUI, PID */
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* ng_rfc1490.h
|
* ng_rfc1490.h
|
||||||
*
|
*
|
||||||
@ -45,7 +44,7 @@
|
|||||||
|
|
||||||
/* Node type name */
|
/* Node type name */
|
||||||
#define NG_RFC1490_NODE_TYPE "rfc1490"
|
#define NG_RFC1490_NODE_TYPE "rfc1490"
|
||||||
#define NGM_RFC1490_COOKIE 861060632
|
#define NGM_RFC1490_COOKIE 1086947474
|
||||||
|
|
||||||
/* Hook names */
|
/* Hook names */
|
||||||
#define NG_RFC1490_HOOK_DOWNSTREAM "downstream"
|
#define NG_RFC1490_HOOK_DOWNSTREAM "downstream"
|
||||||
@ -53,4 +52,10 @@
|
|||||||
#define NG_RFC1490_HOOK_PPP "ppp"
|
#define NG_RFC1490_HOOK_PPP "ppp"
|
||||||
#define NG_RFC1490_HOOK_ETHERNET "ethernet"
|
#define NG_RFC1490_HOOK_ETHERNET "ethernet"
|
||||||
|
|
||||||
|
/* Netgraph commands */
|
||||||
|
enum {
|
||||||
|
NGM_RFC1490_SET_ENCAP, /* sets encapsulation method */
|
||||||
|
NGM_RFC1490_GET_ENCAP, /* gets current encapsulation method */
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _NETGRAPH_NG_RFC1490_H_ */
|
#endif /* _NETGRAPH_NG_RFC1490_H_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user