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 MALLOC (newarray, unsigned char *, 126 newlen * sizeof (*ng_sppp_units), 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 FREE (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 FREE (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 MALLOC (priv, priv_p, sizeof(*priv), M_NETGRAPH_SPPP, M_WAITOK | M_NULLOK | 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 priv->ifp = ifp; 266 267 /* Get an interface unit number */ 268 if ((error = ng_sppp_get_unit(&priv->unit)) != 0) { 269 FREE (pp, M_NETGRAPH_SPPP); 270 FREE (priv, M_NETGRAPH_SPPP); 271 return (error); 272 } 273 274 275 /* Link together node and private info */ 276 NG_NODE_SET_PRIVATE (node, priv); 277 priv->node = node; 278 279 /* Initialize interface structure */ 280 if_initname (SP2IFP(pp), NG_SPPP_IFACE_NAME, priv->unit); 281 ifp->if_start = ng_sppp_start; 282 ifp->if_ioctl = ng_sppp_ioctl; 283 ifp->if_watchdog = NULL; 284 ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); 285 286 /* Give this node the same name as the interface (if possible) */ 287 if (ng_name_node(node, SP2IFP(pp)->if_xname) != 0) 288 log (LOG_WARNING, "%s: can't acquire netgraph name\n", 289 SP2IFP(pp)->if_xname); 290 291 /* Attach the interface */ 292 sppp_attach (ifp); 293 if_attach (ifp); 294 bpfattach (ifp, DLT_NULL, sizeof(u_int32_t)); 295 296 /* Done */ 297 return (0); 298 } 299 300 /* 301 * Give our ok for a hook to be added 302 */ 303 static int 304 ng_sppp_newhook (node_p node, hook_p hook, const char *name) 305 { 306 priv_p priv = NG_NODE_PRIVATE (node); 307 308 if (strcmp (name, NG_SPPP_HOOK_DOWNSTREAM) != 0) 309 return (EINVAL); 310 311 if (priv->hook) 312 return (EISCONN); 313 314 priv->hook = hook; 315 NG_HOOK_SET_PRIVATE (hook, priv); 316 317 return (0); 318 } 319 320 /* 321 * Receive a control message 322 */ 323 static int 324 ng_sppp_rcvmsg (node_p node, item_p item, hook_p lasthook) 325 { 326 const priv_p priv = NG_NODE_PRIVATE (node); 327 struct ng_mesg *msg = NULL; 328 struct ng_mesg *resp = NULL; 329 struct sppp *const pp = IFP2SP(priv->ifp); 330 int error = 0; 331 332 NGI_GET_MSG (item, msg); 333 switch (msg->header.typecookie) { 334 case NGM_SPPP_COOKIE: 335 switch (msg->header.cmd) { 336 case NGM_SPPP_GET_IFNAME: 337 NG_MKRESPONSE (resp, msg, IFNAMSIZ, M_WAITOK | M_NULLOK); 338 if (!resp) { 339 error = ENOMEM; 340 break; 341 } 342 strlcpy(resp->data, SP2IFP(pp)->if_xname, IFNAMSIZ); 343 break; 344 345 default: 346 error = EINVAL; 347 break; 348 } 349 break; 350 default: 351 error = EINVAL; 352 break; 353 } 354 NG_RESPOND_MSG (error, node, item, resp); 355 NG_FREE_MSG (msg); 356 return (error); 357 } 358 359 /* 360 * Recive data from a hook. Pass the packet to the correct input routine. 361 */ 362 static int 363 ng_sppp_rcvdata (hook_p hook, item_p item) 364 { 365 struct mbuf *m; 366 const priv_p priv = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 367 struct sppp *const pp = IFP2SP(priv->ifp); 368 369 NGI_GET_M (item, m); 370 NG_FREE_ITEM (item); 371 /* Sanity checks */ 372 KASSERT (m->m_flags & M_PKTHDR, ("%s: not pkthdr", __func__)); 373 if ((SP2IFP(pp)->if_flags & IFF_UP) == 0) { 374 NG_FREE_M (m); 375 return (ENETDOWN); 376 } 377 378 /* Update interface stats */ 379 SP2IFP(pp)->if_ipackets++; 380 381 /* Note receiving interface */ 382 m->m_pkthdr.rcvif = SP2IFP(pp); 383 384 /* Berkeley packet filter */ 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 */ 395 static int 396 ng_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 */ 414 static int 415 ng_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