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