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 $
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>
28 #include <sys/sockio.h>
29 #include <sys/socket.h>
30 #include <sys/syslog.h>
31 #include <sys/libkern.h>
34 #include <net/if_types.h>
36 #include <net/if_sppp.h>
38 #include <netinet/in.h>
40 #include "ng_message.h"
45 #ifdef NG_SEPARATE_MALLOC
46 MALLOC_DEFINE(M_NETGRAPH_SPPP
, "netgraph_sppp", "netgraph sppp node ");
48 #define M_NETGRAPH_SPPP M_NETGRAPH
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 */
58 typedef struct ng_sppp_private
*priv_p
;
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
);
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
;
72 /* List of commands and how to convert arguments to/from ASCII */
73 static const struct ng_cmdlist ng_sppp_cmds
[] = {
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
,
96 NETGRAPH_INIT(sppp
, &typestruct
);
98 MODULE_DEPEND (ng_sppp
, sppp
, 1, 1, 1);
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;
107 * Find the first free unit number for a new interface.
108 * Increase the size of the unit bitmap as necessary.
111 ng_sppp_get_unit (int *unit
)
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
;
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
)
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
;
136 mask
= ng_sppp_units
[index
];
137 for (bit
= 0; (mask
& 1) != 0; bit
++)
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
;
148 * Free a no longer needed unit number.
151 ng_sppp_free_unit (int unit
)
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
);
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
;
171 /************************************************************************
173 ************************************************************************/
176 * Process an ioctl for the interface
179 ng_sppp_ioctl (struct ifnet
*ifp
, u_long command
, caddr_t data
)
181 return sppp_ioctl (ifp
, command
, data
);
185 * This routine should never be called
189 ng_sppp_start (struct ifnet
*ifp
, struct ifaltq_subque
*ifsq __unused
)
193 priv_p priv
= ifp
->if_softc
;
195 /* Check interface flags */
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
201 /* if (!((ifp->if_flags & IFF_UP) && */
202 /* (ifp->if_drv_flags & IFF_DRV_RUNNING))) { */
206 if (ifp
->if_drv_flags
& IFF_DRV_OACTIVE
)
212 ifp
->if_drv_flags
|= IFF_DRV_OACTIVE
;
214 while ((m
= sppp_dequeue (ifp
)) != NULL
) {
216 len
= m
->m_pkthdr
.len
;
218 NG_SEND_DATA_ONLY (error
, priv
->hook
, m
);
221 ifp
->if_drv_flags
&= ~IFF_DRV_OACTIVE
;
225 ifp
->if_drv_flags
&= ~IFF_DRV_OACTIVE
;
228 /************************************************************************
230 ************************************************************************/
233 * Constructor for a node
236 ng_sppp_constructor (node_p node
)
243 /* Allocate node and interface private structures */
244 priv
= kmalloc(sizeof(*priv
), M_NETGRAPH_SPPP
,
245 M_WAITOK
| M_NULLOK
| M_ZERO
);
249 ifp
= if_alloc(IFT_PPP
);
251 kfree(priv
, M_NETGRAPH_SPPP
);
256 /* Link them together */
257 ifp
->if_softc
= priv
;
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
);
268 /* Link together node and private info */
269 NG_NODE_SET_PRIVATE (node
, priv
);
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
);
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
);
284 /* Attach the interface */
287 bpfattach (ifp
, DLT_NULL
, sizeof(u_int32_t
));
294 * Give our ok for a hook to be added
297 ng_sppp_newhook (node_p node
, hook_p hook
, const char *name
)
299 priv_p priv
= NG_NODE_PRIVATE (node
);
301 if (strcmp (name
, NG_SPPP_HOOK_DOWNSTREAM
) != 0)
308 NG_HOOK_SET_PRIVATE (hook
, priv
);
314 * Receive a control message
317 ng_sppp_rcvmsg (node_p node
, item_p item
, hook_p lasthook
)
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
);
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
);
335 strlcpy(resp
->data
, SP2IFP(pp
)->if_xname
, IFNAMSIZ
);
347 NG_RESPOND_MSG (error
, node
, item
, resp
);
353 * Recive data from a hook. Pass the packet to the correct input routine.
356 ng_sppp_rcvdata (hook_p hook
, item_p item
)
359 const priv_p priv
= NG_NODE_PRIVATE (NG_HOOK_NODE (hook
));
360 struct sppp
*const pp
= IFP2SP(priv
->ifp
);
365 KASSERT (m
->m_flags
& M_PKTHDR
, ("%s: not pkthdr", __func__
));
366 if ((SP2IFP(pp
)->if_flags
& IFF_UP
) == 0) {
371 /* Update interface stats */
372 SP2IFP(pp
)->if_ipackets
++;
374 /* Note receiving interface */
375 m
->m_pkthdr
.rcvif
= SP2IFP(pp
);
377 /* Berkeley packet filter */
378 BPF_MTAP (SP2IFP(pp
), m
);
381 sppp_input (SP2IFP(pp
), m
);
386 * Shutdown and remove the node and its associated interface.
389 ng_sppp_shutdown (node_p node
)
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
);
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
);
405 * Hook disconnection.
408 ng_sppp_disconnect (hook_p hook
)
410 const priv_p priv
= NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));