2 * ng_sppp.c Netgraph to Sppp module.
6 * Copyright (C) 2002-2004 Cronyx Engineering.
7 * Copyright (C) 2002-2004 Roman Kurakin <rik@cronyx.ru>
9 * This software is distributed with NO WARRANTIES, not even the implied
10 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
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.
17 * Cronyx Id: ng_sppp.c,v 1.1.2.10 2004/03/01 15:17:21 rik Exp $
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 $
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>
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>
36 #include <net/if_types.h>
38 #include <net/if_sppp.h>
40 #include <netinet/in.h>
42 #include "ng_message.h"
47 #ifdef NG_SEPARATE_MALLOC
48 MALLOC_DEFINE(M_NETGRAPH_SPPP
, "netgraph_sppp", "netgraph sppp node ");
50 #define M_NETGRAPH_SPPP M_NETGRAPH
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 */
60 typedef struct ng_sppp_private
*priv_p
;
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
);
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
;
74 /* List of commands and how to convert arguments to/from ASCII */
75 static const struct ng_cmdlist ng_sppp_cmds
[] = {
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
,
98 NETGRAPH_INIT(sppp
, &typestruct
);
100 MODULE_DEPEND (ng_sppp
, sppp
, 1, 1, 1);
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;
109 * Find the first free unit number for a new interface.
110 * Increase the size of the unit bitmap as necessary.
113 ng_sppp_get_unit (int *unit
)
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
;
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
)
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
;
138 mask
= ng_sppp_units
[index
];
139 for (bit
= 0; (mask
& 1) != 0; bit
++)
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
;
150 * Free a no longer needed unit number.
153 ng_sppp_free_unit (int unit
)
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
);
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
;
173 /************************************************************************
175 ************************************************************************/
178 * Process an ioctl for the interface
181 ng_sppp_ioctl (struct ifnet
*ifp
, u_long command
, caddr_t data
)
185 error
= sppp_ioctl (ifp
, command
, data
);
193 * This routine should never be called
197 ng_sppp_start (struct ifnet
*ifp
)
201 priv_p priv
= ifp
->if_softc
;
203 /* Check interface flags */
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
209 /* if (!((ifp->if_flags & IFF_UP) && */
210 /* (ifp->if_drv_flags & IFF_DRV_RUNNING))) { */
214 if (ifp
->if_drv_flags
& IFF_DRV_OACTIVE
)
220 ifp
->if_drv_flags
|= IFF_DRV_OACTIVE
;
222 while ((m
= sppp_dequeue (ifp
)) != NULL
) {
224 len
= m
->m_pkthdr
.len
;
226 NG_SEND_DATA_ONLY (error
, priv
->hook
, m
);
229 ifp
->if_drv_flags
&= ~IFF_DRV_OACTIVE
;
233 ifp
->if_drv_flags
&= ~IFF_DRV_OACTIVE
;
236 /************************************************************************
238 ************************************************************************/
241 * Constructor for a node
244 ng_sppp_constructor (node_p node
)
251 /* Allocate node and interface private structures */
252 MALLOC (priv
, priv_p
, sizeof(*priv
), M_NETGRAPH_SPPP
, M_WAITOK
| M_NULLOK
| M_ZERO
);
256 ifp
= if_alloc(IFT_PPP
);
258 FREE (priv
, M_NETGRAPH_SPPP
);
263 /* Link them together */
264 ifp
->if_softc
= priv
;
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
);
275 /* Link together node and private info */
276 NG_NODE_SET_PRIVATE (node
, priv
);
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
);
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
);
291 /* Attach the interface */
294 bpfattach (ifp
, DLT_NULL
, sizeof(u_int32_t
));
301 * Give our ok for a hook to be added
304 ng_sppp_newhook (node_p node
, hook_p hook
, const char *name
)
306 priv_p priv
= NG_NODE_PRIVATE (node
);
308 if (strcmp (name
, NG_SPPP_HOOK_DOWNSTREAM
) != 0)
315 NG_HOOK_SET_PRIVATE (hook
, priv
);
321 * Receive a control message
324 ng_sppp_rcvmsg (node_p node
, item_p item
, hook_p lasthook
)
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
);
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
);
342 strlcpy(resp
->data
, SP2IFP(pp
)->if_xname
, IFNAMSIZ
);
354 NG_RESPOND_MSG (error
, node
, item
, resp
);
360 * Recive data from a hook. Pass the packet to the correct input routine.
363 ng_sppp_rcvdata (hook_p hook
, item_p item
)
366 const priv_p priv
= NG_NODE_PRIVATE (NG_HOOK_NODE (hook
));
367 struct sppp
*const pp
= IFP2SP(priv
->ifp
);
372 KASSERT (m
->m_flags
& M_PKTHDR
, ("%s: not pkthdr", __func__
));
373 if ((SP2IFP(pp
)->if_flags
& IFF_UP
) == 0) {
378 /* Update interface stats */
379 SP2IFP(pp
)->if_ipackets
++;
381 /* Note receiving interface */
382 m
->m_pkthdr
.rcvif
= SP2IFP(pp
);
384 /* Berkeley packet filter */
385 BPF_MTAP (SP2IFP(pp
), m
);
388 sppp_input (SP2IFP(pp
), m
);
393 * Shutdown and remove the node and its associated interface.
396 ng_sppp_shutdown (node_p node
)
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
);
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
);
412 * Hook disconnection.
415 ng_sppp_disconnect (hook_p hook
)
417 const priv_p priv
= NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));