ng_sppp.c revision 148887
1/* 2 * ng_sppp.c Netgraph to Sppp module. 3 */ 4 5/*- 6 * Copyright (C) 2002-2004 Cronyx Engineering. 7 * Copyright (C) 2002-2004 Roman Kurakin <rik@cronyx.ru> 8 * 9 * This software is distributed with NO WARRANTIES, not even the implied 10 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Authors grant any other persons or organisations a permission to use, 13 * modify and redistribute this software in source and binary forms, 14 * as long as this message is kept with the software, all derivative 15 * works or modified versions. 16 * 17 * Cronyx Id: ng_sppp.c,v 1.1.2.10 2004/03/01 15:17:21 rik Exp $ 18 */ 19#include <sys/cdefs.h> 20__FBSDID("$FreeBSD: head/sys/netgraph/ng_sppp.c 148887 2005-08-09 10:20:02Z rwatson $"); 21 22#include <sys/param.h> 23#include <sys/systm.h> 24#include <sys/errno.h> 25#include <sys/kernel.h> 26#include <sys/malloc.h> 27#include <sys/mbuf.h> 28#include <sys/errno.h> 29#include <sys/sockio.h> 30#include <sys/socket.h> 31#include <sys/syslog.h> 32#include <sys/libkern.h> 33 34#include <net/if.h> 35#include <net/if_types.h> 36#include <net/bpf.h> 37#include <net/if_sppp.h> 38 39#include <netinet/in.h> 40 41#include <netgraph/ng_message.h> 42#include <netgraph/netgraph.h> 43#include <netgraph/ng_parse.h> 44#include <netgraph/ng_sppp.h> 45 46#ifdef NG_SEPARATE_MALLOC 47MALLOC_DEFINE(M_NETGRAPH_SPPP, "netgraph_sppp", "netgraph sppp node "); 48#else 49#define M_NETGRAPH_SPPP M_NETGRAPH 50#endif 51 52/* Node private data */ 53struct ng_sppp_private { 54 struct ifnet *ifp; /* Our interface */ 55 int unit; /* Interface unit number */ 56 node_p node; /* Our netgraph node */ 57 hook_p hook; /* Hook */ 58}; 59typedef struct ng_sppp_private *priv_p; 60 61/* Interface methods */ 62static void ng_sppp_start (struct ifnet *ifp); 63static int ng_sppp_ioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 64 65/* Netgraph methods */ 66static ng_constructor_t ng_sppp_constructor; 67static ng_rcvmsg_t ng_sppp_rcvmsg; 68static ng_shutdown_t ng_sppp_shutdown; 69static ng_newhook_t ng_sppp_newhook; 70static ng_rcvdata_t ng_sppp_rcvdata; 71static ng_disconnect_t ng_sppp_disconnect; 72 73/* List of commands and how to convert arguments to/from ASCII */ 74static const struct ng_cmdlist ng_sppp_cmds[] = { 75 { 76 NGM_SPPP_COOKIE, 77 NGM_SPPP_GET_IFNAME, 78 "getifname", 79 NULL, 80 &ng_parse_string_type 81 }, 82 { 0 } 83}; 84 85/* Node type descriptor */ 86static struct ng_type typestruct = { 87 .version = NG_ABI_VERSION, 88 .name = NG_SPPP_NODE_TYPE, 89 .constructor = ng_sppp_constructor, 90 .rcvmsg = ng_sppp_rcvmsg, 91 .shutdown = ng_sppp_shutdown, 92 .newhook = ng_sppp_newhook, 93 .rcvdata = ng_sppp_rcvdata, 94 .disconnect = ng_sppp_disconnect, 95 .cmdlist = ng_sppp_cmds, 96}; 97NETGRAPH_INIT(sppp, &typestruct); 98 99MODULE_DEPEND (ng_sppp, sppp, 1, 1, 1); 100 101/* We keep a bitmap indicating which unit numbers are free. 102 Zero means the unit number is free, one means it's taken. */ 103static unsigned char *ng_sppp_units = NULL; 104static unsigned char ng_sppp_units_len = 0; 105static unsigned char ng_units_in_use = 0; 106 107/* 108 * Find the first free unit number for a new interface. 109 * Increase the size of the unit bitmap as necessary. 110 */ 111static __inline int 112ng_sppp_get_unit (int *unit) 113{ 114 int index, bit; 115 unsigned char mask; 116 117 for (index = 0; index < ng_sppp_units_len 118 && ng_sppp_units[index] == 0xFF; index++); 119 if (index == ng_sppp_units_len) { /* extend array */ 120 unsigned char *newarray; 121 int newlen; 122 123 newlen = (2 * ng_sppp_units_len) + sizeof (*ng_sppp_units); 124 MALLOC (newarray, unsigned char *, 125 newlen * sizeof (*ng_sppp_units), M_NETGRAPH_SPPP, M_NOWAIT); 126 if (newarray == NULL) 127 return (ENOMEM); 128 bcopy (ng_sppp_units, newarray, 129 ng_sppp_units_len * sizeof (*ng_sppp_units)); 130 bzero (newarray + ng_sppp_units_len, 131 newlen - ng_sppp_units_len); 132 if (ng_sppp_units != NULL) 133 FREE (ng_sppp_units, M_NETGRAPH_SPPP); 134 ng_sppp_units = newarray; 135 ng_sppp_units_len = newlen; 136 } 137 mask = ng_sppp_units[index]; 138 for (bit = 0; (mask & 1) != 0; bit++) 139 mask >>= 1; 140 KASSERT ((bit >= 0 && bit < NBBY), 141 ("%s: word=%d bit=%d", __func__, ng_sppp_units[index], bit)); 142 ng_sppp_units[index] |= (1 << bit); 143 *unit = (index * NBBY) + bit; 144 ng_units_in_use++; 145 return (0); 146} 147 148/* 149 * Free a no longer needed unit number. 150 */ 151static __inline void 152ng_sppp_free_unit (int unit) 153{ 154 int index, bit; 155 156 index = unit / NBBY; 157 bit = unit % NBBY; 158 KASSERT (index < ng_sppp_units_len, 159 ("%s: unit=%d len=%d", __func__, unit, ng_sppp_units_len)); 160 KASSERT ((ng_sppp_units[index] & (1 << bit)) != 0, 161 ("%s: unit=%d is free", __func__, unit)); 162 ng_sppp_units[index] &= ~(1 << bit); 163 164 ng_units_in_use--; 165 if (ng_units_in_use == 0) { 166 FREE (ng_sppp_units, M_NETGRAPH_SPPP); 167 ng_sppp_units_len = 0; 168 ng_sppp_units = NULL; 169 } 170} 171 172/************************************************************************ 173 INTERFACE STUFF 174 ************************************************************************/ 175 176/* 177 * Process an ioctl for the interface 178 */ 179static int 180ng_sppp_ioctl (struct ifnet *ifp, u_long command, caddr_t data) 181{ 182 int error = 0; 183 184 error = sppp_ioctl (ifp, command, data); 185 if (error) 186 return error; 187 188 return error; 189} 190 191/* 192 * This routine should never be called 193 */ 194 195static void 196ng_sppp_start (struct ifnet *ifp) 197{ 198 struct mbuf *m; 199 int len, error = 0; 200 priv_p priv = ifp->if_softc; 201 202 /* Check interface flags */ 203 /* 204 * This has side effects. It is not good idea to stop sending if we 205 * are not UP. If we are not running we still want to send LCP term 206 * packets. 207 */ 208/* if (!((ifp->if_flags & IFF_UP) && */ 209/* (ifp->if_drv_flags & IFF_DRV_RUNNING))) { */ 210/* return;*/ 211/* }*/ 212 213 if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 214 return; 215 216 if (!priv->hook) 217 return; 218 219 ifp->if_drv_flags |= IFF_DRV_OACTIVE; 220 221 while ((m = sppp_dequeue (ifp)) != NULL) { 222 if (ifp->if_bpf) 223 BPF_MTAP (ifp, m); 224 len = m->m_pkthdr.len; 225 226 NG_SEND_DATA_ONLY (error, priv->hook, m); 227 228 if (error) { 229 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 230 return; 231 } 232 } 233 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 234} 235 236/************************************************************************ 237 NETGRAPH NODE STUFF 238 ************************************************************************/ 239 240/* 241 * Constructor for a node 242 */ 243static int 244ng_sppp_constructor (node_p node) 245{ 246 struct sppp *pp; 247 struct ifnet *ifp; 248 priv_p priv; 249 int error = 0; 250 251 /* Allocate node and interface private structures */ 252 MALLOC (priv, priv_p, sizeof(*priv), M_NETGRAPH_SPPP, M_NOWAIT|M_ZERO); 253 if (priv == NULL) 254 return (ENOMEM); 255 256 ifp = if_alloc(IFT_PPP); 257 if (ifp == NULL) { 258 FREE (priv, M_NETGRAPH_SPPP); 259 return (ENOSPC); 260 } 261 pp = IFP2SP(ifp); 262 263 /* Link them together */ 264 ifp->if_softc = priv; 265 266 /* Get an interface unit number */ 267 if ((error = ng_sppp_get_unit(&priv->unit)) != 0) { 268 FREE (pp, M_NETGRAPH_SPPP); 269 FREE (priv, M_NETGRAPH_SPPP); 270 return (error); 271 } 272 273 274 /* Link together node and private info */ 275 NG_NODE_SET_PRIVATE (node, priv); 276 priv->node = node; 277 278 /* Initialize interface structure */ 279 if_initname (SP2IFP(pp), NG_SPPP_IFACE_NAME, priv->unit); 280 ifp->if_start = ng_sppp_start; 281 ifp->if_ioctl = ng_sppp_ioctl; 282 ifp->if_watchdog = NULL; 283 ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); 284 285 /* Give this node the same name as the interface (if possible) */ 286 if (ng_name_node(node, SP2IFP(pp)->if_xname) != 0) 287 log (LOG_WARNING, "%s: can't acquire netgraph name\n", 288 SP2IFP(pp)->if_xname); 289 290 /* Attach the interface */ 291 sppp_attach (ifp); 292 if_attach (ifp); 293 bpfattach (ifp, DLT_NULL, sizeof(u_int32_t)); 294 295 /* Done */ 296 return (0); 297} 298 299/* 300 * Give our ok for a hook to be added 301 */ 302static int 303ng_sppp_newhook (node_p node, hook_p hook, const char *name) 304{ 305 priv_p priv = NG_NODE_PRIVATE (node); 306 307 if (strcmp (name, NG_SPPP_HOOK_DOWNSTREAM) != 0) 308 return (EINVAL); 309 310 if (priv->hook) 311 return (EISCONN); 312 313 priv->hook = hook; 314 NG_HOOK_SET_PRIVATE (hook, priv); 315 316 return (0); 317} 318 319/* 320 * Receive a control message 321 */ 322static int 323ng_sppp_rcvmsg (node_p node, item_p item, hook_p lasthook) 324{ 325 const priv_p priv = NG_NODE_PRIVATE (node); 326 struct ng_mesg *msg = NULL; 327 struct ng_mesg *resp = NULL; 328 struct sppp *const pp = IFP2SP(priv->ifp); 329 int error = 0; 330 331 NGI_GET_MSG (item, msg); 332 switch (msg->header.typecookie) { 333 case NGM_SPPP_COOKIE: 334 switch (msg->header.cmd) { 335 case NGM_SPPP_GET_IFNAME: 336 NG_MKRESPONSE (resp, msg, IFNAMSIZ, M_NOWAIT); 337 if (!resp) { 338 error = ENOMEM; 339 break; 340 } 341 strlcpy(resp->data, SP2IFP(pp)->if_xname, IFNAMSIZ); 342 break; 343 344 default: 345 error = EINVAL; 346 break; 347 } 348 break; 349 default: 350 error = EINVAL; 351 break; 352 } 353 NG_RESPOND_MSG (error, node, item, resp); 354 NG_FREE_MSG (msg); 355 return (error); 356} 357 358/* 359 * Recive data from a hook. Pass the packet to the correct input routine. 360 */ 361static int 362ng_sppp_rcvdata (hook_p hook, item_p item) 363{ 364 struct mbuf *m; 365 const priv_p priv = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 366 struct sppp *const pp = IFP2SP(priv->ifp); 367 368 NGI_GET_M (item, m); 369 NG_FREE_ITEM (item); 370 /* Sanity checks */ 371 KASSERT (m->m_flags & M_PKTHDR, ("%s: not pkthdr", __func__)); 372 if ((SP2IFP(pp)->if_flags & IFF_UP) == 0) { 373 NG_FREE_M (m); 374 return (ENETDOWN); 375 } 376 377 /* Update interface stats */ 378 SP2IFP(pp)->if_ipackets++; 379 380 /* Note receiving interface */ 381 m->m_pkthdr.rcvif = SP2IFP(pp); 382 383 /* Berkeley packet filter */ 384 if (SP2IFP(pp)->if_bpf) 385 BPF_MTAP (SP2IFP(pp), m); 386 387 /* Send packet */ 388 sppp_input (SP2IFP(pp), m); 389 return 0; 390} 391 392/* 393 * Shutdown and remove the node and its associated interface. 394 */ 395static int 396ng_sppp_shutdown (node_p node) 397{ 398 const priv_p priv = NG_NODE_PRIVATE(node); 399 /* Detach from the packet filter list of interfaces. */ 400 bpfdetach (priv->ifp); 401 sppp_detach (priv->ifp); 402 if_detach (priv->ifp); 403 if_free(priv->ifp); 404 ng_sppp_free_unit (priv->unit); 405 FREE (priv, M_NETGRAPH_SPPP); 406 NG_NODE_SET_PRIVATE (node, NULL); 407 NG_NODE_UNREF (node); 408 return (0); 409} 410 411/* 412 * Hook disconnection. 413 */ 414static int 415ng_sppp_disconnect (hook_p hook) 416{ 417 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 418 419 if (priv) 420 priv->hook = NULL; 421 422 return (0); 423} 424