aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp/l2tp_netlink.c
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2010-04-02 02:19:10 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-03 17:56:05 -0400
commit309795f4bec2d69cd507a631f82065c2198a0825 (patch)
treeb3676be9a8f65f0d828a07e3bd6906bf7cd7b664 /net/l2tp/l2tp_netlink.c
parentf408e0ce40270559ef80f231843c93baa9947bc5 (diff)
l2tp: Add netlink control API for L2TP
In L2TPv3, we need to create/delete/modify/query L2TP tunnel and session contexts. The number of parameters is significant. So let's use netlink. Userspace uses this API to control L2TP tunnel/session contexts in the kernel. The previous pppol2tp driver was managed using [gs]etsockopt(). This API is retained for backwards compatibility. Unlike L2TPv2 which carries only PPP frames, L2TPv3 can carry raw ethernet frames or other frame types and these do not always have an associated socket family. Therefore, we need a way to use L2TP sessions that doesn't require a socket type for each supported frame type. Hence netlink is used. Signed-off-by: James Chapman <jchapman@katalix.com> Reviewed-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp/l2tp_netlink.c')
-rw-r--r--net/l2tp/l2tp_netlink.c830
1 files changed, 830 insertions, 0 deletions
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
new file mode 100644
index 000000000000..3d0f7f6f7488
--- /dev/null
+++ b/net/l2tp/l2tp_netlink.c
@@ -0,0 +1,830 @@
1/*
2 * L2TP netlink layer, for management
3 *
4 * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
5 *
6 * Partly based on the IrDA nelink implementation
7 * (see net/irda/irnetlink.c) which is:
8 * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
9 * which is in turn partly based on the wireless netlink code:
10 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16
17#include <net/sock.h>
18#include <net/genetlink.h>
19#include <net/udp.h>
20#include <linux/in.h>
21#include <linux/udp.h>
22#include <linux/socket.h>
23#include <linux/module.h>
24#include <linux/list.h>
25#include <net/net_namespace.h>
26
27#include <linux/l2tp.h>
28
29#include "l2tp_core.h"
30
31
32static struct genl_family l2tp_nl_family = {
33 .id = GENL_ID_GENERATE,
34 .name = L2TP_GENL_NAME,
35 .version = L2TP_GENL_VERSION,
36 .hdrsize = 0,
37 .maxattr = L2TP_ATTR_MAX,
38};
39
40/* Accessed under genl lock */
41static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX];
42
43static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info)
44{
45 u32 tunnel_id;
46 u32 session_id;
47 char *ifname;
48 struct l2tp_tunnel *tunnel;
49 struct l2tp_session *session = NULL;
50 struct net *net = genl_info_net(info);
51
52 if (info->attrs[L2TP_ATTR_IFNAME]) {
53 ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]);
54 session = l2tp_session_find_by_ifname(net, ifname);
55 } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) &&
56 (info->attrs[L2TP_ATTR_CONN_ID])) {
57 tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
58 session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
59 tunnel = l2tp_tunnel_find(net, tunnel_id);
60 if (tunnel)
61 session = l2tp_session_find(net, tunnel, session_id);
62 }
63
64 return session;
65}
66
67static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
68{
69 struct sk_buff *msg;
70 void *hdr;
71 int ret = -ENOBUFS;
72
73 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
74 if (!msg) {
75 ret = -ENOMEM;
76 goto out;
77 }
78
79 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
80 &l2tp_nl_family, 0, L2TP_CMD_NOOP);
81 if (IS_ERR(hdr)) {
82 ret = PTR_ERR(hdr);
83 goto err_out;
84 }
85
86 genlmsg_end(msg, hdr);
87
88 return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
89
90err_out:
91 nlmsg_free(msg);
92
93out:
94 return ret;
95}
96
97static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
98{
99 u32 tunnel_id;
100 u32 peer_tunnel_id;
101 int proto_version;
102 int fd;
103 int ret = 0;
104 struct l2tp_tunnel_cfg cfg = { 0, };
105 struct l2tp_tunnel *tunnel;
106 struct net *net = genl_info_net(info);
107
108 if (!info->attrs[L2TP_ATTR_CONN_ID]) {
109 ret = -EINVAL;
110 goto out;
111 }
112 tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
113
114 if (!info->attrs[L2TP_ATTR_PEER_CONN_ID]) {
115 ret = -EINVAL;
116 goto out;
117 }
118 peer_tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_CONN_ID]);
119
120 if (!info->attrs[L2TP_ATTR_PROTO_VERSION]) {
121 ret = -EINVAL;
122 goto out;
123 }
124 proto_version = nla_get_u8(info->attrs[L2TP_ATTR_PROTO_VERSION]);
125
126 if (!info->attrs[L2TP_ATTR_ENCAP_TYPE]) {
127 ret = -EINVAL;
128 goto out;
129 }
130 cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);
131
132 if (!info->attrs[L2TP_ATTR_FD]) {
133 ret = -EINVAL;
134 goto out;
135 }
136 fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
137
138 if (info->attrs[L2TP_ATTR_DEBUG])
139 cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
140
141 tunnel = l2tp_tunnel_find(net, tunnel_id);
142 if (tunnel != NULL) {
143 ret = -EEXIST;
144 goto out;
145 }
146
147 ret = -EINVAL;
148 switch (cfg.encap) {
149 case L2TP_ENCAPTYPE_UDP:
150 case L2TP_ENCAPTYPE_IP:
151 ret = l2tp_tunnel_create(net, fd, proto_version, tunnel_id,
152 peer_tunnel_id, &cfg, &tunnel);
153 break;
154 }
155
156out:
157 return ret;
158}
159
160static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info)
161{
162 struct l2tp_tunnel *tunnel;
163 u32 tunnel_id;
164 int ret = 0;
165 struct net *net = genl_info_net(info);
166
167 if (!info->attrs[L2TP_ATTR_CONN_ID]) {
168 ret = -EINVAL;
169 goto out;
170 }
171 tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
172
173 tunnel = l2tp_tunnel_find(net, tunnel_id);
174 if (tunnel == NULL) {
175 ret = -ENODEV;
176 goto out;
177 }
178
179 (void) l2tp_tunnel_delete(tunnel);
180
181out:
182 return ret;
183}
184
185static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info)
186{
187 struct l2tp_tunnel *tunnel;
188 u32 tunnel_id;
189 int ret = 0;
190 struct net *net = genl_info_net(info);
191
192 if (!info->attrs[L2TP_ATTR_CONN_ID]) {
193 ret = -EINVAL;
194 goto out;
195 }
196 tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
197
198 tunnel = l2tp_tunnel_find(net, tunnel_id);
199 if (tunnel == NULL) {
200 ret = -ENODEV;
201 goto out;
202 }
203
204 if (info->attrs[L2TP_ATTR_DEBUG])
205 tunnel->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
206
207out:
208 return ret;
209}
210
211static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags,
212 struct l2tp_tunnel *tunnel)
213{
214 void *hdr;
215 struct nlattr *nest;
216 struct sock *sk = NULL;
217 struct inet_sock *inet;
218
219 hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags,
220 L2TP_CMD_TUNNEL_GET);
221 if (IS_ERR(hdr))
222 return PTR_ERR(hdr);
223
224 NLA_PUT_U8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version);
225 NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id);
226 NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id);
227 NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, tunnel->debug);
228 NLA_PUT_U16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap);
229
230 nest = nla_nest_start(skb, L2TP_ATTR_STATS);
231 if (nest == NULL)
232 goto nla_put_failure;
233
234 NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, tunnel->stats.tx_packets);
235 NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, tunnel->stats.tx_bytes);
236 NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, tunnel->stats.tx_errors);
237 NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, tunnel->stats.rx_packets);
238 NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, tunnel->stats.rx_bytes);
239 NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, tunnel->stats.rx_seq_discards);
240 NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, tunnel->stats.rx_oos_packets);
241 NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, tunnel->stats.rx_errors);
242 nla_nest_end(skb, nest);
243
244 sk = tunnel->sock;
245 if (!sk)
246 goto out;
247
248 inet = inet_sk(sk);
249
250 switch (tunnel->encap) {
251 case L2TP_ENCAPTYPE_UDP:
252 NLA_PUT_U16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport));
253 NLA_PUT_U16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport));
254 NLA_PUT_U8(skb, L2TP_ATTR_UDP_CSUM, (sk->sk_no_check != UDP_CSUM_NOXMIT));
255 /* NOBREAK */
256 case L2TP_ENCAPTYPE_IP:
257 NLA_PUT_BE32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr);
258 NLA_PUT_BE32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr);
259 break;
260 }
261
262out:
263 return genlmsg_end(skb, hdr);
264
265nla_put_failure:
266 genlmsg_cancel(skb, hdr);
267 return -1;
268}
269
270static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
271{
272 struct l2tp_tunnel *tunnel;
273 struct sk_buff *msg;
274 u32 tunnel_id;
275 int ret = -ENOBUFS;
276 struct net *net = genl_info_net(info);
277
278 if (!info->attrs[L2TP_ATTR_CONN_ID]) {
279 ret = -EINVAL;
280 goto out;
281 }
282
283 tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
284
285 tunnel = l2tp_tunnel_find(net, tunnel_id);
286 if (tunnel == NULL) {
287 ret = -ENODEV;
288 goto out;
289 }
290
291 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
292 if (!msg) {
293 ret = -ENOMEM;
294 goto out;
295 }
296
297 ret = l2tp_nl_tunnel_send(msg, info->snd_pid, info->snd_seq,
298 NLM_F_ACK, tunnel);
299 if (ret < 0)
300 goto err_out;
301
302 return genlmsg_unicast(net, msg, info->snd_pid);
303
304err_out:
305 nlmsg_free(msg);
306
307out:
308 return ret;
309}
310
311static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb)
312{
313 int ti = cb->args[0];
314 struct l2tp_tunnel *tunnel;
315 struct net *net = sock_net(skb->sk);
316
317 for (;;) {
318 tunnel = l2tp_tunnel_find_nth(net, ti);
319 if (tunnel == NULL)
320 goto out;
321
322 if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).pid,
323 cb->nlh->nlmsg_seq, NLM_F_MULTI,
324 tunnel) <= 0)
325 goto out;
326
327 ti++;
328 }
329
330out:
331 cb->args[0] = ti;
332
333 return skb->len;
334}
335
336static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *info)
337{
338 u32 tunnel_id = 0;
339 u32 session_id;
340 u32 peer_session_id;
341 int ret = 0;
342 struct l2tp_tunnel *tunnel;
343 struct l2tp_session *session;
344 struct l2tp_session_cfg cfg = { 0, };
345 struct net *net = genl_info_net(info);
346
347 if (!info->attrs[L2TP_ATTR_CONN_ID]) {
348 ret = -EINVAL;
349 goto out;
350 }
351 tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
352 tunnel = l2tp_tunnel_find(net, tunnel_id);
353 if (!tunnel) {
354 ret = -ENODEV;
355 goto out;
356 }
357
358 if (!info->attrs[L2TP_ATTR_SESSION_ID]) {
359 ret = -EINVAL;
360 goto out;
361 }
362 session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
363 session = l2tp_session_find(net, tunnel, session_id);
364 if (session) {
365 ret = -EEXIST;
366 goto out;
367 }
368
369 if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) {
370 ret = -EINVAL;
371 goto out;
372 }
373 peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]);
374
375 if (!info->attrs[L2TP_ATTR_PW_TYPE]) {
376 ret = -EINVAL;
377 goto out;
378 }
379 cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]);
380 if (cfg.pw_type >= __L2TP_PWTYPE_MAX) {
381 ret = -EINVAL;
382 goto out;
383 }
384
385 if (tunnel->version > 2) {
386 if (info->attrs[L2TP_ATTR_OFFSET])
387 cfg.offset = nla_get_u16(info->attrs[L2TP_ATTR_OFFSET]);
388
389 if (info->attrs[L2TP_ATTR_DATA_SEQ])
390 cfg.data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]);
391
392 cfg.l2specific_type = L2TP_L2SPECTYPE_DEFAULT;
393 if (info->attrs[L2TP_ATTR_L2SPEC_TYPE])
394 cfg.l2specific_type = nla_get_u8(info->attrs[L2TP_ATTR_L2SPEC_TYPE]);
395
396 cfg.l2specific_len = 4;
397 if (info->attrs[L2TP_ATTR_L2SPEC_LEN])
398 cfg.l2specific_len = nla_get_u8(info->attrs[L2TP_ATTR_L2SPEC_LEN]);
399
400 if (info->attrs[L2TP_ATTR_COOKIE]) {
401 u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]);
402 if (len > 8) {
403 ret = -EINVAL;
404 goto out;
405 }
406 cfg.cookie_len = len;
407 memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len);
408 }
409 if (info->attrs[L2TP_ATTR_PEER_COOKIE]) {
410 u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]);
411 if (len > 8) {
412 ret = -EINVAL;
413 goto out;
414 }
415 cfg.peer_cookie_len = len;
416 memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len);
417 }
418 if (info->attrs[L2TP_ATTR_IFNAME])
419 cfg.ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]);
420
421 if (info->attrs[L2TP_ATTR_VLAN_ID])
422 cfg.vlan_id = nla_get_u16(info->attrs[L2TP_ATTR_VLAN_ID]);
423 }
424
425 if (info->attrs[L2TP_ATTR_DEBUG])
426 cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
427
428 if (info->attrs[L2TP_ATTR_RECV_SEQ])
429 cfg.recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
430
431 if (info->attrs[L2TP_ATTR_SEND_SEQ])
432 cfg.send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
433
434 if (info->attrs[L2TP_ATTR_LNS_MODE])
435 cfg.lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
436
437 if (info->attrs[L2TP_ATTR_RECV_TIMEOUT])
438 cfg.reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]);
439
440 if (info->attrs[L2TP_ATTR_MTU])
441 cfg.mtu = nla_get_u16(info->attrs[L2TP_ATTR_MTU]);
442
443 if (info->attrs[L2TP_ATTR_MRU])
444 cfg.mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]);
445
446 if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) ||
447 (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) {
448 ret = -EPROTONOSUPPORT;
449 goto out;
450 }
451
452 /* Check that pseudowire-specific params are present */
453 switch (cfg.pw_type) {
454 case L2TP_PWTYPE_NONE:
455 break;
456 case L2TP_PWTYPE_ETH_VLAN:
457 if (!info->attrs[L2TP_ATTR_VLAN_ID]) {
458 ret = -EINVAL;
459 goto out;
460 }
461 break;
462 case L2TP_PWTYPE_ETH:
463 break;
464 case L2TP_PWTYPE_PPP:
465 case L2TP_PWTYPE_PPP_AC:
466 break;
467 case L2TP_PWTYPE_IP:
468 default:
469 ret = -EPROTONOSUPPORT;
470 break;
471 }
472
473 ret = -EPROTONOSUPPORT;
474 if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create)
475 ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
476 session_id, peer_session_id, &cfg);
477
478out:
479 return ret;
480}
481
482static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *info)
483{
484 int ret = 0;
485 struct l2tp_session *session;
486 u16 pw_type;
487
488 session = l2tp_nl_session_find(info);
489 if (session == NULL) {
490 ret = -ENODEV;
491 goto out;
492 }
493
494 pw_type = session->pwtype;
495 if (pw_type < __L2TP_PWTYPE_MAX)
496 if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
497 ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session);
498
499out:
500 return ret;
501}
502
503static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *info)
504{
505 int ret = 0;
506 struct l2tp_session *session;
507
508 session = l2tp_nl_session_find(info);
509 if (session == NULL) {
510 ret = -ENODEV;
511 goto out;
512 }
513
514 if (info->attrs[L2TP_ATTR_DEBUG])
515 session->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
516
517 if (info->attrs[L2TP_ATTR_DATA_SEQ])
518 session->data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]);
519
520 if (info->attrs[L2TP_ATTR_RECV_SEQ])
521 session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
522
523 if (info->attrs[L2TP_ATTR_SEND_SEQ])
524 session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
525
526 if (info->attrs[L2TP_ATTR_LNS_MODE])
527 session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
528
529 if (info->attrs[L2TP_ATTR_RECV_TIMEOUT])
530 session->reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]);
531
532 if (info->attrs[L2TP_ATTR_MTU])
533 session->mtu = nla_get_u16(info->attrs[L2TP_ATTR_MTU]);
534
535 if (info->attrs[L2TP_ATTR_MRU])
536 session->mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]);
537
538out:
539 return ret;
540}
541
542static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags,
543 struct l2tp_session *session)
544{
545 void *hdr;
546 struct nlattr *nest;
547 struct l2tp_tunnel *tunnel = session->tunnel;
548 struct sock *sk = NULL;
549
550 sk = tunnel->sock;
551
552 hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET);
553 if (IS_ERR(hdr))
554 return PTR_ERR(hdr);
555
556 NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id);
557 NLA_PUT_U32(skb, L2TP_ATTR_SESSION_ID, session->session_id);
558 NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id);
559 NLA_PUT_U32(skb, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id);
560 NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, session->debug);
561 NLA_PUT_U16(skb, L2TP_ATTR_PW_TYPE, session->pwtype);
562 NLA_PUT_U16(skb, L2TP_ATTR_MTU, session->mtu);
563 if (session->mru)
564 NLA_PUT_U16(skb, L2TP_ATTR_MRU, session->mru);
565
566 if (session->ifname && session->ifname[0])
567 NLA_PUT_STRING(skb, L2TP_ATTR_IFNAME, session->ifname);
568 if (session->cookie_len)
569 NLA_PUT(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0]);
570 if (session->peer_cookie_len)
571 NLA_PUT(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, &session->peer_cookie[0]);
572 NLA_PUT_U8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq);
573 NLA_PUT_U8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq);
574 NLA_PUT_U8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode);
575#ifdef CONFIG_XFRM
576 if ((sk) && (sk->sk_policy[0] || sk->sk_policy[1]))
577 NLA_PUT_U8(skb, L2TP_ATTR_USING_IPSEC, 1);
578#endif
579 if (session->reorder_timeout)
580 NLA_PUT_MSECS(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout);
581
582 nest = nla_nest_start(skb, L2TP_ATTR_STATS);
583 if (nest == NULL)
584 goto nla_put_failure;
585 NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, session->stats.tx_packets);
586 NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, session->stats.tx_bytes);
587 NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, session->stats.tx_errors);
588 NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, session->stats.rx_packets);
589 NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, session->stats.rx_bytes);
590 NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, session->stats.rx_seq_discards);
591 NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, session->stats.rx_oos_packets);
592 NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, session->stats.rx_errors);
593 nla_nest_end(skb, nest);
594
595 return genlmsg_end(skb, hdr);
596
597 nla_put_failure:
598 genlmsg_cancel(skb, hdr);
599 return -1;
600}
601
602static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)
603{
604 struct l2tp_session *session;
605 struct sk_buff *msg;
606 int ret;
607
608 session = l2tp_nl_session_find(info);
609 if (session == NULL) {
610 ret = -ENODEV;
611 goto out;
612 }
613
614 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
615 if (!msg) {
616 ret = -ENOMEM;
617 goto out;
618 }
619
620 ret = l2tp_nl_session_send(msg, info->snd_pid, info->snd_seq,
621 0, session);
622 if (ret < 0)
623 goto err_out;
624
625 return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
626
627err_out:
628 nlmsg_free(msg);
629
630out:
631 return ret;
632}
633
634static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback *cb)
635{
636 struct net *net = sock_net(skb->sk);
637 struct l2tp_session *session;
638 struct l2tp_tunnel *tunnel = NULL;
639 int ti = cb->args[0];
640 int si = cb->args[1];
641
642 for (;;) {
643 if (tunnel == NULL) {
644 tunnel = l2tp_tunnel_find_nth(net, ti);
645 if (tunnel == NULL)
646 goto out;
647 }
648
649 session = l2tp_session_find_nth(tunnel, si);
650 if (session == NULL) {
651 ti++;
652 tunnel = NULL;
653 si = 0;
654 continue;
655 }
656
657 if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).pid,
658 cb->nlh->nlmsg_seq, NLM_F_MULTI,
659 session) <= 0)
660 break;
661
662 si++;
663 }
664
665out:
666 cb->args[0] = ti;
667 cb->args[1] = si;
668
669 return skb->len;
670}
671
672static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {
673 [L2TP_ATTR_NONE] = { .type = NLA_UNSPEC, },
674 [L2TP_ATTR_PW_TYPE] = { .type = NLA_U16, },
675 [L2TP_ATTR_ENCAP_TYPE] = { .type = NLA_U16, },
676 [L2TP_ATTR_OFFSET] = { .type = NLA_U16, },
677 [L2TP_ATTR_DATA_SEQ] = { .type = NLA_U8, },
678 [L2TP_ATTR_L2SPEC_TYPE] = { .type = NLA_U8, },
679 [L2TP_ATTR_L2SPEC_LEN] = { .type = NLA_U8, },
680 [L2TP_ATTR_PROTO_VERSION] = { .type = NLA_U8, },
681 [L2TP_ATTR_CONN_ID] = { .type = NLA_U32, },
682 [L2TP_ATTR_PEER_CONN_ID] = { .type = NLA_U32, },
683 [L2TP_ATTR_SESSION_ID] = { .type = NLA_U32, },
684 [L2TP_ATTR_PEER_SESSION_ID] = { .type = NLA_U32, },
685 [L2TP_ATTR_UDP_CSUM] = { .type = NLA_U8, },
686 [L2TP_ATTR_VLAN_ID] = { .type = NLA_U16, },
687 [L2TP_ATTR_DEBUG] = { .type = NLA_U32, },
688 [L2TP_ATTR_RECV_SEQ] = { .type = NLA_U8, },
689 [L2TP_ATTR_SEND_SEQ] = { .type = NLA_U8, },
690 [L2TP_ATTR_LNS_MODE] = { .type = NLA_U8, },
691 [L2TP_ATTR_USING_IPSEC] = { .type = NLA_U8, },
692 [L2TP_ATTR_RECV_TIMEOUT] = { .type = NLA_MSECS, },
693 [L2TP_ATTR_FD] = { .type = NLA_U32, },
694 [L2TP_ATTR_IP_SADDR] = { .type = NLA_U32, },
695 [L2TP_ATTR_IP_DADDR] = { .type = NLA_U32, },
696 [L2TP_ATTR_UDP_SPORT] = { .type = NLA_U16, },
697 [L2TP_ATTR_UDP_DPORT] = { .type = NLA_U16, },
698 [L2TP_ATTR_MTU] = { .type = NLA_U16, },
699 [L2TP_ATTR_MRU] = { .type = NLA_U16, },
700 [L2TP_ATTR_STATS] = { .type = NLA_NESTED, },
701 [L2TP_ATTR_IFNAME] = {
702 .type = NLA_NUL_STRING,
703 .len = IFNAMSIZ - 1,
704 },
705 [L2TP_ATTR_COOKIE] = {
706 .type = NLA_BINARY,
707 .len = 8,
708 },
709 [L2TP_ATTR_PEER_COOKIE] = {
710 .type = NLA_BINARY,
711 .len = 8,
712 },
713};
714
715static struct genl_ops l2tp_nl_ops[] = {
716 {
717 .cmd = L2TP_CMD_NOOP,
718 .doit = l2tp_nl_cmd_noop,
719 .policy = l2tp_nl_policy,
720 /* can be retrieved by unprivileged users */
721 },
722 {
723 .cmd = L2TP_CMD_TUNNEL_CREATE,
724 .doit = l2tp_nl_cmd_tunnel_create,
725 .policy = l2tp_nl_policy,
726 .flags = GENL_ADMIN_PERM,
727 },
728 {
729 .cmd = L2TP_CMD_TUNNEL_DELETE,
730 .doit = l2tp_nl_cmd_tunnel_delete,
731 .policy = l2tp_nl_policy,
732 .flags = GENL_ADMIN_PERM,
733 },
734 {
735 .cmd = L2TP_CMD_TUNNEL_MODIFY,
736 .doit = l2tp_nl_cmd_tunnel_modify,
737 .policy = l2tp_nl_policy,
738 .flags = GENL_ADMIN_PERM,
739 },
740 {
741 .cmd = L2TP_CMD_TUNNEL_GET,
742 .doit = l2tp_nl_cmd_tunnel_get,
743 .dumpit = l2tp_nl_cmd_tunnel_dump,
744 .policy = l2tp_nl_policy,
745 .flags = GENL_ADMIN_PERM,
746 },
747 {
748 .cmd = L2TP_CMD_SESSION_CREATE,
749 .doit = l2tp_nl_cmd_session_create,
750 .policy = l2tp_nl_policy,
751 .flags = GENL_ADMIN_PERM,
752 },
753 {
754 .cmd = L2TP_CMD_SESSION_DELETE,
755 .doit = l2tp_nl_cmd_session_delete,
756 .policy = l2tp_nl_policy,
757 .flags = GENL_ADMIN_PERM,
758 },
759 {
760 .cmd = L2TP_CMD_SESSION_MODIFY,
761 .doit = l2tp_nl_cmd_session_modify,
762 .policy = l2tp_nl_policy,
763 .flags = GENL_ADMIN_PERM,
764 },
765 {
766 .cmd = L2TP_CMD_SESSION_GET,
767 .doit = l2tp_nl_cmd_session_get,
768 .dumpit = l2tp_nl_cmd_session_dump,
769 .policy = l2tp_nl_policy,
770 .flags = GENL_ADMIN_PERM,
771 },
772};
773
774int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops)
775{
776 int ret;
777
778 ret = -EINVAL;
779 if (pw_type >= __L2TP_PWTYPE_MAX)
780 goto err;
781
782 genl_lock();
783 ret = -EBUSY;
784 if (l2tp_nl_cmd_ops[pw_type])
785 goto out;
786
787 l2tp_nl_cmd_ops[pw_type] = ops;
788
789out:
790 genl_unlock();
791err:
792 return 0;
793}
794EXPORT_SYMBOL_GPL(l2tp_nl_register_ops);
795
796void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type)
797{
798 if (pw_type < __L2TP_PWTYPE_MAX) {
799 genl_lock();
800 l2tp_nl_cmd_ops[pw_type] = NULL;
801 genl_unlock();
802 }
803}
804EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);
805
806static int l2tp_nl_init(void)
807{
808 int err;
809
810 printk(KERN_INFO "L2TP netlink interface\n");
811 err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops,
812 ARRAY_SIZE(l2tp_nl_ops));
813
814 return err;
815}
816
817static void l2tp_nl_cleanup(void)
818{
819 genl_unregister_family(&l2tp_nl_family);
820}
821
822module_init(l2tp_nl_init);
823module_exit(l2tp_nl_cleanup);
824
825MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
826MODULE_DESCRIPTION("L2TP netlink");
827MODULE_LICENSE("GPL");
828MODULE_VERSION("1.0");
829MODULE_ALIAS("net-pf-" __stringify(PF_NETLINK) "-proto-" \
830 __stringify(NETLINK_GENERIC) "-type-" "l2tp")