xref: /freebsd/sys/netgraph/ng_ppp.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
14cf49a43SJulian Elischer 
24cf49a43SJulian Elischer /*
34cf49a43SJulian Elischer  * ng_ppp.c
44cf49a43SJulian Elischer  *
54cf49a43SJulian Elischer  * Copyright (c) 1996-1999 Whistle Communications, Inc.
64cf49a43SJulian Elischer  * All rights reserved.
74cf49a43SJulian Elischer  *
84cf49a43SJulian Elischer  * Subject to the following obligations and disclaimer of warranty, use and
94cf49a43SJulian Elischer  * redistribution of this software, in source or object code forms, with or
104cf49a43SJulian Elischer  * without modifications are expressly permitted by Whistle Communications;
114cf49a43SJulian Elischer  * provided, however, that:
124cf49a43SJulian Elischer  * 1. Any and all reproductions of the source or object code must include the
134cf49a43SJulian Elischer  *    copyright notice above and the following disclaimer of warranties; and
144cf49a43SJulian Elischer  * 2. No rights are granted, in any manner or form, to use Whistle
154cf49a43SJulian Elischer  *    Communications, Inc. trademarks, including the mark "WHISTLE
164cf49a43SJulian Elischer  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
174cf49a43SJulian Elischer  *    such appears in the above copyright notice or in the software.
184cf49a43SJulian Elischer  *
194cf49a43SJulian Elischer  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
204cf49a43SJulian Elischer  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
214cf49a43SJulian Elischer  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
224cf49a43SJulian Elischer  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
234cf49a43SJulian Elischer  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
244cf49a43SJulian Elischer  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
254cf49a43SJulian Elischer  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
264cf49a43SJulian Elischer  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
274cf49a43SJulian Elischer  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
284cf49a43SJulian Elischer  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
294cf49a43SJulian Elischer  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
304cf49a43SJulian Elischer  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
314cf49a43SJulian Elischer  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
324cf49a43SJulian Elischer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
334cf49a43SJulian Elischer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
344cf49a43SJulian Elischer  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
354cf49a43SJulian Elischer  * OF SUCH DAMAGE.
364cf49a43SJulian Elischer  *
374cf49a43SJulian Elischer  * Author: Archie Cobbs <archie@whistle.com>
384cf49a43SJulian Elischer  *
394cf49a43SJulian Elischer  * $FreeBSD$
404cf49a43SJulian Elischer  * $Whistle: ng_ppp.c,v 1.22 1999/01/28 23:54:53 julian Exp $
414cf49a43SJulian Elischer  */
424cf49a43SJulian Elischer 
434cf49a43SJulian Elischer /*
444cf49a43SJulian Elischer  * This node does PPP protocol multiplexing based on PPP protocol
454cf49a43SJulian Elischer  * ID numbers. This node does not add address and control fields,
464cf49a43SJulian Elischer  * as that is considered a ``device layer'' issue.
474cf49a43SJulian Elischer  */
484cf49a43SJulian Elischer 
494cf49a43SJulian Elischer #include <sys/param.h>
504cf49a43SJulian Elischer #include <sys/systm.h>
514cf49a43SJulian Elischer #include <sys/kernel.h>
524cf49a43SJulian Elischer #include <sys/conf.h>
534cf49a43SJulian Elischer #include <sys/mbuf.h>
544cf49a43SJulian Elischer #include <sys/malloc.h>
554cf49a43SJulian Elischer #include <sys/errno.h>
564cf49a43SJulian Elischer #include <sys/socket.h>
574cf49a43SJulian Elischer #include <sys/syslog.h>
584cf49a43SJulian Elischer 
594cf49a43SJulian Elischer #include <netgraph/ng_message.h>
604cf49a43SJulian Elischer #include <netgraph/netgraph.h>
614cf49a43SJulian Elischer #include <netgraph/ng_ppp.h>
624cf49a43SJulian Elischer 
634cf49a43SJulian Elischer /* Protocol stuff */
644cf49a43SJulian Elischer #define PROT_DOWNLINK		0xffff
654cf49a43SJulian Elischer #define PROT_BYPASS		0x0000
664cf49a43SJulian Elischer 
674cf49a43SJulian Elischer #define PROT_VALID(p)		(((p) & 0x0101) == 0x0001)
684cf49a43SJulian Elischer #define PROT_COMPRESSIBLE(p)	(((p) & 0xFF00) == 0x0000)
694cf49a43SJulian Elischer 
704cf49a43SJulian Elischer /* Extract protocol from hook private pointer */
714cf49a43SJulian Elischer #define HOOK_PROTO(hook)	(*((u_int16_t *) &hook->private))
724cf49a43SJulian Elischer 
734cf49a43SJulian Elischer /* Node private data */
744cf49a43SJulian Elischer struct private {
754cf49a43SJulian Elischer 	struct	ng_ppp_stat stats;
764cf49a43SJulian Elischer 	u_int   protocomp:1;
774cf49a43SJulian Elischer };
784cf49a43SJulian Elischer typedef struct private *priv_p;
794cf49a43SJulian Elischer 
804cf49a43SJulian Elischer /* Protocol aliases */
814cf49a43SJulian Elischer struct protoalias {
824cf49a43SJulian Elischer 	char   *name;
834cf49a43SJulian Elischer 	u_int16_t proto;
844cf49a43SJulian Elischer };
854cf49a43SJulian Elischer 
864cf49a43SJulian Elischer /* Netgraph node methods */
874cf49a43SJulian Elischer static int	ng_ppp_constructor(node_p *nodep);
884cf49a43SJulian Elischer static int	ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg,
894cf49a43SJulian Elischer 		    const char *retaddr, struct ng_mesg **resp);
904cf49a43SJulian Elischer static int	ng_ppp_rmnode(node_p node);
914cf49a43SJulian Elischer static int	ng_ppp_newhook(node_p node, hook_p hook, const char *name);
924cf49a43SJulian Elischer static int	ng_ppp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
934cf49a43SJulian Elischer static int	ng_ppp_disconnect(hook_p hook);
944cf49a43SJulian Elischer 
954cf49a43SJulian Elischer /* Helper stuff */
964cf49a43SJulian Elischer static int	ng_ppp_decodehookname(const char *name);
974cf49a43SJulian Elischer static hook_p	ng_ppp_findhook(node_p node, int proto);
984cf49a43SJulian Elischer 
994cf49a43SJulian Elischer /* Node type descriptor */
1004cf49a43SJulian Elischer static struct ng_type typestruct = {
1014cf49a43SJulian Elischer 	NG_VERSION,
1024cf49a43SJulian Elischer 	NG_PPP_NODE_TYPE,
1034cf49a43SJulian Elischer 	NULL,
1044cf49a43SJulian Elischer 	ng_ppp_constructor,
1054cf49a43SJulian Elischer 	ng_ppp_rcvmsg,
1064cf49a43SJulian Elischer 	ng_ppp_rmnode,
1074cf49a43SJulian Elischer 	ng_ppp_newhook,
1084cf49a43SJulian Elischer 	NULL,
1094cf49a43SJulian Elischer 	NULL,
1104cf49a43SJulian Elischer 	ng_ppp_rcvdata,
1114cf49a43SJulian Elischer 	ng_ppp_rcvdata,
1124cf49a43SJulian Elischer 	ng_ppp_disconnect
1134cf49a43SJulian Elischer };
1144cf49a43SJulian Elischer NETGRAPH_INIT(ppp, &typestruct);
1154cf49a43SJulian Elischer 
1164cf49a43SJulian Elischer /* Protocol aliases */
1174cf49a43SJulian Elischer static const struct protoalias gAliases[] =
1184cf49a43SJulian Elischer {
1194cf49a43SJulian Elischer 	{ NG_PPP_HOOK_DOWNLINK,		PROT_DOWNLINK	},
1204cf49a43SJulian Elischer 	{ NG_PPP_HOOK_BYPASS,		PROT_BYPASS	},
1214cf49a43SJulian Elischer 	{ NG_PPP_HOOK_LCP,		0xc021		},
1224cf49a43SJulian Elischer 	{ NG_PPP_HOOK_IPCP,		0x8021		},
1234cf49a43SJulian Elischer 	{ NG_PPP_HOOK_ATCP,		0x8029		},
1244cf49a43SJulian Elischer 	{ NG_PPP_HOOK_CCP,		0x80fd		},
1254cf49a43SJulian Elischer 	{ NG_PPP_HOOK_ECP,		0x8053		},
1264cf49a43SJulian Elischer 	{ NG_PPP_HOOK_IP,		0x0021		},
1274cf49a43SJulian Elischer 	{ NG_PPP_HOOK_VJCOMP,		0x002d		},
1284cf49a43SJulian Elischer 	{ NG_PPP_HOOK_VJUNCOMP,		0x002f		},
1294cf49a43SJulian Elischer 	{ NG_PPP_HOOK_MP,		0x003d		},
1304cf49a43SJulian Elischer 	{ NG_PPP_HOOK_COMPD,		0x00fd		},
1314cf49a43SJulian Elischer 	{ NG_PPP_HOOK_CRYPTD,		0x0053		},
1324cf49a43SJulian Elischer 	{ NG_PPP_HOOK_PAP,		0xc023		},
1334cf49a43SJulian Elischer 	{ NG_PPP_HOOK_CHAP,		0xc223		},
1344cf49a43SJulian Elischer 	{ NG_PPP_HOOK_LQR,		0xc025		},
1354cf49a43SJulian Elischer 	{ NULL,				0		}
1364cf49a43SJulian Elischer };
1374cf49a43SJulian Elischer 
1384cf49a43SJulian Elischer #define ERROUT(x)	do { error = (x); goto done; } while (0)
1394cf49a43SJulian Elischer 
1404cf49a43SJulian Elischer /************************************************************************
1414cf49a43SJulian Elischer 			NETGRAPH NODE STUFF
1424cf49a43SJulian Elischer  ************************************************************************/
1434cf49a43SJulian Elischer 
1444cf49a43SJulian Elischer /*
1454cf49a43SJulian Elischer  * Node constructor
1464cf49a43SJulian Elischer  */
1474cf49a43SJulian Elischer static int
1484cf49a43SJulian Elischer ng_ppp_constructor(node_p *nodep)
1494cf49a43SJulian Elischer {
1504cf49a43SJulian Elischer 	priv_p priv;
1514cf49a43SJulian Elischer 	int error;
1524cf49a43SJulian Elischer 
1534cf49a43SJulian Elischer 	/* Allocate private structure */
1544cf49a43SJulian Elischer 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
1554cf49a43SJulian Elischer 	if (priv == NULL)
1564cf49a43SJulian Elischer 		return (ENOMEM);
1574cf49a43SJulian Elischer 	bzero(priv, sizeof(*priv));
1584cf49a43SJulian Elischer 
1594cf49a43SJulian Elischer 	/* Call generic node constructor */
1604cf49a43SJulian Elischer 	if ((error = ng_make_node_common(&typestruct, nodep))) {
1614cf49a43SJulian Elischer 		FREE(priv, M_NETGRAPH);
1624cf49a43SJulian Elischer 		return (error);
1634cf49a43SJulian Elischer 	}
1644cf49a43SJulian Elischer 	(*nodep)->private = priv;
1654cf49a43SJulian Elischer 
1664cf49a43SJulian Elischer 	/* Done */
1674cf49a43SJulian Elischer 	return (0);
1684cf49a43SJulian Elischer }
1694cf49a43SJulian Elischer 
1704cf49a43SJulian Elischer /*
1714cf49a43SJulian Elischer  * Give our OK for a hook to be added
1724cf49a43SJulian Elischer  */
1734cf49a43SJulian Elischer static int
1744cf49a43SJulian Elischer ng_ppp_newhook(node_p node, hook_p hook, const char *name)
1754cf49a43SJulian Elischer {
1764cf49a43SJulian Elischer 	const priv_p priv = node->private;
1774cf49a43SJulian Elischer 	int proto;
1784cf49a43SJulian Elischer 
1794cf49a43SJulian Elischer 	/* Decode protocol number */
1804cf49a43SJulian Elischer 	if ((proto = ng_ppp_decodehookname(name)) < 0)
1814cf49a43SJulian Elischer 		return (EINVAL);
1824cf49a43SJulian Elischer 
1834cf49a43SJulian Elischer 	/* See if already connected */
1844cf49a43SJulian Elischer 	if (ng_ppp_findhook(node, proto) != NULL)
1854cf49a43SJulian Elischer 		return (EISCONN);
1864cf49a43SJulian Elischer 
1874cf49a43SJulian Elischer 	/* Clear stats when downstream hook reconnected */
1884cf49a43SJulian Elischer 	if (proto == PROT_DOWNLINK)
1894cf49a43SJulian Elischer 		bzero(&priv->stats, sizeof(priv->stats));
1904cf49a43SJulian Elischer 
1914cf49a43SJulian Elischer 	/* OK */
1924cf49a43SJulian Elischer 	HOOK_PROTO(hook) = proto;
1934cf49a43SJulian Elischer 	return (0);
1944cf49a43SJulian Elischer }
1954cf49a43SJulian Elischer 
1964cf49a43SJulian Elischer /*
1974cf49a43SJulian Elischer  * Receive a control message
1984cf49a43SJulian Elischer  */
1994cf49a43SJulian Elischer static int
2004cf49a43SJulian Elischer ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg,
2014cf49a43SJulian Elischer 	      const char *raddr, struct ng_mesg **rptr)
2024cf49a43SJulian Elischer {
2034cf49a43SJulian Elischer 	const priv_p priv = node->private;
2044cf49a43SJulian Elischer 	struct ng_mesg *resp = NULL;
2054cf49a43SJulian Elischer 	int error = 0;
2064cf49a43SJulian Elischer 
2074cf49a43SJulian Elischer 	switch (msg->header.typecookie) {
2084cf49a43SJulian Elischer 	case NGM_PPP_COOKIE:
2094cf49a43SJulian Elischer 		switch (msg->header.cmd) {
2104cf49a43SJulian Elischer 		case NGM_PPP_SET_PROTOCOMP:
2114cf49a43SJulian Elischer 			if (msg->header.arglen < sizeof(int))
2124cf49a43SJulian Elischer 				ERROUT(EINVAL);
2134cf49a43SJulian Elischer 			priv->protocomp = !!*((int *) msg->data);
2144cf49a43SJulian Elischer 			break;
2154cf49a43SJulian Elischer 		case NGM_PPP_GET_STATS:
2164cf49a43SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(priv->stats), M_NOWAIT);
2174cf49a43SJulian Elischer 			if (resp == NULL)
2184cf49a43SJulian Elischer 				ERROUT(ENOMEM);
2194cf49a43SJulian Elischer 			*((struct ng_ppp_stat *) resp->data) = priv->stats;
2204cf49a43SJulian Elischer 			break;
2214cf49a43SJulian Elischer 		case NGM_PPP_CLR_STATS:
2224cf49a43SJulian Elischer 			bzero(&priv->stats, sizeof(priv->stats));
2234cf49a43SJulian Elischer 			break;
2244cf49a43SJulian Elischer 		default:
2254cf49a43SJulian Elischer 			error = EINVAL;
2264cf49a43SJulian Elischer 			break;
2274cf49a43SJulian Elischer 		}
2284cf49a43SJulian Elischer 		break;
2294cf49a43SJulian Elischer 	default:
2304cf49a43SJulian Elischer 		error = EINVAL;
2314cf49a43SJulian Elischer 		break;
2324cf49a43SJulian Elischer 	}
2334cf49a43SJulian Elischer 	if (rptr)
2344cf49a43SJulian Elischer 		*rptr = resp;
2354cf49a43SJulian Elischer 	else if (resp)
2364cf49a43SJulian Elischer 		FREE(resp, M_NETGRAPH);
2374cf49a43SJulian Elischer 
2384cf49a43SJulian Elischer done:
2394cf49a43SJulian Elischer 	FREE(msg, M_NETGRAPH);
2404cf49a43SJulian Elischer 	return (error);
2414cf49a43SJulian Elischer }
2424cf49a43SJulian Elischer 
2434cf49a43SJulian Elischer /*
2444cf49a43SJulian Elischer  * Receive data on a hook
2454cf49a43SJulian Elischer  */
2464cf49a43SJulian Elischer static int
2474cf49a43SJulian Elischer ng_ppp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
2484cf49a43SJulian Elischer {
2494cf49a43SJulian Elischer 	const node_p node = hook->node;
2504cf49a43SJulian Elischer 	const priv_p priv = node->private;
2514cf49a43SJulian Elischer 	u_int16_t proto = HOOK_PROTO(hook);
2524cf49a43SJulian Elischer 	int error = 0;
2534cf49a43SJulian Elischer 
2544cf49a43SJulian Elischer 	switch (proto) {
2554cf49a43SJulian Elischer 
2564cf49a43SJulian Elischer 	/* Prepend the (possibly compressed) protocol number */
2574cf49a43SJulian Elischer 	default:
2584cf49a43SJulian Elischer 	    {
2594cf49a43SJulian Elischer 		int psize = (priv->protocomp
2604cf49a43SJulian Elischer 				&& PROT_COMPRESSIBLE(proto)) ? 1 : 2;
2614cf49a43SJulian Elischer 
2624cf49a43SJulian Elischer 		M_PREPEND(m, psize, M_NOWAIT);
2634cf49a43SJulian Elischer 		if (!m || !(m = m_pullup(m, psize)))
2644cf49a43SJulian Elischer 			ERROUT(ENOBUFS);
2654cf49a43SJulian Elischer 		if (psize == 1)
2664cf49a43SJulian Elischer 			*mtod(m, u_char *) = proto;
2674cf49a43SJulian Elischer 		else
2684cf49a43SJulian Elischer 			*mtod(m, u_short *) = htons(proto);
2694cf49a43SJulian Elischer 		hook = ng_ppp_findhook(node, PROT_DOWNLINK);
2704cf49a43SJulian Elischer 		break;
2714cf49a43SJulian Elischer 	    }
2724cf49a43SJulian Elischer 
2734cf49a43SJulian Elischer 	/* Extract the protocol number and direct to the corresponding hook */
2744cf49a43SJulian Elischer 	case PROT_DOWNLINK:
2754cf49a43SJulian Elischer 	    {
2764cf49a43SJulian Elischer 		/* Stats */
2774cf49a43SJulian Elischer 		priv->stats.recvFrames++;
2784cf49a43SJulian Elischer 		priv->stats.recvOctets += m->m_pkthdr.len;
2794cf49a43SJulian Elischer 
2804cf49a43SJulian Elischer 		/* Extract protocol number */
2814cf49a43SJulian Elischer 		for (proto = 0;
2824cf49a43SJulian Elischer 		     !PROT_VALID(proto);
2834cf49a43SJulian Elischer 		     proto = (proto << 8) + *mtod(m, u_char *), m_adj(m, 1)) {
2844cf49a43SJulian Elischer 			if (m == NULL) {
2854cf49a43SJulian Elischer 				priv->stats.badProto++;
2864cf49a43SJulian Elischer 				ERROUT(EINVAL);
2874cf49a43SJulian Elischer 			}
2884cf49a43SJulian Elischer 			if ((m = m_pullup(m, 1)) == NULL)
2894cf49a43SJulian Elischer 				ERROUT(ENOBUFS);
2904cf49a43SJulian Elischer 		}
2914cf49a43SJulian Elischer 
2924cf49a43SJulian Elischer 		/* Find corresponding hook; if none, use the "unhooked"
2934cf49a43SJulian Elischer 		   hook and leave the two-byte protocol prepended */
2944cf49a43SJulian Elischer 		if ((hook = ng_ppp_findhook(node, proto)) == NULL) {
2954cf49a43SJulian Elischer 			priv->stats.unknownProto++;
2964cf49a43SJulian Elischer 			hook = ng_ppp_findhook(node, PROT_BYPASS);
2974cf49a43SJulian Elischer 			M_PREPEND(m, 2, M_NOWAIT);
2984cf49a43SJulian Elischer 			if (m == NULL || (m = m_pullup(m, 2)) == NULL)
2994cf49a43SJulian Elischer 				ERROUT(ENOBUFS);
3004cf49a43SJulian Elischer 			*mtod(m, u_short *) = htons(proto);
3014cf49a43SJulian Elischer 		}
3024cf49a43SJulian Elischer 		break;
3034cf49a43SJulian Elischer 	    }
3044cf49a43SJulian Elischer 
3054cf49a43SJulian Elischer 	/* Send raw data from "unhooked" hook as-is; we assume the
3064cf49a43SJulian Elischer 	   protocol is already prepended */
3074cf49a43SJulian Elischer 	case PROT_BYPASS:
3084cf49a43SJulian Elischer 		hook = ng_ppp_findhook(node, PROT_DOWNLINK);
3094cf49a43SJulian Elischer 		break;
3104cf49a43SJulian Elischer 	}
3114cf49a43SJulian Elischer 
3124cf49a43SJulian Elischer 	/* Stats */
3134cf49a43SJulian Elischer 	if (m != NULL && hook != NULL && HOOK_PROTO(hook) == PROT_DOWNLINK) {
3144cf49a43SJulian Elischer 		priv->stats.xmitFrames++;
3154cf49a43SJulian Elischer 		priv->stats.xmitOctets += m->m_pkthdr.len;
3164cf49a43SJulian Elischer 	}
3174cf49a43SJulian Elischer 
3184cf49a43SJulian Elischer 	/* Forward packet on hook */
3194cf49a43SJulian Elischer 	NG_SEND_DATA(error, hook, m, meta);
3204cf49a43SJulian Elischer 	return (error);
3214cf49a43SJulian Elischer 
3224cf49a43SJulian Elischer done:
3234cf49a43SJulian Elischer 	/* Something went wrong */
3244cf49a43SJulian Elischer 	NG_FREE_DATA(m, meta);
3254cf49a43SJulian Elischer 	return (error);
3264cf49a43SJulian Elischer }
3274cf49a43SJulian Elischer 
3284cf49a43SJulian Elischer /*
3294cf49a43SJulian Elischer  * Destroy node
3304cf49a43SJulian Elischer  */
3314cf49a43SJulian Elischer static int
3324cf49a43SJulian Elischer ng_ppp_rmnode(node_p node)
3334cf49a43SJulian Elischer {
3344cf49a43SJulian Elischer 	const priv_p priv = node->private;
3354cf49a43SJulian Elischer 
3364cf49a43SJulian Elischer 	/* Take down netgraph node */
3374cf49a43SJulian Elischer 	node->flags |= NG_INVALID;
3384cf49a43SJulian Elischer 	ng_cutlinks(node);
3394cf49a43SJulian Elischer 	ng_unname(node);
3404cf49a43SJulian Elischer 	bzero(priv, sizeof(*priv));
3414cf49a43SJulian Elischer 	FREE(priv, M_NETGRAPH);
3424cf49a43SJulian Elischer 	node->private = NULL;
3434cf49a43SJulian Elischer 	ng_unref(node);		/* let the node escape */
3444cf49a43SJulian Elischer 	return (0);
3454cf49a43SJulian Elischer }
3464cf49a43SJulian Elischer 
3474cf49a43SJulian Elischer /*
3484cf49a43SJulian Elischer  * Hook disconnection
3494cf49a43SJulian Elischer  */
3504cf49a43SJulian Elischer static int
3514cf49a43SJulian Elischer ng_ppp_disconnect(hook_p hook)
3524cf49a43SJulian Elischer {
3534cf49a43SJulian Elischer 	if (hook->node->numhooks == 0)
3544cf49a43SJulian Elischer 		ng_rmnode(hook->node);
3554cf49a43SJulian Elischer 	return (0);
3564cf49a43SJulian Elischer }
3574cf49a43SJulian Elischer 
3584cf49a43SJulian Elischer /************************************************************************
3594cf49a43SJulian Elischer 			HELPER STUFF
3604cf49a43SJulian Elischer  ************************************************************************/
3614cf49a43SJulian Elischer 
3624cf49a43SJulian Elischer /*
3634cf49a43SJulian Elischer  * Decode ASCII protocol name
3644cf49a43SJulian Elischer  */
3654cf49a43SJulian Elischer static int
3664cf49a43SJulian Elischer ng_ppp_decodehookname(const char *name)
3674cf49a43SJulian Elischer {
3684cf49a43SJulian Elischer 	int     k, proto;
3694cf49a43SJulian Elischer 
3704cf49a43SJulian Elischer 	for (k = 0; gAliases[k].name; k++)
3714cf49a43SJulian Elischer 		if (!strcmp(gAliases[k].name, name))
3724cf49a43SJulian Elischer 			return (gAliases[k].proto);
3734cf49a43SJulian Elischer 	if (strlen(name) != 6 || name[0] != '0' || name[1] != 'x')
3744cf49a43SJulian Elischer 		return (-1);
3754cf49a43SJulian Elischer 	for (proto = k = 2; k < 6; k++) {
3764cf49a43SJulian Elischer 		const u_char ch = name[k] | 0x20;
3774cf49a43SJulian Elischer 		int dig;
3784cf49a43SJulian Elischer 
3794cf49a43SJulian Elischer 		if (ch >= '0' && ch <= '9')
3804cf49a43SJulian Elischer 			dig = ch - '0';
3814cf49a43SJulian Elischer 		else if (ch >= 'a' && ch <= 'f')
3824cf49a43SJulian Elischer 			dig = ch - 'a' + 10;
3834cf49a43SJulian Elischer 		else
3844cf49a43SJulian Elischer 			return (-1);
3854cf49a43SJulian Elischer 		proto = (proto << 4) + dig;
3864cf49a43SJulian Elischer 	}
3874cf49a43SJulian Elischer 	if (!PROT_VALID(proto))
3884cf49a43SJulian Elischer 		return(-1);
3894cf49a43SJulian Elischer 	return (proto);
3904cf49a43SJulian Elischer }
3914cf49a43SJulian Elischer 
3924cf49a43SJulian Elischer /*
3934cf49a43SJulian Elischer  * Find a hook by protocol number
3944cf49a43SJulian Elischer  */
3954cf49a43SJulian Elischer static hook_p
3964cf49a43SJulian Elischer ng_ppp_findhook(node_p node, int proto)
3974cf49a43SJulian Elischer {
3984cf49a43SJulian Elischer 	hook_p hook;
3994cf49a43SJulian Elischer 
4004cf49a43SJulian Elischer 	LIST_FOREACH(hook, &node->hooks, hooks) {
4014cf49a43SJulian Elischer 		if (HOOK_PROTO(hook) == proto)
4024cf49a43SJulian Elischer 			return (hook);
4034cf49a43SJulian Elischer 	}
4044cf49a43SJulian Elischer 	return (NULL);
4054cf49a43SJulian Elischer }
4064cf49a43SJulian Elischer 
407