14cf49a43SJulian Elischer /*
24cf49a43SJulian Elischer * ng_rfc1490.c
3c398230bSWarner Losh */
4c398230bSWarner Losh
5c398230bSWarner Losh /*-
64cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc.
74cf49a43SJulian Elischer * All rights reserved.
84cf49a43SJulian Elischer *
94cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and
104cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or
114cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications;
124cf49a43SJulian Elischer * provided, however, that:
134cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the
144cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and
154cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle
164cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE
174cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
184cf49a43SJulian Elischer * such appears in the above copyright notice or in the software.
194cf49a43SJulian Elischer *
204cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
214cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
224cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
234cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
244cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
254cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
264cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
274cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
284cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
294cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
304cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
314cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
324cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
334cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
344cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
354cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
364cf49a43SJulian Elischer * OF SUCH DAMAGE.
374cf49a43SJulian Elischer *
38cc3bbd68SJulian Elischer * Author: Julian Elischer <julian@freebsd.org>
3974f5c6aaSJulian Elischer * $Whistle: ng_rfc1490.c,v 1.22 1999/11/01 09:24:52 julian Exp $
404cf49a43SJulian Elischer */
414cf49a43SJulian Elischer
424cf49a43SJulian Elischer /*
434cf49a43SJulian Elischer * This node does RFC 1490 multiplexing.
444cf49a43SJulian Elischer *
454cf49a43SJulian Elischer * NOTE: RFC 1490 is updated by RFC 2427.
464cf49a43SJulian Elischer */
474cf49a43SJulian Elischer
484cf49a43SJulian Elischer #include <sys/param.h>
494cf49a43SJulian Elischer #include <sys/systm.h>
504cf49a43SJulian Elischer #include <sys/errno.h>
514cf49a43SJulian Elischer #include <sys/kernel.h>
524cf49a43SJulian Elischer #include <sys/malloc.h>
534cf49a43SJulian Elischer #include <sys/mbuf.h>
544cf49a43SJulian Elischer #include <sys/errno.h>
554cf49a43SJulian Elischer #include <sys/socket.h>
564cf49a43SJulian Elischer
574cf49a43SJulian Elischer #include <net/if.h>
584cf49a43SJulian Elischer #include <netinet/in.h>
594cf49a43SJulian Elischer #include <netinet/if_ether.h>
604cf49a43SJulian Elischer
614cf49a43SJulian Elischer #include <netgraph/ng_message.h>
624cf49a43SJulian Elischer #include <netgraph/netgraph.h>
63a974ba0bSJulian Elischer #include <netgraph/ng_parse.h>
644cf49a43SJulian Elischer #include <netgraph/ng_rfc1490.h>
654cf49a43SJulian Elischer
664cf49a43SJulian Elischer /*
674cf49a43SJulian Elischer * DEFINITIONS
684cf49a43SJulian Elischer */
694cf49a43SJulian Elischer
704cf49a43SJulian Elischer /* Q.922 stuff -- see RFC 1490 */
714cf49a43SJulian Elischer #define HDLC_UI 0x03
724cf49a43SJulian Elischer
734cf49a43SJulian Elischer #define NLPID_IP 0xCC
744cf49a43SJulian Elischer #define NLPID_PPP 0xCF
754cf49a43SJulian Elischer #define NLPID_SNAP 0x80
764cf49a43SJulian Elischer #define NLPID_Q933 0x08
774cf49a43SJulian Elischer #define NLPID_CLNP 0x81
784cf49a43SJulian Elischer #define NLPID_ESIS 0x82
794cf49a43SJulian Elischer #define NLPID_ISIS 0x83
804cf49a43SJulian Elischer
81a974ba0bSJulian Elischer #define ERROUT(x) do { error = (x); goto done; } while (0)
82a974ba0bSJulian Elischer
83a974ba0bSJulian Elischer /* Encapsulation methods we understand */
84a974ba0bSJulian Elischer enum {
85a974ba0bSJulian Elischer NG_RFC1490_ENCAP_IETF_IP = 1, /* see RFC2427, chapter 7, table 1 */
86a974ba0bSJulian Elischer NG_RFC1490_ENCAP_IETF_SNAP, /* see RFC2427, chapter 7, table 2 */
87a974ba0bSJulian Elischer NG_RFC1490_ENCAP_CISCO, /* Cisco's proprietary encapsulation */
88a974ba0bSJulian Elischer };
89a974ba0bSJulian Elischer
90a974ba0bSJulian Elischer struct ng_rfc1490_encap_t {
91a974ba0bSJulian Elischer u_int8_t method;
92a974ba0bSJulian Elischer const char *name;
93a974ba0bSJulian Elischer };
94a974ba0bSJulian Elischer
95a974ba0bSJulian Elischer static const struct ng_rfc1490_encap_t ng_rfc1490_encaps[] = {
96a974ba0bSJulian Elischer { NG_RFC1490_ENCAP_IETF_IP, "ietf-ip" },
97a974ba0bSJulian Elischer { NG_RFC1490_ENCAP_IETF_SNAP, "ietf-snap" },
98a974ba0bSJulian Elischer { NG_RFC1490_ENCAP_CISCO, "cisco" },
99a974ba0bSJulian Elischer { 0, NULL},
100a974ba0bSJulian Elischer };
101a974ba0bSJulian Elischer
1024cf49a43SJulian Elischer /* Node private data */
1030e97a08fSArchie Cobbs struct ng_rfc1490_private {
1044cf49a43SJulian Elischer hook_p downlink;
1054cf49a43SJulian Elischer hook_p ppp;
1064cf49a43SJulian Elischer hook_p inet;
1077586b25cSBrian Feldman hook_p ethernet;
108a974ba0bSJulian Elischer const struct ng_rfc1490_encap_t *enc;
1094cf49a43SJulian Elischer };
1100e97a08fSArchie Cobbs typedef struct ng_rfc1490_private *priv_p;
1114cf49a43SJulian Elischer
1124cf49a43SJulian Elischer /* Netgraph node methods */
11374f5c6aaSJulian Elischer static ng_constructor_t ng_rfc1490_constructor;
11474f5c6aaSJulian Elischer static ng_rcvmsg_t ng_rfc1490_rcvmsg;
115069154d5SJulian Elischer static ng_shutdown_t ng_rfc1490_shutdown;
11674f5c6aaSJulian Elischer static ng_newhook_t ng_rfc1490_newhook;
11774f5c6aaSJulian Elischer static ng_rcvdata_t ng_rfc1490_rcvdata;
11874f5c6aaSJulian Elischer static ng_disconnect_t ng_rfc1490_disconnect;
1194cf49a43SJulian Elischer
120a974ba0bSJulian Elischer /* List of commands and how to convert arguments to/from ASCII */
121a974ba0bSJulian Elischer static const struct ng_cmdlist ng_rfc1490_cmds[] = {
122a974ba0bSJulian Elischer {
123a974ba0bSJulian Elischer NGM_RFC1490_COOKIE,
124a974ba0bSJulian Elischer NGM_RFC1490_SET_ENCAP,
125a974ba0bSJulian Elischer "setencap",
126a974ba0bSJulian Elischer &ng_parse_string_type,
127a974ba0bSJulian Elischer NULL
128a974ba0bSJulian Elischer },
129a974ba0bSJulian Elischer {
130a974ba0bSJulian Elischer NGM_RFC1490_COOKIE,
131a974ba0bSJulian Elischer NGM_RFC1490_GET_ENCAP,
132a974ba0bSJulian Elischer "getencap",
133a974ba0bSJulian Elischer NULL,
134a974ba0bSJulian Elischer &ng_parse_string_type
135a974ba0bSJulian Elischer },
136a974ba0bSJulian Elischer { 0 }
137a974ba0bSJulian Elischer };
138a974ba0bSJulian Elischer
1394cf49a43SJulian Elischer /* Node type descriptor */
1404cf49a43SJulian Elischer static struct ng_type typestruct = {
141f8aae777SJulian Elischer .version = NG_ABI_VERSION,
142f8aae777SJulian Elischer .name = NG_RFC1490_NODE_TYPE,
143f8aae777SJulian Elischer .constructor = ng_rfc1490_constructor,
144f8aae777SJulian Elischer .rcvmsg = ng_rfc1490_rcvmsg,
145f8aae777SJulian Elischer .shutdown = ng_rfc1490_shutdown,
146f8aae777SJulian Elischer .newhook = ng_rfc1490_newhook,
147f8aae777SJulian Elischer .rcvdata = ng_rfc1490_rcvdata,
148f8aae777SJulian Elischer .disconnect = ng_rfc1490_disconnect,
149a974ba0bSJulian Elischer .cmdlist = ng_rfc1490_cmds,
1504cf49a43SJulian Elischer };
1514cf49a43SJulian Elischer NETGRAPH_INIT(rfc1490, &typestruct);
1524cf49a43SJulian Elischer
1534cf49a43SJulian Elischer /************************************************************************
1544cf49a43SJulian Elischer NETGRAPH NODE STUFF
1554cf49a43SJulian Elischer ************************************************************************/
1564cf49a43SJulian Elischer
1574cf49a43SJulian Elischer /*
1584cf49a43SJulian Elischer * Node constructor
1594cf49a43SJulian Elischer */
1604cf49a43SJulian Elischer static int
ng_rfc1490_constructor(node_p node)161069154d5SJulian Elischer ng_rfc1490_constructor(node_p node)
1624cf49a43SJulian Elischer {
1634cf49a43SJulian Elischer priv_p priv;
1644cf49a43SJulian Elischer
1654cf49a43SJulian Elischer /* Allocate private structure */
166674d86bfSGleb Smirnoff priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
1674cf49a43SJulian Elischer
168a974ba0bSJulian Elischer /* Initialize to default encapsulation method - ietf-ip */
169a974ba0bSJulian Elischer priv->enc = ng_rfc1490_encaps;
170a974ba0bSJulian Elischer
17130400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, priv);
1724cf49a43SJulian Elischer
1734cf49a43SJulian Elischer /* Done */
1744cf49a43SJulian Elischer return (0);
1754cf49a43SJulian Elischer }
1764cf49a43SJulian Elischer
1774cf49a43SJulian Elischer /*
1784cf49a43SJulian Elischer * Give our ok for a hook to be added
1794cf49a43SJulian Elischer */
1804cf49a43SJulian Elischer static int
ng_rfc1490_newhook(node_p node,hook_p hook,const char * name)1814cf49a43SJulian Elischer ng_rfc1490_newhook(node_p node, hook_p hook, const char *name)
1824cf49a43SJulian Elischer {
18330400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
1844cf49a43SJulian Elischer
1854cf49a43SJulian Elischer if (!strcmp(name, NG_RFC1490_HOOK_DOWNSTREAM)) {
1864cf49a43SJulian Elischer if (priv->downlink)
1874cf49a43SJulian Elischer return (EISCONN);
1884cf49a43SJulian Elischer priv->downlink = hook;
1894cf49a43SJulian Elischer } else if (!strcmp(name, NG_RFC1490_HOOK_PPP)) {
1904cf49a43SJulian Elischer if (priv->ppp)
1914cf49a43SJulian Elischer return (EISCONN);
1924cf49a43SJulian Elischer priv->ppp = hook;
1934cf49a43SJulian Elischer } else if (!strcmp(name, NG_RFC1490_HOOK_INET)) {
1944cf49a43SJulian Elischer if (priv->inet)
1954cf49a43SJulian Elischer return (EISCONN);
1964cf49a43SJulian Elischer priv->inet = hook;
1977586b25cSBrian Feldman } else if (!strcmp(name, NG_RFC1490_HOOK_ETHERNET)) {
1987586b25cSBrian Feldman if (priv->ethernet)
1997586b25cSBrian Feldman return (EISCONN);
2007586b25cSBrian Feldman priv->ethernet = hook;
2014cf49a43SJulian Elischer } else
2024cf49a43SJulian Elischer return (EINVAL);
2034cf49a43SJulian Elischer return (0);
2044cf49a43SJulian Elischer }
2054cf49a43SJulian Elischer
2064cf49a43SJulian Elischer /*
207a974ba0bSJulian Elischer * Receive a control message.
2084cf49a43SJulian Elischer */
2094cf49a43SJulian Elischer static int
ng_rfc1490_rcvmsg(node_p node,item_p item,hook_p lasthook)210069154d5SJulian Elischer ng_rfc1490_rcvmsg(node_p node, item_p item, hook_p lasthook)
2114cf49a43SJulian Elischer {
212a974ba0bSJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
213a974ba0bSJulian Elischer struct ng_mesg *msg;
214a974ba0bSJulian Elischer struct ng_mesg *resp = NULL;
215a974ba0bSJulian Elischer int error = 0;
216a974ba0bSJulian Elischer
217a974ba0bSJulian Elischer NGI_GET_MSG(item, msg);
218a974ba0bSJulian Elischer
219a974ba0bSJulian Elischer if (msg->header.typecookie == NGM_RFC1490_COOKIE) {
220a974ba0bSJulian Elischer switch (msg->header.cmd) {
221a974ba0bSJulian Elischer case NGM_RFC1490_SET_ENCAP:
222a974ba0bSJulian Elischer {
223a974ba0bSJulian Elischer const struct ng_rfc1490_encap_t *enc;
224a974ba0bSJulian Elischer char *s;
225a974ba0bSJulian Elischer size_t len;
226a974ba0bSJulian Elischer
227a974ba0bSJulian Elischer if (msg->header.arglen == 0)
228a974ba0bSJulian Elischer ERROUT(EINVAL);
229a974ba0bSJulian Elischer
230a974ba0bSJulian Elischer s = (char *)msg->data;
231a974ba0bSJulian Elischer len = msg->header.arglen - 1;
232a974ba0bSJulian Elischer
233a974ba0bSJulian Elischer /* Search for matching encapsulation method */
234a974ba0bSJulian Elischer for (enc = ng_rfc1490_encaps; enc->method != 0; enc++ )
235a974ba0bSJulian Elischer if ((strlen(enc->name) == len) &&
236a974ba0bSJulian Elischer !strncmp(enc->name, s, len))
237a974ba0bSJulian Elischer break; /* found */
238a974ba0bSJulian Elischer
239a974ba0bSJulian Elischer if (enc->method != 0)
240a974ba0bSJulian Elischer priv->enc = enc;
241a974ba0bSJulian Elischer else
242a974ba0bSJulian Elischer error = EINVAL;
243a974ba0bSJulian Elischer break;
244a974ba0bSJulian Elischer }
245a974ba0bSJulian Elischer case NGM_RFC1490_GET_ENCAP:
246a974ba0bSJulian Elischer
247a974ba0bSJulian Elischer NG_MKRESPONSE(resp, msg, strlen(priv->enc->name) + 1, M_NOWAIT);
248a974ba0bSJulian Elischer if (resp == NULL)
249a974ba0bSJulian Elischer ERROUT(ENOMEM);
250a974ba0bSJulian Elischer
251a974ba0bSJulian Elischer strlcpy((char *)resp->data, priv->enc->name,
252a974ba0bSJulian Elischer strlen(priv->enc->name) + 1);
253a974ba0bSJulian Elischer break;
254a974ba0bSJulian Elischer
255a974ba0bSJulian Elischer default:
256a974ba0bSJulian Elischer error = EINVAL;
257a974ba0bSJulian Elischer break;
258a974ba0bSJulian Elischer }
259a974ba0bSJulian Elischer } else
260a974ba0bSJulian Elischer error = EINVAL;
261a974ba0bSJulian Elischer
262a974ba0bSJulian Elischer done:
263a974ba0bSJulian Elischer NG_RESPOND_MSG(error, node, item, resp);
264a974ba0bSJulian Elischer NG_FREE_MSG(msg);
265a974ba0bSJulian Elischer return (error);
2664cf49a43SJulian Elischer }
2674cf49a43SJulian Elischer
2684cf49a43SJulian Elischer /*
2694cf49a43SJulian Elischer * Receive data on a hook and encapsulate according to RFC 1490.
2704cf49a43SJulian Elischer * Only those nodes marked (*) are supported by this routine so far.
2714cf49a43SJulian Elischer *
2724cf49a43SJulian Elischer * Q.922 control
2734cf49a43SJulian Elischer * |
2744cf49a43SJulian Elischer * |
275a974ba0bSJulian Elischer * ---------------------------------------------------------------------
276a974ba0bSJulian Elischer * | 0x03 | |
277a974ba0bSJulian Elischer * UI I Frame Cisco
278a974ba0bSJulian Elischer * | | Encapsulation
279a974ba0bSJulian Elischer * --------------------------------- -------------- |
280a974ba0bSJulian Elischer * | 0x08 | 0x81 |0xCC |0xCF | 0x00 |..01.... |..10.... --------------
281a974ba0bSJulian Elischer * | | | | | 0x80 | | |0x800 |
282a974ba0bSJulian Elischer * Q.933 CLNP IP(*) PPP(*) SNAP ISO 8208 ISO 8208 | |
283a974ba0bSJulian Elischer * | (rfc1973) | Modulo 8 Modulo 128 IP(*) Others
2844cf49a43SJulian Elischer * | |
2854cf49a43SJulian Elischer * -------------------- OUI
2864cf49a43SJulian Elischer * | | |
2874cf49a43SJulian Elischer * L2 ID L3 ID -------------------------
2884cf49a43SJulian Elischer * | User |00-80-C2 |00-00-00
2894cf49a43SJulian Elischer * | specified | |
2904cf49a43SJulian Elischer * | 0x70 PID Ethertype
2914cf49a43SJulian Elischer * | | |
2927586b25cSBrian Feldman * ------------------- -----------------... ----------
2937586b25cSBrian Feldman * |0x51 |0x4E | |0x4C |0x7 |0xB | |0x806 |
2944cf49a43SJulian Elischer * | | | | | | | | |
295a974ba0bSJulian Elischer * 7776 Q.922 Others 802.2 802.3(*) 802.6 Others IP(*) Others
2964cf49a43SJulian Elischer *
2974cf49a43SJulian Elischer *
2984cf49a43SJulian Elischer */
2994cf49a43SJulian Elischer
3004cf49a43SJulian Elischer #define MAX_ENCAPS_HDR 8
3014cf49a43SJulian Elischer #define OUICMP(P,A,B,C) ((P)[0]==(A) && (P)[1]==(B) && (P)[2]==(C))
3024cf49a43SJulian Elischer
3034cf49a43SJulian Elischer static int
ng_rfc1490_rcvdata(hook_p hook,item_p item)304069154d5SJulian Elischer ng_rfc1490_rcvdata(hook_p hook, item_p item)
3054cf49a43SJulian Elischer {
30630400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook);
30730400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
3084cf49a43SJulian Elischer int error = 0;
309069154d5SJulian Elischer struct mbuf *m;
3104cf49a43SJulian Elischer
311069154d5SJulian Elischer NGI_GET_M(item, m);
3124cf49a43SJulian Elischer if (hook == priv->downlink) {
313816b834fSArchie Cobbs const u_char *start;
314816b834fSArchie Cobbs const u_char *ptr;
3154cf49a43SJulian Elischer
3161cf3fa79SJulian Elischer if (m->m_len < MAX_ENCAPS_HDR
3171cf3fa79SJulian Elischer && !(m = m_pullup(m, MAX_ENCAPS_HDR)))
3184cf49a43SJulian Elischer ERROUT(ENOBUFS);
319816b834fSArchie Cobbs ptr = start = mtod(m, const u_char *);
3204cf49a43SJulian Elischer
321a974ba0bSJulian Elischer if (priv->enc->method == NG_RFC1490_ENCAP_CISCO)
322a974ba0bSJulian Elischer goto switch_on_etype;
323a974ba0bSJulian Elischer
3244cf49a43SJulian Elischer /* Must be UI frame */
3254cf49a43SJulian Elischer if (*ptr++ != HDLC_UI)
3264cf49a43SJulian Elischer ERROUT(0);
3274cf49a43SJulian Elischer
3284cf49a43SJulian Elischer /* Eat optional zero pad byte */
3294cf49a43SJulian Elischer if (*ptr == 0x00)
3304cf49a43SJulian Elischer ptr++;
3314cf49a43SJulian Elischer
3324cf49a43SJulian Elischer /* Multiplex on NLPID */
3334cf49a43SJulian Elischer switch (*ptr++) {
3344cf49a43SJulian Elischer case NLPID_SNAP:
3354cf49a43SJulian Elischer if (OUICMP(ptr, 0, 0, 0)) { /* It's an ethertype */
3364cf49a43SJulian Elischer u_int16_t etype;
3374cf49a43SJulian Elischer
3384cf49a43SJulian Elischer ptr += 3;
339a974ba0bSJulian Elischer switch_on_etype: etype = ntohs(*((const u_int16_t *)ptr));
3404cf49a43SJulian Elischer ptr += 2;
3414cf49a43SJulian Elischer m_adj(m, ptr - start);
3424cf49a43SJulian Elischer switch (etype) {
3434cf49a43SJulian Elischer case ETHERTYPE_IP:
344069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item,
345069154d5SJulian Elischer priv->inet, m);
3464cf49a43SJulian Elischer break;
3474cf49a43SJulian Elischer case ETHERTYPE_ARP:
3484cf49a43SJulian Elischer case ETHERTYPE_REVARP:
3494cf49a43SJulian Elischer default:
3504cf49a43SJulian Elischer ERROUT(0);
3514cf49a43SJulian Elischer }
3527586b25cSBrian Feldman } else if (OUICMP(ptr, 0x00, 0x80, 0xc2)) {
3537586b25cSBrian Feldman /* 802.1 bridging */
3547586b25cSBrian Feldman ptr += 3;
3557586b25cSBrian Feldman if (*ptr++ != 0x00)
3567586b25cSBrian Feldman ERROUT(0); /* unknown PID octet 0 */
3577586b25cSBrian Feldman if (*ptr++ != 0x07)
3587586b25cSBrian Feldman ERROUT(0); /* not FCS-less 802.3 */
3597586b25cSBrian Feldman m_adj(m, ptr - start);
3607586b25cSBrian Feldman NG_FWD_NEW_DATA(error, item, priv->ethernet, m);
3617586b25cSBrian Feldman } else /* Other weird stuff... */
3624cf49a43SJulian Elischer ERROUT(0);
3634cf49a43SJulian Elischer break;
3644cf49a43SJulian Elischer case NLPID_IP:
3654cf49a43SJulian Elischer m_adj(m, ptr - start);
366069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, priv->inet, m);
3674cf49a43SJulian Elischer break;
3684cf49a43SJulian Elischer case NLPID_PPP:
3694cf49a43SJulian Elischer m_adj(m, ptr - start);
370069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, priv->ppp, m);
3714cf49a43SJulian Elischer break;
3724cf49a43SJulian Elischer case NLPID_Q933:
3734cf49a43SJulian Elischer case NLPID_CLNP:
3744cf49a43SJulian Elischer case NLPID_ESIS:
3754cf49a43SJulian Elischer case NLPID_ISIS:
3764cf49a43SJulian Elischer ERROUT(0);
3774cf49a43SJulian Elischer default: /* Try PPP (see RFC 1973) */
3784cf49a43SJulian Elischer ptr--; /* NLPID becomes PPP proto */
3794cf49a43SJulian Elischer if ((*ptr & 0x01) == 0x01)
3804cf49a43SJulian Elischer ERROUT(0);
3814cf49a43SJulian Elischer m_adj(m, ptr - start);
382069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, priv->ppp, m);
3834cf49a43SJulian Elischer break;
3844cf49a43SJulian Elischer }
3854cf49a43SJulian Elischer } else if (hook == priv->ppp) {
386*eb1b1807SGleb Smirnoff M_PREPEND(m, 2, M_NOWAIT); /* Prepend PPP NLPID */
3874cf49a43SJulian Elischer if (!m)
3884cf49a43SJulian Elischer ERROUT(ENOBUFS);
3894cf49a43SJulian Elischer mtod(m, u_char *)[0] = HDLC_UI;
3904cf49a43SJulian Elischer mtod(m, u_char *)[1] = NLPID_PPP;
391069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, priv->downlink, m);
3924cf49a43SJulian Elischer } else if (hook == priv->inet) {
393a974ba0bSJulian Elischer switch (priv->enc->method) {
394a974ba0bSJulian Elischer case NG_RFC1490_ENCAP_IETF_IP:
395*eb1b1807SGleb Smirnoff M_PREPEND(m, 2, M_NOWAIT); /* Prepend IP NLPID */
3964cf49a43SJulian Elischer if (!m)
3974cf49a43SJulian Elischer ERROUT(ENOBUFS);
3984cf49a43SJulian Elischer mtod(m, u_char *)[0] = HDLC_UI;
3994cf49a43SJulian Elischer mtod(m, u_char *)[1] = NLPID_IP;
400a974ba0bSJulian Elischer break;
401a974ba0bSJulian Elischer case NG_RFC1490_ENCAP_IETF_SNAP:
402a974ba0bSJulian Elischer /*
403a974ba0bSJulian Elischer * According to RFC2427 frame should begin with
404a974ba0bSJulian Elischer * HDLC_UI PAD NLIPID OUI PID
405a974ba0bSJulian Elischer * 03 00 80 00 00 00 08 00
406a974ba0bSJulian Elischer */
407*eb1b1807SGleb Smirnoff M_PREPEND(m, 8, M_NOWAIT);
408a974ba0bSJulian Elischer if (!m)
409a974ba0bSJulian Elischer ERROUT(ENOBUFS);
410a974ba0bSJulian Elischer mtod(m, u_char *)[0] = HDLC_UI;
411a974ba0bSJulian Elischer mtod(m, u_char *)[1] = 0x00; /* PAD */
412a974ba0bSJulian Elischer mtod(m, u_char *)[2] = NLPID_SNAP;
413a974ba0bSJulian Elischer bzero((char *)(mtod(m, u_char *) + 3), 3); /* OUI 0-0-0 */
414a974ba0bSJulian Elischer *((u_int16_t *)mtod(m, u_int16_t *) + 6/sizeof(u_int16_t))
415a974ba0bSJulian Elischer = htons(ETHERTYPE_IP); /* PID */
416a974ba0bSJulian Elischer break;
417a974ba0bSJulian Elischer case NG_RFC1490_ENCAP_CISCO:
418*eb1b1807SGleb Smirnoff M_PREPEND(m, 2, M_NOWAIT); /* Prepend IP ethertype */
419a974ba0bSJulian Elischer if (!m)
420a974ba0bSJulian Elischer ERROUT(ENOBUFS);
421a974ba0bSJulian Elischer *((u_int16_t *)mtod(m, u_int16_t *)) = htons(ETHERTYPE_IP);
422a974ba0bSJulian Elischer break;
423a974ba0bSJulian Elischer }
424069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, priv->downlink, m);
4257586b25cSBrian Feldman } else if (hook == priv->ethernet) {
426*eb1b1807SGleb Smirnoff M_PREPEND(m, 8, M_NOWAIT); /* Prepend NLPID, OUI, PID */
4277586b25cSBrian Feldman if (!m)
4287586b25cSBrian Feldman ERROUT(ENOBUFS);
4297586b25cSBrian Feldman mtod(m, u_char *)[0] = HDLC_UI;
4307586b25cSBrian Feldman mtod(m, u_char *)[1] = 0x00; /* pad */
4317586b25cSBrian Feldman mtod(m, u_char *)[2] = NLPID_SNAP;
4327586b25cSBrian Feldman mtod(m, u_char *)[3] = 0x00; /* OUI */
4337586b25cSBrian Feldman mtod(m, u_char *)[4] = 0x80;
4347586b25cSBrian Feldman mtod(m, u_char *)[5] = 0xc2;
4357586b25cSBrian Feldman mtod(m, u_char *)[6] = 0x00; /* PID */
4367586b25cSBrian Feldman mtod(m, u_char *)[7] = 0x07;
4377586b25cSBrian Feldman NG_FWD_NEW_DATA(error, item, priv->downlink, m);
4384cf49a43SJulian Elischer } else
439d28843a4SRui Paulo panic("%s", __func__);
4404cf49a43SJulian Elischer
4414cf49a43SJulian Elischer done:
442069154d5SJulian Elischer if (item)
443069154d5SJulian Elischer NG_FREE_ITEM(item);
444069154d5SJulian Elischer NG_FREE_M(m);
4454cf49a43SJulian Elischer return (error);
4464cf49a43SJulian Elischer }
4474cf49a43SJulian Elischer
4484cf49a43SJulian Elischer /*
4494cf49a43SJulian Elischer * Nuke node
4504cf49a43SJulian Elischer */
4514cf49a43SJulian Elischer static int
ng_rfc1490_shutdown(node_p node)452069154d5SJulian Elischer ng_rfc1490_shutdown(node_p node)
4534cf49a43SJulian Elischer {
45430400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
4554cf49a43SJulian Elischer
4564cf49a43SJulian Elischer /* Take down netgraph node */
4574cf49a43SJulian Elischer bzero(priv, sizeof(*priv));
4581ede983cSDag-Erling Smørgrav free(priv, M_NETGRAPH);
45930400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL);
46030400f03SJulian Elischer NG_NODE_UNREF(node); /* let the node escape */
4614cf49a43SJulian Elischer return (0);
4624cf49a43SJulian Elischer }
4634cf49a43SJulian Elischer
4644cf49a43SJulian Elischer /*
4654cf49a43SJulian Elischer * Hook disconnection
4664cf49a43SJulian Elischer */
4674cf49a43SJulian Elischer static int
ng_rfc1490_disconnect(hook_p hook)4684cf49a43SJulian Elischer ng_rfc1490_disconnect(hook_p hook)
4694cf49a43SJulian Elischer {
47030400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
4714cf49a43SJulian Elischer
47230400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
47330400f03SJulian Elischer && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
47430400f03SJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook));
4754cf49a43SJulian Elischer else if (hook == priv->downlink)
4764cf49a43SJulian Elischer priv->downlink = NULL;
4774cf49a43SJulian Elischer else if (hook == priv->inet)
4784cf49a43SJulian Elischer priv->inet = NULL;
4794cf49a43SJulian Elischer else if (hook == priv->ppp)
4804cf49a43SJulian Elischer priv->ppp = NULL;
4817586b25cSBrian Feldman else if (hook == priv->ethernet)
4827586b25cSBrian Feldman priv->ethernet = NULL;
4834cf49a43SJulian Elischer else
484d28843a4SRui Paulo panic("%s", __func__);
4854cf49a43SJulian Elischer return (0);
4864cf49a43SJulian Elischer }
487