1127376Srik/* 2127376Srik * ng_sppp.c Netgraph to Sppp module. 3139823Simp */ 4139823Simp 5139823Simp/*- 6127376Srik * Copyright (C) 2002-2004 Cronyx Engineering. 7127376Srik * Copyright (C) 2002-2004 Roman Kurakin <rik@cronyx.ru> 8127376Srik * 9127376Srik * This software is distributed with NO WARRANTIES, not even the implied 10127376Srik * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11127376Srik * 12127376Srik * Authors grant any other persons or organisations a permission to use, 13127376Srik * modify and redistribute this software in source and binary forms, 14127376Srik * as long as this message is kept with the software, all derivative 15127376Srik * works or modified versions. 16127376Srik * 17127376Srik * Cronyx Id: ng_sppp.c,v 1.1.2.10 2004/03/01 15:17:21 rik Exp $ 18127376Srik */ 19127376Srik#include <sys/cdefs.h> 20127376Srik__FBSDID("$FreeBSD$"); 21127376Srik 22127376Srik#include <sys/param.h> 23127376Srik#include <sys/systm.h> 24127376Srik#include <sys/errno.h> 25127376Srik#include <sys/kernel.h> 26127376Srik#include <sys/malloc.h> 27127376Srik#include <sys/mbuf.h> 28127376Srik#include <sys/errno.h> 29127376Srik#include <sys/sockio.h> 30127376Srik#include <sys/socket.h> 31127376Srik#include <sys/syslog.h> 32127376Srik#include <sys/libkern.h> 33127376Srik 34127376Srik#include <net/if.h> 35127376Srik#include <net/if_types.h> 36127376Srik#include <net/bpf.h> 37127376Srik#include <net/if_sppp.h> 38127376Srik 39127376Srik#include <netinet/in.h> 40127376Srik 41127376Srik#include <netgraph/ng_message.h> 42127376Srik#include <netgraph/netgraph.h> 43127376Srik#include <netgraph/ng_parse.h> 44127376Srik#include <netgraph/ng_sppp.h> 45127376Srik 46127376Srik#ifdef NG_SEPARATE_MALLOC 47227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_SPPP, "netgraph_sppp", "netgraph sppp node"); 48127376Srik#else 49127376Srik#define M_NETGRAPH_SPPP M_NETGRAPH 50127376Srik#endif 51127376Srik 52127376Srik/* Node private data */ 53127376Srikstruct ng_sppp_private { 54147256Sbrooks struct ifnet *ifp; /* Our interface */ 55127376Srik int unit; /* Interface unit number */ 56127376Srik node_p node; /* Our netgraph node */ 57127376Srik hook_p hook; /* Hook */ 58127376Srik}; 59127376Sriktypedef struct ng_sppp_private *priv_p; 60127376Srik 61127376Srik/* Interface methods */ 62127376Srikstatic void ng_sppp_start (struct ifnet *ifp); 63127376Srikstatic int ng_sppp_ioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 64127376Srik 65127376Srik/* Netgraph methods */ 66127376Srikstatic ng_constructor_t ng_sppp_constructor; 67127376Srikstatic ng_rcvmsg_t ng_sppp_rcvmsg; 68127376Srikstatic ng_shutdown_t ng_sppp_shutdown; 69127376Srikstatic ng_newhook_t ng_sppp_newhook; 70127376Srikstatic ng_rcvdata_t ng_sppp_rcvdata; 71127376Srikstatic ng_disconnect_t ng_sppp_disconnect; 72127376Srik 73127376Srik/* List of commands and how to convert arguments to/from ASCII */ 74127376Srikstatic const struct ng_cmdlist ng_sppp_cmds[] = { 75127376Srik { 76127376Srik NGM_SPPP_COOKIE, 77127376Srik NGM_SPPP_GET_IFNAME, 78127376Srik "getifname", 79127376Srik NULL, 80141197Sru &ng_parse_string_type 81127376Srik }, 82127376Srik { 0 } 83127376Srik}; 84127376Srik 85127376Srik/* Node type descriptor */ 86127376Srikstatic struct ng_type typestruct = { 87129823Sjulian .version = NG_ABI_VERSION, 88129823Sjulian .name = NG_SPPP_NODE_TYPE, 89129823Sjulian .constructor = ng_sppp_constructor, 90129823Sjulian .rcvmsg = ng_sppp_rcvmsg, 91129823Sjulian .shutdown = ng_sppp_shutdown, 92129823Sjulian .newhook = ng_sppp_newhook, 93129823Sjulian .rcvdata = ng_sppp_rcvdata, 94129823Sjulian .disconnect = ng_sppp_disconnect, 95129823Sjulian .cmdlist = ng_sppp_cmds, 96127376Srik}; 97127376SrikNETGRAPH_INIT(sppp, &typestruct); 98127376Srik 99127376SrikMODULE_DEPEND (ng_sppp, sppp, 1, 1, 1); 100127376Srik 101127376Srik/* We keep a bitmap indicating which unit numbers are free. 102127376Srik Zero means the unit number is free, one means it's taken. */ 103127376Srikstatic unsigned char *ng_sppp_units = NULL; 104127376Srikstatic unsigned char ng_sppp_units_len = 0; 105127376Srikstatic unsigned char ng_units_in_use = 0; 106127376Srik 107127376Srik/* 108127376Srik * Find the first free unit number for a new interface. 109127376Srik * Increase the size of the unit bitmap as necessary. 110127376Srik */ 111220781Sglebiusstatic __inline void 112127376Srikng_sppp_get_unit (int *unit) 113127376Srik{ 114127376Srik int index, bit; 115127376Srik unsigned char mask; 116127376Srik 117127376Srik for (index = 0; index < ng_sppp_units_len 118127376Srik && ng_sppp_units[index] == 0xFF; index++); 119127376Srik if (index == ng_sppp_units_len) { /* extend array */ 120127376Srik unsigned char *newarray; 121127376Srik int newlen; 122127376Srik 123127376Srik newlen = (2 * ng_sppp_units_len) + sizeof (*ng_sppp_units); 124184205Sdes newarray = malloc (newlen * sizeof (*ng_sppp_units), 125220781Sglebius M_NETGRAPH_SPPP, M_WAITOK); 126127376Srik bcopy (ng_sppp_units, newarray, 127127376Srik ng_sppp_units_len * sizeof (*ng_sppp_units)); 128127376Srik bzero (newarray + ng_sppp_units_len, 129127376Srik newlen - ng_sppp_units_len); 130127376Srik if (ng_sppp_units != NULL) 131184205Sdes free (ng_sppp_units, M_NETGRAPH_SPPP); 132127376Srik ng_sppp_units = newarray; 133127376Srik ng_sppp_units_len = newlen; 134127376Srik } 135127376Srik mask = ng_sppp_units[index]; 136127376Srik for (bit = 0; (mask & 1) != 0; bit++) 137127376Srik mask >>= 1; 138127376Srik KASSERT ((bit >= 0 && bit < NBBY), 139127376Srik ("%s: word=%d bit=%d", __func__, ng_sppp_units[index], bit)); 140127376Srik ng_sppp_units[index] |= (1 << bit); 141127376Srik *unit = (index * NBBY) + bit; 142127376Srik ng_units_in_use++; 143127376Srik} 144127376Srik 145127376Srik/* 146127376Srik * Free a no longer needed unit number. 147127376Srik */ 148131575Sstefanfstatic __inline void 149127376Srikng_sppp_free_unit (int unit) 150127376Srik{ 151127376Srik int index, bit; 152127376Srik 153127376Srik index = unit / NBBY; 154127376Srik bit = unit % NBBY; 155127376Srik KASSERT (index < ng_sppp_units_len, 156127376Srik ("%s: unit=%d len=%d", __func__, unit, ng_sppp_units_len)); 157127376Srik KASSERT ((ng_sppp_units[index] & (1 << bit)) != 0, 158127376Srik ("%s: unit=%d is free", __func__, unit)); 159127376Srik ng_sppp_units[index] &= ~(1 << bit); 160127376Srik 161127376Srik ng_units_in_use--; 162127376Srik if (ng_units_in_use == 0) { 163184205Sdes free (ng_sppp_units, M_NETGRAPH_SPPP); 164127376Srik ng_sppp_units_len = 0; 165127376Srik ng_sppp_units = NULL; 166127376Srik } 167127376Srik} 168127376Srik 169127376Srik/************************************************************************ 170127376Srik INTERFACE STUFF 171127376Srik ************************************************************************/ 172127376Srik 173127376Srik/* 174127376Srik * Process an ioctl for the interface 175127376Srik */ 176127376Srikstatic int 177127376Srikng_sppp_ioctl (struct ifnet *ifp, u_long command, caddr_t data) 178127376Srik{ 179127376Srik int error = 0; 180127376Srik 181127376Srik error = sppp_ioctl (ifp, command, data); 182127376Srik if (error) 183127376Srik return error; 184127376Srik 185127376Srik return error; 186127376Srik} 187127376Srik 188127376Srik/* 189127376Srik * This routine should never be called 190127376Srik */ 191127376Srik 192127376Srikstatic void 193127376Srikng_sppp_start (struct ifnet *ifp) 194127376Srik{ 195127376Srik struct mbuf *m; 196127376Srik int len, error = 0; 197127376Srik priv_p priv = ifp->if_softc; 198127376Srik 199127376Srik /* Check interface flags */ 200127376Srik /* 201127376Srik * This has side effects. It is not good idea to stop sending if we 202127376Srik * are not UP. If we are not running we still want to send LCP term 203127376Srik * packets. 204127376Srik */ 205148887Srwatson/* if (!((ifp->if_flags & IFF_UP) && */ 206148887Srwatson/* (ifp->if_drv_flags & IFF_DRV_RUNNING))) { */ 207127376Srik/* return;*/ 208127376Srik/* }*/ 209127376Srik 210148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 211127376Srik return; 212127376Srik 213127376Srik if (!priv->hook) 214127376Srik return; 215127376Srik 216148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 217127376Srik 218127376Srik while ((m = sppp_dequeue (ifp)) != NULL) { 219165632Sjhb BPF_MTAP (ifp, m); 220127376Srik len = m->m_pkthdr.len; 221127376Srik 222127376Srik NG_SEND_DATA_ONLY (error, priv->hook, m); 223127376Srik 224127376Srik if (error) { 225148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 226127376Srik return; 227127376Srik } 228127376Srik } 229148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 230127376Srik} 231127376Srik 232127376Srik/************************************************************************ 233127376Srik NETGRAPH NODE STUFF 234127376Srik ************************************************************************/ 235127376Srik 236127376Srik/* 237127376Srik * Constructor for a node 238127376Srik */ 239127376Srikstatic int 240127376Srikng_sppp_constructor (node_p node) 241127376Srik{ 242127376Srik struct sppp *pp; 243147256Sbrooks struct ifnet *ifp; 244127376Srik priv_p priv; 245127376Srik 246127376Srik /* Allocate node and interface private structures */ 247220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_SPPP, M_WAITOK | M_ZERO); 248147256Sbrooks 249147256Sbrooks ifp = if_alloc(IFT_PPP); 250147256Sbrooks if (ifp == NULL) { 251184205Sdes free (priv, M_NETGRAPH_SPPP); 252147256Sbrooks return (ENOSPC); 253127376Srik } 254147256Sbrooks pp = IFP2SP(ifp); 255127376Srik 256127376Srik /* Link them together */ 257147256Sbrooks ifp->if_softc = priv; 258155016Srik priv->ifp = ifp; 259127376Srik 260127376Srik /* Get an interface unit number */ 261220781Sglebius ng_sppp_get_unit(&priv->unit); 262127376Srik 263127376Srik /* Link together node and private info */ 264127376Srik NG_NODE_SET_PRIVATE (node, priv); 265127376Srik priv->node = node; 266127376Srik 267127376Srik /* Initialize interface structure */ 268147256Sbrooks if_initname (SP2IFP(pp), NG_SPPP_IFACE_NAME, priv->unit); 269147256Sbrooks ifp->if_start = ng_sppp_start; 270147256Sbrooks ifp->if_ioctl = ng_sppp_ioctl; 271147256Sbrooks ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); 272127376Srik 273127376Srik /* Give this node the same name as the interface (if possible) */ 274147256Sbrooks if (ng_name_node(node, SP2IFP(pp)->if_xname) != 0) 275141197Sru log (LOG_WARNING, "%s: can't acquire netgraph name\n", 276147256Sbrooks SP2IFP(pp)->if_xname); 277127376Srik 278127376Srik /* Attach the interface */ 279147256Sbrooks sppp_attach (ifp); 280147256Sbrooks if_attach (ifp); 281147611Sdwmalone bpfattach (ifp, DLT_NULL, sizeof(u_int32_t)); 282127376Srik 283127376Srik /* Done */ 284127376Srik return (0); 285127376Srik} 286127376Srik 287127376Srik/* 288127376Srik * Give our ok for a hook to be added 289127376Srik */ 290127376Srikstatic int 291127376Srikng_sppp_newhook (node_p node, hook_p hook, const char *name) 292127376Srik{ 293127376Srik priv_p priv = NG_NODE_PRIVATE (node); 294127376Srik 295127376Srik if (strcmp (name, NG_SPPP_HOOK_DOWNSTREAM) != 0) 296127376Srik return (EINVAL); 297127376Srik 298127376Srik if (priv->hook) 299127376Srik return (EISCONN); 300127376Srik 301127376Srik priv->hook = hook; 302127376Srik NG_HOOK_SET_PRIVATE (hook, priv); 303127376Srik 304127376Srik return (0); 305127376Srik} 306127376Srik 307127376Srik/* 308127376Srik * Receive a control message 309127376Srik */ 310127376Srikstatic int 311127376Srikng_sppp_rcvmsg (node_p node, item_p item, hook_p lasthook) 312127376Srik{ 313127376Srik const priv_p priv = NG_NODE_PRIVATE (node); 314127376Srik struct ng_mesg *msg = NULL; 315127376Srik struct ng_mesg *resp = NULL; 316147256Sbrooks struct sppp *const pp = IFP2SP(priv->ifp); 317127376Srik int error = 0; 318127376Srik 319127376Srik NGI_GET_MSG (item, msg); 320127376Srik switch (msg->header.typecookie) { 321127376Srik case NGM_SPPP_COOKIE: 322127376Srik switch (msg->header.cmd) { 323127376Srik case NGM_SPPP_GET_IFNAME: 324141197Sru NG_MKRESPONSE (resp, msg, IFNAMSIZ, M_NOWAIT); 325127376Srik if (!resp) { 326127376Srik error = ENOMEM; 327127376Srik break; 328127376Srik } 329147256Sbrooks strlcpy(resp->data, SP2IFP(pp)->if_xname, IFNAMSIZ); 330127376Srik break; 331127376Srik 332127376Srik default: 333127376Srik error = EINVAL; 334127376Srik break; 335127376Srik } 336127376Srik break; 337127376Srik default: 338127376Srik error = EINVAL; 339127376Srik break; 340127376Srik } 341127376Srik NG_RESPOND_MSG (error, node, item, resp); 342127376Srik NG_FREE_MSG (msg); 343127376Srik return (error); 344127376Srik} 345127376Srik 346127376Srik/* 347127376Srik * Recive data from a hook. Pass the packet to the correct input routine. 348127376Srik */ 349127376Srikstatic int 350127376Srikng_sppp_rcvdata (hook_p hook, item_p item) 351127376Srik{ 352127376Srik struct mbuf *m; 353127376Srik const priv_p priv = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 354147256Sbrooks struct sppp *const pp = IFP2SP(priv->ifp); 355127376Srik 356127376Srik NGI_GET_M (item, m); 357127376Srik NG_FREE_ITEM (item); 358127376Srik /* Sanity checks */ 359127376Srik KASSERT (m->m_flags & M_PKTHDR, ("%s: not pkthdr", __func__)); 360147256Sbrooks if ((SP2IFP(pp)->if_flags & IFF_UP) == 0) { 361127376Srik NG_FREE_M (m); 362127376Srik return (ENETDOWN); 363127376Srik } 364127376Srik 365127376Srik /* Update interface stats */ 366147256Sbrooks SP2IFP(pp)->if_ipackets++; 367127376Srik 368127376Srik /* Note receiving interface */ 369147256Sbrooks m->m_pkthdr.rcvif = SP2IFP(pp); 370127376Srik 371127376Srik /* Berkeley packet filter */ 372165632Sjhb BPF_MTAP (SP2IFP(pp), m); 373127376Srik 374127376Srik /* Send packet */ 375147256Sbrooks sppp_input (SP2IFP(pp), m); 376127376Srik return 0; 377127376Srik} 378127376Srik 379127376Srik/* 380127376Srik * Shutdown and remove the node and its associated interface. 381127376Srik */ 382127376Srikstatic int 383127376Srikng_sppp_shutdown (node_p node) 384127376Srik{ 385127376Srik const priv_p priv = NG_NODE_PRIVATE(node); 386127376Srik /* Detach from the packet filter list of interfaces. */ 387147256Sbrooks bpfdetach (priv->ifp); 388147256Sbrooks sppp_detach (priv->ifp); 389147256Sbrooks if_detach (priv->ifp); 390147256Sbrooks if_free(priv->ifp); 391127376Srik ng_sppp_free_unit (priv->unit); 392184205Sdes free (priv, M_NETGRAPH_SPPP); 393127376Srik NG_NODE_SET_PRIVATE (node, NULL); 394127376Srik NG_NODE_UNREF (node); 395127376Srik return (0); 396127376Srik} 397127376Srik 398127376Srik/* 399127376Srik * Hook disconnection. 400127376Srik */ 401127376Srikstatic int 402127376Srikng_sppp_disconnect (hook_p hook) 403127376Srik{ 404127376Srik const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 405127376Srik 406127376Srik if (priv) 407127376Srik priv->hook = NULL; 408127376Srik 409127376Srik return (0); 410127376Srik} 411