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