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/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 "ng_message.h" 42 #include "netgraph.h" 43 #include "ng_parse.h" 44 #include "ng_sppp.h" 45 46 #ifdef NG_SEPARATE_MALLOC 47 MALLOC_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 */ 53 struct 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 }; 59 typedef struct ng_sppp_private *priv_p; 60 61 /* Interface methods */ 62 static void ng_sppp_start (struct ifnet *ifp, struct ifaltq_subque *); 63 static int ng_sppp_ioctl (struct ifnet *ifp, u_long cmd, caddr_t data); 64 65 /* Netgraph methods */ 66 static ng_constructor_t ng_sppp_constructor; 67 static ng_rcvmsg_t ng_sppp_rcvmsg; 68 static ng_shutdown_t ng_sppp_shutdown; 69 static ng_newhook_t ng_sppp_newhook; 70 static ng_rcvdata_t ng_sppp_rcvdata; 71 static ng_disconnect_t ng_sppp_disconnect; 72 73 /* List of commands and how to convert arguments to/from ASCII */ 74 static 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 */ 86 static 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 }; 97 NETGRAPH_INIT(sppp, &typestruct); 98 99 MODULE_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. */ 103 static unsigned char *ng_sppp_units = NULL; 104 static unsigned char ng_sppp_units_len = 0; 105 static 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 */ 111 static __inline int 112 ng_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 newarray = kmalloc(newlen * sizeof(*ng_sppp_units), 125 M_NETGRAPH_SPPP, M_WAITOK | M_NULLOK); 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 kfree(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 */ 151 static __inline void 152 ng_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 kfree(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 */ 179 static int 180 ng_sppp_ioctl (struct ifnet *ifp, u_long command, caddr_t data) 181 { 182 return sppp_ioctl (ifp, command, data); 183 } 184 185 /* 186 * This routine should never be called 187 */ 188 189 static void 190 ng_sppp_start (struct ifnet *ifp, struct ifaltq_subque *ifsq __unused) 191 { 192 struct mbuf *m; 193 int len, error = 0; 194 priv_p priv = ifp->if_softc; 195 196 /* Check interface flags */ 197 /* 198 * This has side effects. It is not good idea to stop sending if we 199 * are not UP. If we are not running we still want to send LCP term 200 * packets. 201 */ 202 /* if (!((ifp->if_flags & IFF_UP) && */ 203 /* (ifp->if_drv_flags & IFF_DRV_RUNNING))) { */ 204 /* return;*/ 205 /* }*/ 206 207 if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 208 return; 209 210 if (!priv->hook) 211 return; 212 213 ifp->if_drv_flags |= IFF_DRV_OACTIVE; 214 215 while ((m = sppp_dequeue (ifp)) != NULL) { 216 BPF_MTAP (ifp, m); 217 len = m->m_pkthdr.len; 218 219 NG_SEND_DATA_ONLY (error, priv->hook, m); 220 221 if (error) { 222 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 223 return; 224 } 225 } 226 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 227 } 228 229 /************************************************************************ 230 NETGRAPH NODE STUFF 231 ************************************************************************/ 232 233 /* 234 * Constructor for a node 235 */ 236 static int 237 ng_sppp_constructor (node_p node) 238 { 239 struct sppp *pp; 240 struct ifnet *ifp; 241 priv_p priv; 242 int error = 0; 243 244 /* Allocate node and interface private structures */ 245 priv = kmalloc(sizeof(*priv), M_NETGRAPH_SPPP, 246 M_WAITOK | M_NULLOK | M_ZERO); 247 if (priv == NULL) 248 return (ENOMEM); 249 250 ifp = if_alloc(IFT_PPP); 251 if (ifp == NULL) { 252 kfree(priv, M_NETGRAPH_SPPP); 253 return (ENOSPC); 254 } 255 pp = IFP2SP(ifp); 256 257 /* Link them together */ 258 ifp->if_softc = priv; 259 priv->ifp = ifp; 260 261 /* Get an interface unit number */ 262 if ((error = ng_sppp_get_unit(&priv->unit)) != 0) { 263 kfree(pp, M_NETGRAPH_SPPP); 264 kfree(priv, M_NETGRAPH_SPPP); 265 return (error); 266 } 267 268 269 /* Link together node and private info */ 270 NG_NODE_SET_PRIVATE (node, priv); 271 priv->node = node; 272 273 /* Initialize interface structure */ 274 if_initname (SP2IFP(pp), NG_SPPP_IFACE_NAME, priv->unit); 275 ifp->if_start = ng_sppp_start; 276 ifp->if_ioctl = ng_sppp_ioctl; 277 ifp->if_watchdog = NULL; 278 ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST); 279 280 /* Give this node the same name as the interface (if possible) */ 281 if (ng_name_node(node, SP2IFP(pp)->if_xname) != 0) 282 log (LOG_WARNING, "%s: can't acquire netgraph name\n", 283 SP2IFP(pp)->if_xname); 284 285 /* Attach the interface */ 286 sppp_attach (ifp); 287 if_attach (ifp); 288 bpfattach (ifp, DLT_NULL, sizeof(u_int32_t)); 289 290 /* Done */ 291 return (0); 292 } 293 294 /* 295 * Give our ok for a hook to be added 296 */ 297 static int 298 ng_sppp_newhook (node_p node, hook_p hook, const char *name) 299 { 300 priv_p priv = NG_NODE_PRIVATE (node); 301 302 if (strcmp (name, NG_SPPP_HOOK_DOWNSTREAM) != 0) 303 return (EINVAL); 304 305 if (priv->hook) 306 return (EISCONN); 307 308 priv->hook = hook; 309 NG_HOOK_SET_PRIVATE (hook, priv); 310 311 return (0); 312 } 313 314 /* 315 * Receive a control message 316 */ 317 static int 318 ng_sppp_rcvmsg (node_p node, item_p item, hook_p lasthook) 319 { 320 const priv_p priv = NG_NODE_PRIVATE (node); 321 struct ng_mesg *msg = NULL; 322 struct ng_mesg *resp = NULL; 323 struct sppp *const pp = IFP2SP(priv->ifp); 324 int error = 0; 325 326 NGI_GET_MSG (item, msg); 327 switch (msg->header.typecookie) { 328 case NGM_SPPP_COOKIE: 329 switch (msg->header.cmd) { 330 case NGM_SPPP_GET_IFNAME: 331 NG_MKRESPONSE (resp, msg, IFNAMSIZ, M_WAITOK | M_NULLOK); 332 if (!resp) { 333 error = ENOMEM; 334 break; 335 } 336 strlcpy(resp->data, SP2IFP(pp)->if_xname, IFNAMSIZ); 337 break; 338 339 default: 340 error = EINVAL; 341 break; 342 } 343 break; 344 default: 345 error = EINVAL; 346 break; 347 } 348 NG_RESPOND_MSG (error, node, item, resp); 349 NG_FREE_MSG (msg); 350 return (error); 351 } 352 353 /* 354 * Recive data from a hook. Pass the packet to the correct input routine. 355 */ 356 static int 357 ng_sppp_rcvdata (hook_p hook, item_p item) 358 { 359 struct mbuf *m; 360 const priv_p priv = NG_NODE_PRIVATE (NG_HOOK_NODE (hook)); 361 struct sppp *const pp = IFP2SP(priv->ifp); 362 363 NGI_GET_M (item, m); 364 NG_FREE_ITEM (item); 365 /* Sanity checks */ 366 KASSERT (m->m_flags & M_PKTHDR, ("%s: not pkthdr", __func__)); 367 if ((SP2IFP(pp)->if_flags & IFF_UP) == 0) { 368 NG_FREE_M (m); 369 return (ENETDOWN); 370 } 371 372 /* Update interface stats */ 373 SP2IFP(pp)->if_ipackets++; 374 375 /* Note receiving interface */ 376 m->m_pkthdr.rcvif = SP2IFP(pp); 377 378 /* Berkeley packet filter */ 379 BPF_MTAP (SP2IFP(pp), m); 380 381 /* Send packet */ 382 sppp_input (SP2IFP(pp), m); 383 return 0; 384 } 385 386 /* 387 * Shutdown and remove the node and its associated interface. 388 */ 389 static int 390 ng_sppp_shutdown (node_p node) 391 { 392 const priv_p priv = NG_NODE_PRIVATE(node); 393 /* Detach from the packet filter list of interfaces. */ 394 bpfdetach (priv->ifp); 395 sppp_detach (priv->ifp); 396 if_detach (priv->ifp); 397 if_free(priv->ifp); 398 ng_sppp_free_unit (priv->unit); 399 kfree(priv, M_NETGRAPH_SPPP); 400 NG_NODE_SET_PRIVATE (node, NULL); 401 NG_NODE_UNREF (node); 402 return (0); 403 } 404 405 /* 406 * Hook disconnection. 407 */ 408 static int 409 ng_sppp_disconnect (hook_p hook) 410 { 411 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 412 413 if (priv) 414 priv->hook = NULL; 415 416 return (0); 417 } 418