xref: /freebsd/sys/netgraph/ng_rfc1490.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
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