From f062ee581efd7818cff2a968dea0ee508ac27522 Mon Sep 17 00:00:00 2001 From: rik Date: Wed, 24 Mar 2004 17:24:01 +0000 Subject: sppp (4) to netgraph (4) node. As always: I'l connect it to the system after extra check. Approved by: imp (mentor) Approved by: julian (in general) --- sys/modules/netgraph/sppp/Makefile | 7 + sys/netgraph/ng_sppp.c | 442 +++++++++++++++++++++++++++++++++++++ sys/netgraph/ng_sppp.h | 42 ++++ 3 files changed, 491 insertions(+) create mode 100644 sys/modules/netgraph/sppp/Makefile create mode 100644 sys/netgraph/ng_sppp.c create mode 100644 sys/netgraph/ng_sppp.h diff --git a/sys/modules/netgraph/sppp/Makefile b/sys/modules/netgraph/sppp/Makefile new file mode 100644 index 0000000..203e83e --- /dev/null +++ b/sys/modules/netgraph/sppp/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ +# Cronyx Id: ng_sppp.Makefile,v 1.1.2.1 2002/12/25 08:37:25 rik Exp $ + +KMOD= ng_sppp +SRCS= ng_sppp.c + +.include diff --git a/sys/netgraph/ng_sppp.c b/sys/netgraph/ng_sppp.c new file mode 100644 index 0000000..144e4db --- /dev/null +++ b/sys/netgraph/ng_sppp.c @@ -0,0 +1,442 @@ +/* + * ng_sppp.c Netgraph to Sppp module. + * + * Copyright (C) 2002-2004 Cronyx Engineering. + * Copyright (C) 2002-2004 Roman Kurakin + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organisations a permission to use, + * modify and redistribute this software in source and binary forms, + * as long as this message is kept with the software, all derivative + * works or modified versions. + * + * Cronyx Id: ng_sppp.c,v 1.1.2.10 2004/03/01 15:17:21 rik Exp $ + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#ifdef NG_SEPARATE_MALLOC +MALLOC_DEFINE(M_NETGRAPH_SPPP, "netgraph_sppp", "netgraph sppp node "); +#else +#define M_NETGRAPH_SPPP M_NETGRAPH +#endif + +/* Node private data */ +struct ng_sppp_private { + struct sppp *pp; /* Our interface */ + int unit; /* Interface unit number */ + node_p node; /* Our netgraph node */ + hook_p hook; /* Hook */ +}; +typedef struct ng_sppp_private *priv_p; + +/* Interface methods */ +static void ng_sppp_start (struct ifnet *ifp); +static int ng_sppp_ioctl (struct ifnet *ifp, u_long cmd, caddr_t data); + +/* Netgraph methods */ +static ng_constructor_t ng_sppp_constructor; +static ng_rcvmsg_t ng_sppp_rcvmsg; +static ng_shutdown_t ng_sppp_shutdown; +static ng_newhook_t ng_sppp_newhook; +static ng_rcvdata_t ng_sppp_rcvdata; +static ng_disconnect_t ng_sppp_disconnect; + +/* Parse type for struct ng_sppp_ifname */ +static const struct ng_parse_fixedstring_info ng_sppp_ifname_info = { + NG_SPPP_IFACE_NAME_MAX + 1 +}; + +static const struct ng_parse_type ng_sppp_ifname_type = { + &ng_parse_fixedstring_type, + &ng_sppp_ifname_info +}; + +/* List of commands and how to convert arguments to/from ASCII */ +static const struct ng_cmdlist ng_sppp_cmds[] = { + { + NGM_SPPP_COOKIE, + NGM_SPPP_GET_IFNAME, + "getifname", + NULL, + &ng_sppp_ifname_type + }, + { 0 } +}; + +/* Node type descriptor */ +static struct ng_type typestruct = { + NG_ABI_VERSION, + NG_SPPP_NODE_TYPE, + NULL, + ng_sppp_constructor, + ng_sppp_rcvmsg, + ng_sppp_shutdown, + ng_sppp_newhook, + NULL, + NULL, + ng_sppp_rcvdata, + ng_sppp_disconnect, + ng_sppp_cmds +}; +NETGRAPH_INIT(sppp, &typestruct); + +MODULE_DEPEND (ng_sppp, sppp, 1, 1, 1); + +/* We keep a bitmap indicating which unit numbers are free. + Zero means the unit number is free, one means it's taken. */ +static unsigned char *ng_sppp_units = NULL; +static unsigned char ng_sppp_units_len = 0; +static unsigned char ng_units_in_use = 0; + +/* + * Find the first free unit number for a new interface. + * Increase the size of the unit bitmap as necessary. + */ +static __inline__ int +ng_sppp_get_unit (int *unit) +{ + int index, bit; + unsigned char mask; + + for (index = 0; index < ng_sppp_units_len + && ng_sppp_units[index] == 0xFF; index++); + if (index == ng_sppp_units_len) { /* extend array */ + unsigned char *newarray; + int newlen; + + newlen = (2 * ng_sppp_units_len) + sizeof (*ng_sppp_units); + MALLOC (newarray, unsigned char *, + newlen * sizeof (*ng_sppp_units), M_NETGRAPH_SPPP, M_NOWAIT); + if (newarray == NULL) + return (ENOMEM); + bcopy (ng_sppp_units, newarray, + ng_sppp_units_len * sizeof (*ng_sppp_units)); + bzero (newarray + ng_sppp_units_len, + newlen - ng_sppp_units_len); + if (ng_sppp_units != NULL) + FREE (ng_sppp_units, M_NETGRAPH_SPPP); + ng_sppp_units = newarray; + ng_sppp_units_len = newlen; + } + mask = ng_sppp_units[index]; + for (bit = 0; (mask & 1) != 0; bit++) + mask >>= 1; + KASSERT ((bit >= 0 && bit < NBBY), + ("%s: word=%d bit=%d", __func__, ng_sppp_units[index], bit)); + ng_sppp_units[index] |= (1 << bit); + *unit = (index * NBBY) + bit; + ng_units_in_use++; + return (0); +} + +/* + * Free a no longer needed unit number. + */ +static __inline__ void +ng_sppp_free_unit (int unit) +{ + int index, bit; + + index = unit / NBBY; + bit = unit % NBBY; + KASSERT (index < ng_sppp_units_len, + ("%s: unit=%d len=%d", __func__, unit, ng_sppp_units_len)); + KASSERT ((ng_sppp_units[index] & (1 << bit)) != 0, + ("%s: unit=%d is free", __func__, unit)); + ng_sppp_units[index] &= ~(1 << bit); + + ng_units_in_use--; + if (ng_units_in_use == 0) { + FREE (ng_sppp_units, M_NETGRAPH_SPPP); + ng_sppp_units_len = 0; + ng_sppp_units = NULL; + } +} + +/************************************************************************ + INTERFACE STUFF + ************************************************************************/ + +/* + * Process an ioctl for the interface + */ +static int +ng_sppp_ioctl (struct ifnet *ifp, u_long command, caddr_t data) +{ + int error = 0; + + error = sppp_ioctl (ifp, command, data); + if (error) + return error; + + return error; +} + +/* + * This routine should never be called + */ + +static void +ng_sppp_start (struct ifnet *ifp) +{ + struct mbuf *m; + int len, error = 0; + priv_p priv = ifp->if_softc; + + /* Check interface flags */ + /* + * This has side effects. It is not good idea to stop sending if we + * are not UP. If we are not running we still want to send LCP term + * packets. + */ +/* if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {*/ +/* return;*/ +/* }*/ + + if (ifp->if_flags & IFF_OACTIVE) + return; + + if (!priv->hook) + return; + + ifp->if_flags |= IFF_OACTIVE; + + while ((m = sppp_dequeue (ifp)) != NULL) { + if (ifp->if_bpf) + BPF_MTAP (ifp, m); + len = m->m_pkthdr.len; + + NG_SEND_DATA_ONLY (error, priv->hook, m); + + if (error) { + ifp->if_flags &= ~IFF_OACTIVE; + return; + } + } + ifp->if_flags &= ~IFF_OACTIVE; +} + +/************************************************************************ + NETGRAPH NODE STUFF + ************************************************************************/ + +/* + * Constructor for a node + */ +static int +ng_sppp_constructor (node_p node) +{ + char ifname[NG_SPPP_IFACE_NAME_MAX + 1]; + struct sppp *pp; + priv_p priv; + int error = 0; + + /* Allocate node and interface private structures */ + MALLOC (priv, priv_p, sizeof(*priv), M_NETGRAPH_SPPP, M_NOWAIT|M_ZERO); + if (priv == NULL) + return (ENOMEM); + MALLOC (pp, struct sppp *, sizeof(*pp), M_NETGRAPH_SPPP, M_NOWAIT|M_ZERO); + if (pp == NULL) { + FREE (priv, M_NETGRAPH_SPPP); + return (ENOMEM); + } + + /* Link them together */ + pp->pp_if.if_softc = priv; + priv->pp = pp; + + /* Get an interface unit number */ + if ((error = ng_sppp_get_unit(&priv->unit)) != 0) { + FREE (pp, M_NETGRAPH_SPPP); + FREE (priv, M_NETGRAPH_SPPP); + return (error); + } + + + /* Link together node and private info */ + NG_NODE_SET_PRIVATE (node, priv); + priv->node = node; + + /* Initialize interface structure */ + if_initname (&pp->pp_if, NG_SPPP_IFACE_NAME, priv->unit); + pp->pp_if.if_start = ng_sppp_start; + pp->pp_if.if_ioctl = ng_sppp_ioctl; + pp->pp_if.if_watchdog = NULL; + pp->pp_if.if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); + + /* Give this node the same name as the interface (if possible) */ + bzero (ifname, sizeof(ifname)); + snprintf (ifname, sizeof(ifname), "%s%d", NG_SPPP_IFACE_NAME, priv->unit); + if (ng_name_node(node, ifname) != 0) + log (LOG_WARNING, "%s: can't acquire netgraph name\n", ifname); + + /* Attach the interface */ + sppp_attach (&pp->pp_if); + if_attach (&pp->pp_if); + bpfattach (&pp->pp_if, DLT_NULL, sizeof(u_int)); + + /* Done */ + return (0); +} + +/* + * Give our ok for a hook to be added + */ +static int +ng_sppp_newhook (node_p node, hook_p hook, const char *name) +{ + priv_p priv = NG_NODE_PRIVATE (node); + + if (strcmp (name, NG_SPPP_HOOK_DOWNSTREAM) != 0) + return (EINVAL); + + if (priv->hook) + return (EISCONN); + + priv->hook = hook; + NG_HOOK_SET_PRIVATE (hook, priv); + + return (0); +} + +/* + * Receive a control message + */ +static int +ng_sppp_rcvmsg (node_p node, item_p item, hook_p lasthook) +{ + const priv_p priv = NG_NODE_PRIVATE (node); + struct ng_mesg *msg = NULL; + struct ng_mesg *resp = NULL; + struct sppp *const pp = priv->pp; + int error = 0; + + NGI_GET_MSG (item, msg); + switch (msg->header.typecookie) { + case NGM_SPPP_COOKIE: + switch (msg->header.cmd) { + case NGM_SPPP_GET_IFNAME: + { + struct ng_sppp_ifname *arg; + + NG_MKRESPONSE (resp, msg, sizeof (*arg), M_NOWAIT); + if (!resp) { + error = ENOMEM; + break; + } + arg = (struct ng_sppp_ifname *)resp->data; + snprintf (arg->ngif_name, sizeof (arg->ngif_name), + "%s", pp->pp_if.if_xname); + break; + } + + default: + error = EINVAL; + break; + } + break; + default: + error = EINVAL; + break; + } + NG_RESPOND_MSG (error, node, item, resp); + NG_FREE_MSG (msg); + return (error); +} + +/* + * Recive data from a hook. Pass the packet to the correct input routine. + */ +static int +ng_sppp_rcvdata (hook_p hook, item_p item) +{ + struct mbuf *m; + const priv_p priv = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); + struct sppp *const pp = priv->pp; + + NGI_GET_M (item, m); + NG_FREE_ITEM (item); + /* Sanity checks */ + KASSERT (m->m_flags & M_PKTHDR, ("%s: not pkthdr", __func__)); + if (m == NULL) + return (EINVAL); + if ((pp->pp_if.if_flags & IFF_UP) == 0) { + NG_FREE_M (m); + return (ENETDOWN); + } + + /* Update interface stats */ + pp->pp_if.if_ipackets++; + + /* Note receiving interface */ + m->m_pkthdr.rcvif = &pp->pp_if; + + /* Berkeley packet filter */ + if (pp->pp_if.if_bpf) + BPF_MTAP (&pp->pp_if, m); + + /* Send packet */ + sppp_input (&pp->pp_if, m); + return 0; +} + +/* + * Shutdown and remove the node and its associated interface. + */ +static int +ng_sppp_shutdown (node_p node) +{ + const priv_p priv = NG_NODE_PRIVATE(node); + /* Detach from the packet filter list of interfaces. */ + bpfdetach (&priv->pp->pp_if); + sppp_detach (&priv->pp->pp_if); + if_detach (&priv->pp->pp_if); + FREE (priv->pp, M_NETGRAPH_SPPP); + priv->pp = NULL; + ng_sppp_free_unit (priv->unit); + FREE (priv, M_NETGRAPH_SPPP); + NG_NODE_SET_PRIVATE (node, NULL); + NG_NODE_UNREF (node); + return (0); +} + +/* + * Hook disconnection. + */ +static int +ng_sppp_disconnect (hook_p hook) +{ + const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); + + if (priv) + priv->hook = NULL; + + return (0); +} diff --git a/sys/netgraph/ng_sppp.h b/sys/netgraph/ng_sppp.h new file mode 100644 index 0000000..2616f03 --- /dev/null +++ b/sys/netgraph/ng_sppp.h @@ -0,0 +1,42 @@ +/* + * ng_sppp.h Netgraph to Sppp module. + * + * Copyright (C) 2002-2004 Cronyx Engineering. + * Copyright (C) 2002-2004 Roman Kurakin + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organisations a permission to use, + * modify and redistribute this software in source and binary forms, + * as long as this message is kept with the software, all derivative + * works or modified versions. + * + * $FreeBSD$ + * Cronyx Id: ng_sppp.h,v 1.1.2.6 2004/03/01 15:17:21 rik Exp $ + */ + +#ifndef _NETGRAPH_SPPP_H_ +#define _NETGRAPH_SPPP_H_ + +/* Node type name and magic cookie */ +#define NG_SPPP_NODE_TYPE "sppp" +#define NGM_SPPP_COOKIE 1040804655 + +/* Interface base name */ +#define NG_SPPP_IFACE_NAME "sppp" +#define NG_SPPP_IFACE_NAME_MAX 15 + +/* My hook names */ +#define NG_SPPP_HOOK_DOWNSTREAM "downstream" + +/* Netgraph commands */ +enum { + NGM_SPPP_GET_IFNAME = 1, /* returns struct ng_sppp_ifname */ +}; + +struct ng_sppp_ifname { + char ngif_name[NG_SPPP_IFACE_NAME_MAX + 1]; +}; + +#endif /* _NETGRAPH_SPPP_H_ */ -- cgit v1.1