Blame view
net/l2tp/l2tp_ppp.c
46.8 KB
fd558d186 l2tp: Split pppol... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/***************************************************************************** * Linux PPP over L2TP (PPPoX/PPPoL2TP) Sockets * * PPPoX --- Generic PPP encapsulation socket family * PPPoL2TP --- PPP over L2TP (RFC 2661) * * Version: 2.0.0 * * Authors: James Chapman (jchapman@katalix.com) * * Based on original work by Martijn van Oosterhout <kleptog@svana.org> * * License: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ /* This driver handles only L2TP data frames; control frames are handled by a * userspace application. * * To send data in an L2TP session, userspace opens a PPPoL2TP socket and * attaches it to a bound UDP socket with local tunnel_id / session_id and * peer tunnel_id / session_id set. Data can then be sent or received using * regular socket sendmsg() / recvmsg() calls. Kernel parameters of the socket * can be read or modified using ioctl() or [gs]etsockopt() calls. * * When a PPPoL2TP socket is connected with local and peer session_id values * zero, the socket is treated as a special tunnel management socket. * * Here's example userspace code to create a socket for sending/receiving data * over an L2TP session:- * * struct sockaddr_pppol2tp sax; * int fd; * int session_fd; * * fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); * * sax.sa_family = AF_PPPOX; * sax.sa_protocol = PX_PROTO_OL2TP; * sax.pppol2tp.fd = tunnel_fd; // bound UDP socket * sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr; * sax.pppol2tp.addr.sin_port = addr->sin_port; * sax.pppol2tp.addr.sin_family = AF_INET; * sax.pppol2tp.s_tunnel = tunnel_id; * sax.pppol2tp.s_session = session_id; * sax.pppol2tp.d_tunnel = peer_tunnel_id; * sax.pppol2tp.d_session = peer_session_id; * * session_fd = connect(fd, (struct sockaddr *)&sax, sizeof(sax)); * * A pppd plugin that allows PPP traffic to be carried over L2TP using * this driver is available from the OpenL2TP project at * http://openl2tp.sourceforge.net. */ |
a4ca44fa5 net: l2tp: Standa... |
59 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
fd558d186 l2tp: Split pppol... |
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#include <linux/module.h> #include <linux/string.h> #include <linux/list.h> #include <linux/uaccess.h> #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/kthread.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/jiffies.h> #include <linux/netdevice.h> #include <linux/net.h> #include <linux/inetdevice.h> #include <linux/skbuff.h> #include <linux/init.h> #include <linux/ip.h> #include <linux/udp.h> #include <linux/if_pppox.h> #include <linux/if_pppol2tp.h> #include <net/sock.h> #include <linux/ppp_channel.h> #include <linux/ppp_defs.h> |
4b32da2bc ppp: Replace uses... |
85 |
#include <linux/ppp-ioctl.h> |
fd558d186 l2tp: Split pppol... |
86 87 88 89 |
#include <linux/file.h> #include <linux/hash.h> #include <linux/sort.h> #include <linux/proc_fs.h> |
309795f4b l2tp: Add netlink... |
90 |
#include <linux/l2tp.h> |
fd558d186 l2tp: Split pppol... |
91 92 93 94 95 96 97 |
#include <linux/nsproxy.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #include <net/dst.h> #include <net/ip.h> #include <net/udp.h> #include <net/xfrm.h> |
cf2f5c886 l2tp: push all pp... |
98 |
#include <net/inet_common.h> |
fd558d186 l2tp: Split pppol... |
99 100 |
#include <asm/byteorder.h> |
60063497a atomic: use <linu... |
101 |
#include <linux/atomic.h> |
fd558d186 l2tp: Split pppol... |
102 103 104 105 106 107 108 |
#include "l2tp_core.h" #define PPPOL2TP_DRV_VERSION "V2.0" /* Space for UDP, L2TP and PPP headers */ #define PPPOL2TP_HEADER_OVERHEAD 40 |
fd558d186 l2tp: Split pppol... |
109 110 111 112 113 114 115 116 117 118 119 120 |
/* Number of bytes to build transmit L2TP headers. * Unfortunately the size is different depending on whether sequence numbers * are enabled. */ #define PPPOL2TP_L2TP_HDR_SIZE_SEQ 10 #define PPPOL2TP_L2TP_HDR_SIZE_NOSEQ 6 /* Private data of each session. This data lives at the end of struct * l2tp_session, referenced via session->priv[]. */ struct pppol2tp_session { int owner; /* pid that opened the socket */ |
ee40fb2e1 l2tp: protect soc... |
121 122 |
struct mutex sk_lock; /* Protects .sk */ struct sock __rcu *sk; /* Pointer to the session |
fd558d186 l2tp: Split pppol... |
123 |
* PPPoX socket */ |
ee40fb2e1 l2tp: protect soc... |
124 125 |
struct sock *__sk; /* Copy of .sk, for cleanup */ struct rcu_head rcu; /* For asynchronous release */ |
fd558d186 l2tp: Split pppol... |
126 127 128 129 130 |
int flags; /* accessed by PPPIOCGFLAGS. * Unused. */ }; static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb); |
d7100da02 ppp: make channel... |
131 132 133 |
static const struct ppp_channel_ops pppol2tp_chan_ops = { .start_xmit = pppol2tp_xmit, }; |
fd558d186 l2tp: Split pppol... |
134 |
static const struct proto_ops pppol2tp_ops; |
ee40fb2e1 l2tp: protect soc... |
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
/* Retrieves the pppol2tp socket associated to a session. * A reference is held on the returned socket, so this function must be paired * with sock_put(). */ static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session) { struct pppol2tp_session *ps = l2tp_session_priv(session); struct sock *sk; rcu_read_lock(); sk = rcu_dereference(ps->sk); if (sk) sock_hold(sk); rcu_read_unlock(); return sk; } |
fd558d186 l2tp: Split pppol... |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
/* Helpers to obtain tunnel/session contexts from sockets. */ static inline struct l2tp_session *pppol2tp_sock_to_session(struct sock *sk) { struct l2tp_session *session; if (sk == NULL) return NULL; sock_hold(sk); session = (struct l2tp_session *)(sk->sk_user_data); if (session == NULL) { sock_put(sk); goto out; } BUG_ON(session->magic != L2TP_SESSION_MAGIC); out: return session; } /***************************************************************************** * Receive data handling *****************************************************************************/ static int pppol2tp_recv_payload_hook(struct sk_buff *skb) { /* Skip PPP header, if present. In testing, Microsoft L2TP clients * don't send the PPP header (PPP header compression enabled), but * other clients can include the header. So we cope with both cases * here. The PPP header is always FF03 when using L2TP. * * Note that skb->data[] isn't dereferenced from a u16 ptr here since * the field may be unaligned. */ if (!pskb_may_pull(skb, 2)) return 1; |
54c151d9e l2tp: Refactor th... |
190 |
if ((skb->data[0] == PPP_ALLSTATIONS) && (skb->data[1] == PPP_UI)) |
fd558d186 l2tp: Split pppol... |
191 192 193 194 195 196 197 |
skb_pull(skb, 2); return 0; } /* Receive message. This is the recvmsg for the PPPoL2TP socket. */ |
1b7841404 net: Remove iocb ... |
198 199 |
static int pppol2tp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) |
fd558d186 l2tp: Split pppol... |
200 201 202 203 204 205 206 207 |
{ int err; struct sk_buff *skb; struct sock *sk = sock->sk; err = -EIO; if (sk->sk_state & PPPOX_BOUND) goto end; |
fd558d186 l2tp: Split pppol... |
208 209 210 211 212 213 214 215 216 217 |
err = 0; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); if (!skb) goto end; if (len > skb->len) len = skb->len; else if (len < skb->len) msg->msg_flags |= MSG_TRUNC; |
51f3d02b9 net: Add and use ... |
218 |
err = skb_copy_datagram_msg(skb, 0, msg, len); |
fd558d186 l2tp: Split pppol... |
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
if (likely(err == 0)) err = len; kfree_skb(skb); end: return err; } static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len) { struct pppol2tp_session *ps = l2tp_session_priv(session); struct sock *sk = NULL; /* If the socket is bound, send it in to PPP's input queue. Otherwise * queue it on the session socket. */ |
ee40fb2e1 l2tp: protect soc... |
235 236 |
rcu_read_lock(); sk = rcu_dereference(ps->sk); |
fd558d186 l2tp: Split pppol... |
237 238 239 240 241 |
if (sk == NULL) goto no_sock; if (sk->sk_state & PPPOX_BOUND) { struct pppox_sock *po; |
98f40b3e2 l2tp: rely on ppp... |
242 |
|
fba40c632 net: l2tp: ppp: c... |
243 |
l2tp_dbg(session, L2TP_MSG_DATA, |
a4ca44fa5 net: l2tp: Standa... |
244 245 246 |
"%s: recv %d byte data frame, passing to ppp ", session->name, data_len); |
fd558d186 l2tp: Split pppol... |
247 |
|
fd558d186 l2tp: Split pppol... |
248 249 250 |
po = pppox_sk(sk); ppp_input(&po->chan, skb); } else { |
fba40c632 net: l2tp: ppp: c... |
251 |
l2tp_dbg(session, L2TP_MSG_DATA, |
9e9cb6221 l2tp: fix userspa... |
252 253 254 |
"%s: recv %d byte data frame, passing to L2TP socket ", session->name, data_len); |
fd558d186 l2tp: Split pppol... |
255 |
|
9e9cb6221 l2tp: fix userspa... |
256 257 258 259 |
if (sock_queue_rcv_skb(sk, skb) < 0) { atomic_long_inc(&session->stats.rx_errors); kfree_skb(skb); } |
fd558d186 l2tp: Split pppol... |
260 |
} |
ee40fb2e1 l2tp: protect soc... |
261 |
rcu_read_unlock(); |
fd558d186 l2tp: Split pppol... |
262 263 264 265 |
return; no_sock: |
ee40fb2e1 l2tp: protect soc... |
266 |
rcu_read_unlock(); |
fba40c632 net: l2tp: ppp: c... |
267 268 |
l2tp_info(session, L2TP_MSG_DATA, "%s: no socket ", session->name); |
fd558d186 l2tp: Split pppol... |
269 270 |
kfree_skb(skb); } |
fd558d186 l2tp: Split pppol... |
271 272 273 |
/************************************************************************ * Transmit handling ***********************************************************************/ |
fd558d186 l2tp: Split pppol... |
274 275 276 277 |
/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here * when a user application does a sendmsg() on the session socket. L2TP and * PPP headers must be inserted into the user's data. */ |
1b7841404 net: Remove iocb ... |
278 |
static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, |
fd558d186 l2tp: Split pppol... |
279 280 |
size_t total_len) { |
fd558d186 l2tp: Split pppol... |
281 282 283 284 285 |
struct sock *sk = sock->sk; struct sk_buff *skb; int error; struct l2tp_session *session; struct l2tp_tunnel *tunnel; |
0d76751fa l2tp: Add L2TPv3 ... |
286 |
int uhlen; |
fd558d186 l2tp: Split pppol... |
287 288 289 290 291 292 293 294 295 296 |
error = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) goto error; /* Get session and tunnel contexts */ error = -EBADF; session = pppol2tp_sock_to_session(sk); if (session == NULL) goto error; |
7198c77aa l2tp: avoid using... |
297 |
tunnel = session->tunnel; |
fd558d186 l2tp: Split pppol... |
298 |
|
0d76751fa l2tp: Add L2TPv3 ... |
299 |
uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; |
fd558d186 l2tp: Split pppol... |
300 301 302 |
/* Allocate a socket buffer */ error = -ENOMEM; skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) + |
0d76751fa l2tp: Add L2TPv3 ... |
303 |
uhlen + session->hdr_len + |
54c151d9e l2tp: Refactor th... |
304 |
2 + total_len, /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */ |
fd558d186 l2tp: Split pppol... |
305 306 |
0, GFP_KERNEL); if (!skb) |
7198c77aa l2tp: avoid using... |
307 |
goto error_put_sess; |
fd558d186 l2tp: Split pppol... |
308 309 310 311 312 313 |
/* Reserve space for headers. */ skb_reserve(skb, NET_SKB_PAD); skb_reset_network_header(skb); skb_reserve(skb, sizeof(struct iphdr)); skb_reset_transport_header(skb); |
0d76751fa l2tp: Add L2TPv3 ... |
314 |
skb_reserve(skb, uhlen); |
fd558d186 l2tp: Split pppol... |
315 316 |
/* Add PPP header */ |
54c151d9e l2tp: Refactor th... |
317 318 |
skb->data[0] = PPP_ALLSTATIONS; skb->data[1] = PPP_UI; |
fd558d186 l2tp: Split pppol... |
319 320 321 |
skb_put(skb, 2); /* Copy user data into skb */ |
6ce8e9ce5 new helper: memcp... |
322 |
error = memcpy_from_msg(skb_put(skb, total_len), m, total_len); |
fd558d186 l2tp: Split pppol... |
323 324 |
if (error < 0) { kfree_skb(skb); |
7198c77aa l2tp: avoid using... |
325 |
goto error_put_sess; |
fd558d186 l2tp: Split pppol... |
326 |
} |
fd558d186 l2tp: Split pppol... |
327 |
|
455cc32bf l2tp: must disabl... |
328 |
local_bh_disable(); |
fd558d186 l2tp: Split pppol... |
329 |
l2tp_xmit_skb(session, skb, session->hdr_len); |
455cc32bf l2tp: must disabl... |
330 |
local_bh_enable(); |
fd558d186 l2tp: Split pppol... |
331 |
|
8b82547e3 l2tp: Restore soc... |
332 |
sock_put(sk); |
fd558d186 l2tp: Split pppol... |
333 |
|
a6f79d0f2 l2tp: Fix sendmsg... |
334 |
return total_len; |
fd558d186 l2tp: Split pppol... |
335 |
|
fd558d186 l2tp: Split pppol... |
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
error_put_sess: sock_put(sk); error: return error; } /* Transmit function called by generic PPP driver. Sends PPP frame * over PPPoL2TP socket. * * This is almost the same as pppol2tp_sendmsg(), but rather than * being called with a msghdr from userspace, it is called with a skb * from the kernel. * * The supplied skb from ppp doesn't have enough headroom for the * insertion of L2TP, UDP and IP headers so we need to allocate more * headroom in the skb. This will create a cloned skb. But we must be * careful in the error case because the caller will expect to free * the skb it supplied, not our cloned skb. So we take care to always * leave the original skb unfreed if we return an error. */ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) { |
fd558d186 l2tp: Split pppol... |
358 |
struct sock *sk = (struct sock *) chan->private; |
fd558d186 l2tp: Split pppol... |
359 360 |
struct l2tp_session *session; struct l2tp_tunnel *tunnel; |
09df57ca6 l2tp: give proper... |
361 |
int uhlen, headroom; |
fd558d186 l2tp: Split pppol... |
362 363 364 365 366 367 368 369 |
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) goto abort; /* Get session and tunnel contexts from the socket */ session = pppol2tp_sock_to_session(sk); if (session == NULL) goto abort; |
7198c77aa l2tp: avoid using... |
370 |
tunnel = session->tunnel; |
fd558d186 l2tp: Split pppol... |
371 |
|
09df57ca6 l2tp: give proper... |
372 373 374 375 376 |
uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; headroom = NET_SKB_PAD + sizeof(struct iphdr) + /* IP header */ uhlen + /* UDP header (if L2TP_ENCAPTYPE_UDP) */ session->hdr_len + /* L2TP header */ |
54c151d9e l2tp: Refactor th... |
377 |
2; /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */ |
09df57ca6 l2tp: give proper... |
378 |
if (skb_cow_head(skb, headroom)) |
7198c77aa l2tp: avoid using... |
379 |
goto abort_put_sess; |
fd558d186 l2tp: Split pppol... |
380 |
|
fd558d186 l2tp: Split pppol... |
381 |
/* Setup PPP header */ |
54c151d9e l2tp: Refactor th... |
382 383 384 |
__skb_push(skb, 2); skb->data[0] = PPP_ALLSTATIONS; skb->data[1] = PPP_UI; |
fd558d186 l2tp: Split pppol... |
385 |
|
455cc32bf l2tp: must disabl... |
386 |
local_bh_disable(); |
e0d4435f9 l2tp: Update PPP-... |
387 |
l2tp_xmit_skb(session, skb, session->hdr_len); |
455cc32bf l2tp: must disabl... |
388 |
local_bh_enable(); |
fd558d186 l2tp: Split pppol... |
389 |
|
fd558d186 l2tp: Split pppol... |
390 |
sock_put(sk); |
7198c77aa l2tp: avoid using... |
391 |
|
fd558d186 l2tp: Split pppol... |
392 |
return 1; |
fd558d186 l2tp: Split pppol... |
393 394 395 396 397 398 399 400 401 402 403 |
abort_put_sess: sock_put(sk); abort: /* Free the original skb */ kfree_skb(skb); return 1; } /***************************************************************************** * Session (and tunnel control) socket create/destroy. *****************************************************************************/ |
d02ba2a61 l2tp: fix race in... |
404 405 406 407 408 409 410 |
static void pppol2tp_put_sk(struct rcu_head *head) { struct pppol2tp_session *ps; ps = container_of(head, typeof(*ps), rcu); sock_put(ps->__sk); } |
fd558d186 l2tp: Split pppol... |
411 412 413 414 |
/* Called by l2tp_core when a session socket is being closed. */ static void pppol2tp_session_close(struct l2tp_session *session) { |
fd558d186 l2tp: Split pppol... |
415 416 417 418 419 420 421 |
} /* Really kill the session socket. (Called from sock_put() if * refcnt == 0.) */ static void pppol2tp_session_destruct(struct sock *sk) { |
f6e16b299 l2tp: unhash l2tp... |
422 |
struct l2tp_session *session = sk->sk_user_data; |
e91793bb6 l2tp: purge socke... |
423 424 425 |
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_write_queue); |
f6e16b299 l2tp: unhash l2tp... |
426 |
if (session) { |
fd558d186 l2tp: Split pppol... |
427 428 429 430 |
sk->sk_user_data = NULL; BUG_ON(session->magic != L2TP_SESSION_MAGIC); l2tp_session_dec_refcount(session); } |
fd558d186 l2tp: Split pppol... |
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
} /* Called when the PPPoX socket (session) is closed. */ static int pppol2tp_release(struct socket *sock) { struct sock *sk = sock->sk; struct l2tp_session *session; int error; if (!sk) return 0; error = -EBADF; lock_sock(sk); if (sock_flag(sk, SOCK_DEAD) != 0) goto error; pppox_unbind_sock(sk); /* Signal the death of the socket. */ sk->sk_state = PPPOX_DEAD; sock_orphan(sk); sock->sk = NULL; session = pppol2tp_sock_to_session(sk); |
d02ba2a61 l2tp: fix race in... |
457 |
if (session) { |
3d609342c l2tp: fix refcoun... |
458 |
struct pppol2tp_session *ps; |
f98be6c63 l2tp: initialise ... |
459 |
l2tp_session_delete(session); |
3d609342c l2tp: fix refcoun... |
460 461 462 463 464 465 466 467 468 469 470 471 472 |
ps = l2tp_session_priv(session); mutex_lock(&ps->sk_lock); ps->__sk = rcu_dereference_protected(ps->sk, lockdep_is_held(&ps->sk_lock)); RCU_INIT_POINTER(ps->sk, NULL); mutex_unlock(&ps->sk_lock); call_rcu(&ps->rcu, pppol2tp_put_sk); /* Rely on the sock_put() call at the end of the function for * dropping the reference held by pppol2tp_sock_to_session(). * The last reference will be dropped by pppol2tp_put_sk(). */ |
fd558d186 l2tp: Split pppol... |
473 |
} |
d02ba2a61 l2tp: fix race in... |
474 |
|
fd558d186 l2tp: Split pppol... |
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
release_sock(sk); /* This will delete the session context via * pppol2tp_session_destruct() if the socket's refcnt drops to * zero. */ sock_put(sk); return 0; error: release_sock(sk); return error; } static struct proto pppol2tp_sk_proto = { .name = "PPPOL2TP", .owner = THIS_MODULE, .obj_size = sizeof(struct pppox_sock), }; static int pppol2tp_backlog_recv(struct sock *sk, struct sk_buff *skb) { int rc; rc = l2tp_udp_encap_recv(sk, skb); if (rc) kfree_skb(skb); return NET_RX_SUCCESS; } /* socket() handler. Initialize a new struct sock. */ |
11aa9c28b net: Pass kern fr... |
509 |
static int pppol2tp_create(struct net *net, struct socket *sock, int kern) |
fd558d186 l2tp: Split pppol... |
510 511 512 |
{ int error = -ENOMEM; struct sock *sk; |
11aa9c28b net: Pass kern fr... |
513 |
sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, kern); |
fd558d186 l2tp: Split pppol... |
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
if (!sk) goto out; sock_init_data(sock, sk); sock->state = SS_UNCONNECTED; sock->ops = &pppol2tp_ops; sk->sk_backlog_rcv = pppol2tp_backlog_recv; sk->sk_protocol = PX_PROTO_OL2TP; sk->sk_family = PF_PPPOX; sk->sk_state = PPPOX_NONE; sk->sk_type = SOCK_STREAM; sk->sk_destruct = pppol2tp_session_destruct; error = 0; out: return error; } |
9dd79945b l2tp: use IS_ENAB... |
534 |
#if IS_ENABLED(CONFIG_L2TP_DEBUGFS) |
0ad661404 l2tp: Add debugfs... |
535 536 537 |
static void pppol2tp_show(struct seq_file *m, void *arg) { struct l2tp_session *session = arg; |
ee40fb2e1 l2tp: protect soc... |
538 539 540 541 542 |
struct sock *sk; sk = pppol2tp_session_get_sock(session); if (sk) { struct pppox_sock *po = pppox_sk(sk); |
0ad661404 l2tp: Add debugfs... |
543 |
|
ee40fb2e1 l2tp: protect soc... |
544 545 546 |
seq_printf(m, " interface %s ", ppp_dev_name(&po->chan)); sock_put(sk); |
0ad661404 l2tp: Add debugfs... |
547 548 549 |
} } #endif |
f98be6c63 l2tp: initialise ... |
550 551 552 553 554 555 556 557 558 559 560 561 562 |
static void pppol2tp_session_init(struct l2tp_session *session) { struct pppol2tp_session *ps; struct dst_entry *dst; session->recv_skb = pppol2tp_recv; session->session_close = pppol2tp_session_close; #if IS_ENABLED(CONFIG_L2TP_DEBUGFS) session->show = pppol2tp_show; #endif ps = l2tp_session_priv(session); mutex_init(&ps->sk_lock); |
f98be6c63 l2tp: initialise ... |
563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
ps->owner = current->pid; /* If PMTU discovery was enabled, use the MTU that was discovered */ dst = sk_dst_get(session->tunnel->sock); if (dst) { u32 pmtu = dst_mtu(dst); if (pmtu) { session->mtu = pmtu - PPPOL2TP_HEADER_OVERHEAD; session->mru = pmtu - PPPOL2TP_HEADER_OVERHEAD; } dst_release(dst); } } |
fd558d186 l2tp: Split pppol... |
577 578 579 580 581 582 583 584 585 586 587 |
/* connect() handler. Attach a PPPoX socket to a tunnel UDP socket */ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len, int flags) { struct sock *sk = sock->sk; struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr; struct pppox_sock *po = pppox_sk(sk); struct l2tp_session *session = NULL; struct l2tp_tunnel *tunnel; struct pppol2tp_session *ps; |
fd558d186 l2tp: Split pppol... |
588 589 |
struct l2tp_session_cfg cfg = { 0, }; int error = 0; |
e0d4435f9 l2tp: Update PPP-... |
590 591 |
u32 tunnel_id, peer_tunnel_id; u32 session_id, peer_session_id; |
dbdbc73b4 l2tp: fix duplica... |
592 |
bool drop_refcnt = false; |
f9e56baf0 l2tp: hold tunnel... |
593 |
bool drop_tunnel = false; |
e0d4435f9 l2tp: Update PPP-... |
594 595 |
int ver = 2; int fd; |
fd558d186 l2tp: Split pppol... |
596 597 598 599 |
lock_sock(sk); error = -EINVAL; |
eb1c28c05 l2tp: check socka... |
600 601 602 603 604 605 |
if (sockaddr_len != sizeof(struct sockaddr_pppol2tp) && sockaddr_len != sizeof(struct sockaddr_pppol2tpv3) && sockaddr_len != sizeof(struct sockaddr_pppol2tpin6) && sockaddr_len != sizeof(struct sockaddr_pppol2tpv3in6)) goto end; |
fd558d186 l2tp: Split pppol... |
606 607 608 609 610 611 612 613 614 615 616 617 |
if (sp->sa_protocol != PX_PROTO_OL2TP) goto end; /* Check for already bound sockets */ error = -EBUSY; if (sk->sk_state & PPPOX_CONNECTED) goto end; /* We don't supporting rebinding anyway */ error = -EALREADY; if (sk->sk_user_data) goto end; /* socket is already attached */ |
b79585f53 l2tp: pppol2tp_co... |
618 619 620 621 622 623 624 |
/* Get params from socket address. Handle L2TPv2 and L2TPv3. * This is nasty because there are different sockaddr_pppol2tp * structs for L2TPv2, L2TPv3, over IPv4 and IPv6. We use * the sockaddr size to determine which structure the caller * is using. */ peer_tunnel_id = 0; |
e0d4435f9 l2tp: Update PPP-... |
625 626 627 628 629 630 631 |
if (sockaddr_len == sizeof(struct sockaddr_pppol2tp)) { fd = sp->pppol2tp.fd; tunnel_id = sp->pppol2tp.s_tunnel; peer_tunnel_id = sp->pppol2tp.d_tunnel; session_id = sp->pppol2tp.s_session; peer_session_id = sp->pppol2tp.d_session; } else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3)) { |
b79585f53 l2tp: pppol2tp_co... |
632 633 |
struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) sp; |
e0d4435f9 l2tp: Update PPP-... |
634 635 636 637 638 639 |
ver = 3; fd = sp3->pppol2tp.fd; tunnel_id = sp3->pppol2tp.s_tunnel; peer_tunnel_id = sp3->pppol2tp.d_tunnel; session_id = sp3->pppol2tp.s_session; peer_session_id = sp3->pppol2tp.d_session; |
b79585f53 l2tp: pppol2tp_co... |
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 |
} else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpin6)) { struct sockaddr_pppol2tpin6 *sp6 = (struct sockaddr_pppol2tpin6 *) sp; fd = sp6->pppol2tp.fd; tunnel_id = sp6->pppol2tp.s_tunnel; peer_tunnel_id = sp6->pppol2tp.d_tunnel; session_id = sp6->pppol2tp.s_session; peer_session_id = sp6->pppol2tp.d_session; } else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3in6)) { struct sockaddr_pppol2tpv3in6 *sp6 = (struct sockaddr_pppol2tpv3in6 *) sp; ver = 3; fd = sp6->pppol2tp.fd; tunnel_id = sp6->pppol2tp.s_tunnel; peer_tunnel_id = sp6->pppol2tp.d_tunnel; session_id = sp6->pppol2tp.s_session; peer_session_id = sp6->pppol2tp.d_session; |
e0d4435f9 l2tp: Update PPP-... |
657 658 659 660 661 662 |
} else { error = -EINVAL; goto end; /* bad socket address */ } /* Don't bind if tunnel_id is 0 */ |
fd558d186 l2tp: Split pppol... |
663 |
error = -EINVAL; |
e0d4435f9 l2tp: Update PPP-... |
664 |
if (tunnel_id == 0) |
fd558d186 l2tp: Split pppol... |
665 |
goto end; |
f9e56baf0 l2tp: hold tunnel... |
666 667 668 |
tunnel = l2tp_tunnel_get(sock_net(sk), tunnel_id); if (tunnel) drop_tunnel = true; |
309795f4b l2tp: Add netlink... |
669 |
|
e0d4435f9 l2tp: Update PPP-... |
670 671 |
/* Special case: create tunnel context if session_id and * peer_session_id is 0. Otherwise look up tunnel using supplied |
fd558d186 l2tp: Split pppol... |
672 673 |
* tunnel id. */ |
e0d4435f9 l2tp: Update PPP-... |
674 |
if ((session_id == 0) && (peer_session_id == 0)) { |
309795f4b l2tp: Add netlink... |
675 676 677 678 679 680 681 682 |
if (tunnel == NULL) { struct l2tp_tunnel_cfg tcfg = { .encap = L2TP_ENCAPTYPE_UDP, .debug = 0, }; error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, &tcfg, &tunnel); if (error < 0) goto end; |
6b9f34239 l2tp: fix races i... |
683 684 685 686 687 688 689 690 691 |
l2tp_tunnel_inc_refcount(tunnel); error = l2tp_tunnel_register(tunnel, sock_net(sk), &tcfg); if (error < 0) { kfree(tunnel); goto end; } drop_tunnel = true; |
309795f4b l2tp: Add netlink... |
692 |
} |
fd558d186 l2tp: Split pppol... |
693 |
} else { |
fd558d186 l2tp: Split pppol... |
694 695 696 697 698 699 700 701 702 703 704 705 |
/* Error if we can't find the tunnel */ error = -ENOENT; if (tunnel == NULL) goto end; /* Error if socket is not prepped */ if (tunnel->sock == NULL) goto end; } if (tunnel->recv_payload_hook == NULL) tunnel->recv_payload_hook = pppol2tp_recv_payload_hook; |
b79585f53 l2tp: pppol2tp_co... |
706 707 |
if (tunnel->peer_tunnel_id == 0) tunnel->peer_tunnel_id = peer_tunnel_id; |
fd558d186 l2tp: Split pppol... |
708 |
|
a4346210c l2tp: remove ->re... |
709 |
session = l2tp_session_get(sock_net(sk), tunnel, session_id); |
dbdbc73b4 l2tp: fix duplica... |
710 711 712 713 714 715 |
if (session) { drop_refcnt = true; ps = l2tp_session_priv(session); /* Using a pre-existing session is fine as long as it hasn't * been connected yet. |
309795f4b l2tp: Add netlink... |
716 |
*/ |
ee40fb2e1 l2tp: protect soc... |
717 718 |
mutex_lock(&ps->sk_lock); if (rcu_dereference_protected(ps->sk, |
3d609342c l2tp: fix refcoun... |
719 720 |
lockdep_is_held(&ps->sk_lock)) || ps->__sk) { |
ee40fb2e1 l2tp: protect soc... |
721 |
mutex_unlock(&ps->sk_lock); |
dbdbc73b4 l2tp: fix duplica... |
722 723 724 |
error = -EEXIST; goto end; } |
309795f4b l2tp: Add netlink... |
725 |
} else { |
dbdbc73b4 l2tp: fix duplica... |
726 727 728 |
/* Default MTU must allow space for UDP/L2TP/PPP headers */ cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; cfg.mru = cfg.mtu; |
309795f4b l2tp: Add netlink... |
729 |
|
dbdbc73b4 l2tp: fix duplica... |
730 731 732 733 734 |
session = l2tp_session_create(sizeof(struct pppol2tp_session), tunnel, session_id, peer_session_id, &cfg); if (IS_ERR(session)) { error = PTR_ERR(session); |
309795f4b l2tp: Add netlink... |
735 |
goto end; |
dbdbc73b4 l2tp: fix duplica... |
736 |
} |
3953ae7b2 l2tp: don't regis... |
737 |
|
f98be6c63 l2tp: initialise ... |
738 |
pppol2tp_session_init(session); |
ee40fb2e1 l2tp: protect soc... |
739 |
ps = l2tp_session_priv(session); |
3953ae7b2 l2tp: don't regis... |
740 |
l2tp_session_inc_refcount(session); |
ee40fb2e1 l2tp: protect soc... |
741 742 |
mutex_lock(&ps->sk_lock); |
3953ae7b2 l2tp: don't regis... |
743 744 |
error = l2tp_session_register(session, tunnel); if (error < 0) { |
ee40fb2e1 l2tp: protect soc... |
745 |
mutex_unlock(&ps->sk_lock); |
3953ae7b2 l2tp: don't regis... |
746 747 748 749 |
kfree(session); goto end; } drop_refcnt = true; |
fd558d186 l2tp: Split pppol... |
750 |
} |
fd558d186 l2tp: Split pppol... |
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
/* Special case: if source & dest session_id == 0x0000, this * socket is being created to manage the tunnel. Just set up * the internal context for use by ioctl() and sockopt() * handlers. */ if ((session->session_id == 0) && (session->peer_session_id == 0)) { error = 0; goto out_no_ppp; } /* The only header we need to worry about is the L2TP * header. This size is different depending on whether * sequence numbers are enabled for the data channel. */ po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; po->chan.private = sk; po->chan.ops = &pppol2tp_chan_ops; po->chan.mtu = session->mtu; error = ppp_register_net_channel(sock_net(sk), &po->chan); |
ee40fb2e1 l2tp: protect soc... |
773 774 |
if (error) { mutex_unlock(&ps->sk_lock); |
fd558d186 l2tp: Split pppol... |
775 |
goto end; |
ee40fb2e1 l2tp: protect soc... |
776 |
} |
fd558d186 l2tp: Split pppol... |
777 778 779 780 |
out_no_ppp: /* This is how we get the session context from the socket. */ sk->sk_user_data = session; |
ee40fb2e1 l2tp: protect soc... |
781 782 |
rcu_assign_pointer(ps->sk, sk); mutex_unlock(&ps->sk_lock); |
f98be6c63 l2tp: initialise ... |
783 784 785 786 787 |
/* Keep the reference we've grabbed on the session: sk doesn't expect * the session to disappear. pppol2tp_session_destruct() is responsible * for dropping it. */ drop_refcnt = false; |
fd558d186 l2tp: Split pppol... |
788 |
sk->sk_state = PPPOX_CONNECTED; |
fba40c632 net: l2tp: ppp: c... |
789 790 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: created ", |
a4ca44fa5 net: l2tp: Standa... |
791 |
session->name); |
fd558d186 l2tp: Split pppol... |
792 793 |
end: |
dbdbc73b4 l2tp: fix duplica... |
794 795 |
if (drop_refcnt) l2tp_session_dec_refcount(session); |
f9e56baf0 l2tp: hold tunnel... |
796 797 |
if (drop_tunnel) l2tp_tunnel_dec_refcount(tunnel); |
fd558d186 l2tp: Split pppol... |
798 799 800 801 |
release_sock(sk); return error; } |
309795f4b l2tp: Add netlink... |
802 |
#ifdef CONFIG_L2TP_V3 |
f026bc29a l2tp: pass tunnel... |
803 804 805 806 |
/* Called when creating sessions via the netlink interface. */ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) |
309795f4b l2tp: Add netlink... |
807 808 |
{ int error; |
309795f4b l2tp: Add netlink... |
809 |
struct l2tp_session *session; |
309795f4b l2tp: Add netlink... |
810 |
|
309795f4b l2tp: Add netlink... |
811 |
/* Error if tunnel socket is not prepped */ |
f026bc29a l2tp: pass tunnel... |
812 813 |
if (!tunnel->sock) { error = -ENOENT; |
3953ae7b2 l2tp: don't regis... |
814 |
goto err; |
f026bc29a l2tp: pass tunnel... |
815 |
} |
309795f4b l2tp: Add netlink... |
816 |
|
309795f4b l2tp: Add netlink... |
817 818 819 820 821 822 823 |
/* Default MTU values. */ if (cfg->mtu == 0) cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; if (cfg->mru == 0) cfg->mru = cfg->mtu; /* Allocate and initialize a new session context. */ |
309795f4b l2tp: Add netlink... |
824 825 826 |
session = l2tp_session_create(sizeof(struct pppol2tp_session), tunnel, session_id, peer_session_id, cfg); |
dbdbc73b4 l2tp: fix duplica... |
827 828 |
if (IS_ERR(session)) { error = PTR_ERR(session); |
3953ae7b2 l2tp: don't regis... |
829 |
goto err; |
dbdbc73b4 l2tp: fix duplica... |
830 |
} |
309795f4b l2tp: Add netlink... |
831 |
|
f98be6c63 l2tp: initialise ... |
832 |
pppol2tp_session_init(session); |
309795f4b l2tp: Add netlink... |
833 |
|
3953ae7b2 l2tp: don't regis... |
834 835 836 |
error = l2tp_session_register(session, tunnel); if (error < 0) goto err_sess; |
309795f4b l2tp: Add netlink... |
837 |
|
3953ae7b2 l2tp: don't regis... |
838 |
return 0; |
309795f4b l2tp: Add netlink... |
839 |
|
3953ae7b2 l2tp: don't regis... |
840 841 842 |
err_sess: kfree(session); err: |
309795f4b l2tp: Add netlink... |
843 844 |
return error; } |
309795f4b l2tp: Add netlink... |
845 |
#endif /* CONFIG_L2TP_V3 */ |
fd558d186 l2tp: Split pppol... |
846 847 848 |
/* getname() support. */ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, |
9b2c45d47 net: make getname... |
849 |
int peer) |
fd558d186 l2tp: Split pppol... |
850 |
{ |
e0d4435f9 l2tp: Update PPP-... |
851 |
int len = 0; |
fd558d186 l2tp: Split pppol... |
852 853 854 855 856 857 858 859 860 861 |
int error = 0; struct l2tp_session *session; struct l2tp_tunnel *tunnel; struct sock *sk = sock->sk; struct inet_sock *inet; struct pppol2tp_session *pls; error = -ENOTCONN; if (sk == NULL) goto end; |
56cff471d l2tp: Fix the con... |
862 |
if (!(sk->sk_state & PPPOX_CONNECTED)) |
fd558d186 l2tp: Split pppol... |
863 864 865 866 867 868 869 870 |
goto end; error = -EBADF; session = pppol2tp_sock_to_session(sk); if (session == NULL) goto end; pls = l2tp_session_priv(session); |
7198c77aa l2tp: avoid using... |
871 |
tunnel = session->tunnel; |
fd558d186 l2tp: Split pppol... |
872 |
|
bbdb32cb5 Fix pppol2tp gets... |
873 |
inet = inet_sk(tunnel->sock); |
d2cf33616 net/l2tp: add sup... |
874 |
if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET)) { |
e0d4435f9 l2tp: Update PPP-... |
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 |
struct sockaddr_pppol2tp sp; len = sizeof(sp); memset(&sp, 0, len); sp.sa_family = AF_PPPOX; sp.sa_protocol = PX_PROTO_OL2TP; sp.pppol2tp.fd = tunnel->fd; sp.pppol2tp.pid = pls->owner; sp.pppol2tp.s_tunnel = tunnel->tunnel_id; sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id; sp.pppol2tp.s_session = session->session_id; sp.pppol2tp.d_session = session->peer_session_id; sp.pppol2tp.addr.sin_family = AF_INET; sp.pppol2tp.addr.sin_port = inet->inet_dport; sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr; memcpy(uaddr, &sp, len); |
d2cf33616 net/l2tp: add sup... |
890 891 892 |
#if IS_ENABLED(CONFIG_IPV6) } else if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET6)) { |
d2cf33616 net/l2tp: add sup... |
893 |
struct sockaddr_pppol2tpin6 sp; |
efe4208f4 ipv6: make lookup... |
894 |
|
d2cf33616 net/l2tp: add sup... |
895 896 897 898 899 900 901 902 903 904 905 906 |
len = sizeof(sp); memset(&sp, 0, len); sp.sa_family = AF_PPPOX; sp.sa_protocol = PX_PROTO_OL2TP; sp.pppol2tp.fd = tunnel->fd; sp.pppol2tp.pid = pls->owner; sp.pppol2tp.s_tunnel = tunnel->tunnel_id; sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id; sp.pppol2tp.s_session = session->session_id; sp.pppol2tp.d_session = session->peer_session_id; sp.pppol2tp.addr.sin6_family = AF_INET6; sp.pppol2tp.addr.sin6_port = inet->inet_dport; |
efe4208f4 ipv6: make lookup... |
907 908 |
memcpy(&sp.pppol2tp.addr.sin6_addr, &tunnel->sock->sk_v6_daddr, sizeof(tunnel->sock->sk_v6_daddr)); |
d2cf33616 net/l2tp: add sup... |
909 910 911 |
memcpy(uaddr, &sp, len); } else if ((tunnel->version == 3) && (tunnel->sock->sk_family == AF_INET6)) { |
d2cf33616 net/l2tp: add sup... |
912 |
struct sockaddr_pppol2tpv3in6 sp; |
efe4208f4 ipv6: make lookup... |
913 |
|
d2cf33616 net/l2tp: add sup... |
914 915 916 917 918 919 920 921 922 923 924 925 |
len = sizeof(sp); memset(&sp, 0, len); sp.sa_family = AF_PPPOX; sp.sa_protocol = PX_PROTO_OL2TP; sp.pppol2tp.fd = tunnel->fd; sp.pppol2tp.pid = pls->owner; sp.pppol2tp.s_tunnel = tunnel->tunnel_id; sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id; sp.pppol2tp.s_session = session->session_id; sp.pppol2tp.d_session = session->peer_session_id; sp.pppol2tp.addr.sin6_family = AF_INET6; sp.pppol2tp.addr.sin6_port = inet->inet_dport; |
efe4208f4 ipv6: make lookup... |
926 927 |
memcpy(&sp.pppol2tp.addr.sin6_addr, &tunnel->sock->sk_v6_daddr, sizeof(tunnel->sock->sk_v6_daddr)); |
d2cf33616 net/l2tp: add sup... |
928 929 |
memcpy(uaddr, &sp, len); #endif |
e0d4435f9 l2tp: Update PPP-... |
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 |
} else if (tunnel->version == 3) { struct sockaddr_pppol2tpv3 sp; len = sizeof(sp); memset(&sp, 0, len); sp.sa_family = AF_PPPOX; sp.sa_protocol = PX_PROTO_OL2TP; sp.pppol2tp.fd = tunnel->fd; sp.pppol2tp.pid = pls->owner; sp.pppol2tp.s_tunnel = tunnel->tunnel_id; sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id; sp.pppol2tp.s_session = session->session_id; sp.pppol2tp.d_session = session->peer_session_id; sp.pppol2tp.addr.sin_family = AF_INET; sp.pppol2tp.addr.sin_port = inet->inet_dport; sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr; memcpy(uaddr, &sp, len); } |
fd558d186 l2tp: Split pppol... |
947 |
|
9b2c45d47 net: make getname... |
948 |
error = len; |
fd558d186 l2tp: Split pppol... |
949 |
|
fd558d186 l2tp: Split pppol... |
950 |
sock_put(sk); |
fd558d186 l2tp: Split pppol... |
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 |
end: return error; } /**************************************************************************** * ioctl() handlers. * * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP * sockets. However, in order to control kernel tunnel features, we allow * userspace to create a special "tunnel" PPPoX socket which is used for * control only. Tunnel PPPoX sockets have session_id == 0 and simply allow * the user application to issue L2TP setsockopt(), getsockopt() and ioctl() * calls. ****************************************************************************/ static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest, struct l2tp_stats *stats) { |
7b7c0719c l2tp: avoid deadl... |
969 970 971 972 973 974 975 976 |
dest->tx_packets = atomic_long_read(&stats->tx_packets); dest->tx_bytes = atomic_long_read(&stats->tx_bytes); dest->tx_errors = atomic_long_read(&stats->tx_errors); dest->rx_packets = atomic_long_read(&stats->rx_packets); dest->rx_bytes = atomic_long_read(&stats->rx_bytes); dest->rx_seq_discards = atomic_long_read(&stats->rx_seq_discards); dest->rx_oos_packets = atomic_long_read(&stats->rx_oos_packets); dest->rx_errors = atomic_long_read(&stats->rx_errors); |
fd558d186 l2tp: Split pppol... |
977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
} /* Session ioctl helper. */ static int pppol2tp_session_ioctl(struct l2tp_session *session, unsigned int cmd, unsigned long arg) { struct ifreq ifr; int err = 0; struct sock *sk; int val = (int) arg; struct pppol2tp_session *ps = l2tp_session_priv(session); struct l2tp_tunnel *tunnel = session->tunnel; struct pppol2tp_ioc_stats stats; |
fba40c632 net: l2tp: ppp: c... |
991 |
l2tp_dbg(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
992 993 994 |
"%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx) ", session->name, cmd, arg); |
fd558d186 l2tp: Split pppol... |
995 |
|
ee40fb2e1 l2tp: protect soc... |
996 |
sk = pppol2tp_session_get_sock(session); |
5903f5949 l2tp: check ps->s... |
997 998 |
if (!sk) return -EBADR; |
fd558d186 l2tp: Split pppol... |
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 |
switch (cmd) { case SIOCGIFMTU: err = -ENXIO; if (!(sk->sk_state & PPPOX_CONNECTED)) break; err = -EFAULT; if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq))) break; ifr.ifr_mtu = session->mtu; if (copy_to_user((void __user *) arg, &ifr, sizeof(struct ifreq))) break; |
fba40c632 net: l2tp: ppp: c... |
1011 1012 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: get mtu=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1013 |
session->name, session->mtu); |
fd558d186 l2tp: Split pppol... |
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 |
err = 0; break; case SIOCSIFMTU: err = -ENXIO; if (!(sk->sk_state & PPPOX_CONNECTED)) break; err = -EFAULT; if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq))) break; session->mtu = ifr.ifr_mtu; |
fba40c632 net: l2tp: ppp: c... |
1027 1028 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: set mtu=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1029 |
session->name, session->mtu); |
fd558d186 l2tp: Split pppol... |
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
err = 0; break; case PPPIOCGMRU: err = -ENXIO; if (!(sk->sk_state & PPPOX_CONNECTED)) break; err = -EFAULT; if (put_user(session->mru, (int __user *) arg)) break; |
fba40c632 net: l2tp: ppp: c... |
1041 1042 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: get mru=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1043 |
session->name, session->mru); |
fd558d186 l2tp: Split pppol... |
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 |
err = 0; break; case PPPIOCSMRU: err = -ENXIO; if (!(sk->sk_state & PPPOX_CONNECTED)) break; err = -EFAULT; if (get_user(val, (int __user *) arg)) break; session->mru = val; |
fba40c632 net: l2tp: ppp: c... |
1057 1058 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: set mru=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1059 |
session->name, session->mru); |
fd558d186 l2tp: Split pppol... |
1060 1061 1062 1063 1064 1065 1066 |
err = 0; break; case PPPIOCGFLAGS: err = -EFAULT; if (put_user(ps->flags, (int __user *) arg)) break; |
fba40c632 net: l2tp: ppp: c... |
1067 1068 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: get flags=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1069 |
session->name, ps->flags); |
fd558d186 l2tp: Split pppol... |
1070 1071 1072 1073 1074 1075 1076 1077 |
err = 0; break; case PPPIOCSFLAGS: err = -EFAULT; if (get_user(val, (int __user *) arg)) break; ps->flags = val; |
fba40c632 net: l2tp: ppp: c... |
1078 1079 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: set flags=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1080 |
session->name, ps->flags); |
fd558d186 l2tp: Split pppol... |
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 |
err = 0; break; case PPPIOCGL2TPSTATS: err = -ENXIO; if (!(sk->sk_state & PPPOX_CONNECTED)) break; memset(&stats, 0, sizeof(stats)); stats.tunnel_id = tunnel->tunnel_id; stats.session_id = session->session_id; pppol2tp_copy_stats(&stats, &session->stats); if (copy_to_user((void __user *) arg, &stats, sizeof(stats))) break; |
fba40c632 net: l2tp: ppp: c... |
1096 1097 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: get L2TP stats ", |
a4ca44fa5 net: l2tp: Standa... |
1098 |
session->name); |
fd558d186 l2tp: Split pppol... |
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 |
err = 0; break; default: err = -ENOSYS; break; } sock_put(sk); return err; } /* Tunnel ioctl helper. * * Note the special handling for PPPIOCGL2TPSTATS below. If the ioctl data * specifies a session_id, the session ioctl handler is called. This allows an * application to retrieve session stats via a tunnel socket. */ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel, unsigned int cmd, unsigned long arg) { int err = 0; struct sock *sk; struct pppol2tp_ioc_stats stats; |
fba40c632 net: l2tp: ppp: c... |
1124 |
l2tp_dbg(tunnel, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1125 1126 1127 |
"%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx) ", tunnel->name, cmd, arg); |
fd558d186 l2tp: Split pppol... |
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 |
sk = tunnel->sock; sock_hold(sk); switch (cmd) { case PPPIOCGL2TPSTATS: err = -ENXIO; if (!(sk->sk_state & PPPOX_CONNECTED)) break; if (copy_from_user(&stats, (void __user *) arg, sizeof(stats))) { err = -EFAULT; break; } if (stats.session_id != 0) { /* resend to session ioctl handler */ struct l2tp_session *session = |
57377d635 l2tp: ensure sess... |
1146 |
l2tp_session_get(sock_net(sk), tunnel, |
a4346210c l2tp: remove ->re... |
1147 |
stats.session_id); |
57377d635 l2tp: ensure sess... |
1148 1149 1150 1151 |
if (session) { err = pppol2tp_session_ioctl(session, cmd, arg); |
57377d635 l2tp: ensure sess... |
1152 1153 |
l2tp_session_dec_refcount(session); } else { |
fd558d186 l2tp: Split pppol... |
1154 |
err = -EBADR; |
57377d635 l2tp: ensure sess... |
1155 |
} |
fd558d186 l2tp: Split pppol... |
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 |
break; } #ifdef CONFIG_XFRM stats.using_ipsec = (sk->sk_policy[0] || sk->sk_policy[1]) ? 1 : 0; #endif pppol2tp_copy_stats(&stats, &tunnel->stats); if (copy_to_user((void __user *) arg, &stats, sizeof(stats))) { err = -EFAULT; break; } |
fba40c632 net: l2tp: ppp: c... |
1166 1167 |
l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: get L2TP stats ", |
a4ca44fa5 net: l2tp: Standa... |
1168 |
tunnel->name); |
fd558d186 l2tp: Split pppol... |
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
err = 0; break; default: err = -ENOSYS; break; } sock_put(sk); return err; } /* Main ioctl() handler. * Dispatch to tunnel or session helpers depending on the socket. */ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; struct l2tp_session *session; struct l2tp_tunnel *tunnel; |
fd558d186 l2tp: Split pppol... |
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 |
int err; if (!sk) return 0; err = -EBADF; if (sock_flag(sk, SOCK_DEAD) != 0) goto end; err = -ENOTCONN; if ((sk->sk_user_data == NULL) || (!(sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)))) goto end; /* Get session context from the socket */ err = -EBADF; session = pppol2tp_sock_to_session(sk); if (session == NULL) goto end; /* Special case: if session's session_id is zero, treat ioctl as a * tunnel ioctl */ |
fd558d186 l2tp: Split pppol... |
1214 1215 |
if ((session->session_id == 0) && (session->peer_session_id == 0)) { |
7198c77aa l2tp: avoid using... |
1216 |
tunnel = session->tunnel; |
fd558d186 l2tp: Split pppol... |
1217 |
err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg); |
fd558d186 l2tp: Split pppol... |
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 |
goto end_put_sess; } err = pppol2tp_session_ioctl(session, cmd, arg); end_put_sess: sock_put(sk); end: return err; } /***************************************************************************** * setsockopt() / getsockopt() support. * * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP * sockets. In order to control kernel tunnel features, we allow userspace to * create a special "tunnel" PPPoX socket which is used for control only. * Tunnel PPPoX sockets have session_id == 0 and simply allow the user * application to issue L2TP setsockopt(), getsockopt() and ioctl() calls. *****************************************************************************/ /* Tunnel setsockopt() helper. */ static int pppol2tp_tunnel_setsockopt(struct sock *sk, struct l2tp_tunnel *tunnel, int optname, int val) { int err = 0; switch (optname) { case PPPOL2TP_SO_DEBUG: tunnel->debug = val; |
fba40c632 net: l2tp: ppp: c... |
1250 1251 |
l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: set debug=%x ", |
a4ca44fa5 net: l2tp: Standa... |
1252 |
tunnel->name, tunnel->debug); |
fd558d186 l2tp: Split pppol... |
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
break; default: err = -ENOPROTOOPT; break; } return err; } /* Session setsockopt helper. */ static int pppol2tp_session_setsockopt(struct sock *sk, struct l2tp_session *session, int optname, int val) { int err = 0; |
fd558d186 l2tp: Split pppol... |
1270 1271 1272 1273 1274 1275 1276 |
switch (optname) { case PPPOL2TP_SO_RECVSEQ: if ((val != 0) && (val != 1)) { err = -EINVAL; break; } |
3f9b9770b net: l2tp: fix ne... |
1277 |
session->recv_seq = !!val; |
fba40c632 net: l2tp: ppp: c... |
1278 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1279 1280 1281 |
"%s: set recv_seq=%d ", session->name, session->recv_seq); |
fd558d186 l2tp: Split pppol... |
1282 1283 1284 1285 1286 1287 1288 |
break; case PPPOL2TP_SO_SENDSEQ: if ((val != 0) && (val != 1)) { err = -EINVAL; break; } |
3f9b9770b net: l2tp: fix ne... |
1289 |
session->send_seq = !!val; |
fd558d186 l2tp: Split pppol... |
1290 |
{ |
ee40fb2e1 l2tp: protect soc... |
1291 |
struct pppox_sock *po = pppox_sk(sk); |
fd558d186 l2tp: Split pppol... |
1292 1293 1294 |
po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ : PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; } |
bb5016eac l2tp: fix manual ... |
1295 |
l2tp_session_set_header_len(session, session->tunnel->version); |
fba40c632 net: l2tp: ppp: c... |
1296 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1297 1298 1299 |
"%s: set send_seq=%d ", session->name, session->send_seq); |
fd558d186 l2tp: Split pppol... |
1300 1301 1302 1303 1304 1305 1306 |
break; case PPPOL2TP_SO_LNSMODE: if ((val != 0) && (val != 1)) { err = -EINVAL; break; } |
3f9b9770b net: l2tp: fix ne... |
1307 |
session->lns_mode = !!val; |
fba40c632 net: l2tp: ppp: c... |
1308 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1309 1310 1311 |
"%s: set lns_mode=%d ", session->name, session->lns_mode); |
fd558d186 l2tp: Split pppol... |
1312 1313 1314 1315 |
break; case PPPOL2TP_SO_DEBUG: session->debug = val; |
fba40c632 net: l2tp: ppp: c... |
1316 1317 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: set debug=%x ", |
a4ca44fa5 net: l2tp: Standa... |
1318 |
session->name, session->debug); |
fd558d186 l2tp: Split pppol... |
1319 1320 1321 1322 |
break; case PPPOL2TP_SO_REORDERTO: session->reorder_timeout = msecs_to_jiffies(val); |
fba40c632 net: l2tp: ppp: c... |
1323 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1324 1325 1326 |
"%s: set reorder_timeout=%d ", session->name, session->reorder_timeout); |
fd558d186 l2tp: Split pppol... |
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
break; default: err = -ENOPROTOOPT; break; } return err; } /* Main setsockopt() entry point. * Does API checks, then calls either the tunnel or session setsockopt * handler, according to whether the PPPoL2TP socket is a for a regular * session or the special tunnel type. */ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct l2tp_session *session; struct l2tp_tunnel *tunnel; |
fd558d186 l2tp: Split pppol... |
1348 1349 1350 1351 |
int val; int err; if (level != SOL_PPPOL2TP) |
3cf521f7d net/l2tp: don't f... |
1352 |
return -EINVAL; |
fd558d186 l2tp: Split pppol... |
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 |
if (optlen < sizeof(int)) return -EINVAL; if (get_user(val, (int __user *)optval)) return -EFAULT; err = -ENOTCONN; if (sk->sk_user_data == NULL) goto end; /* Get session context from the socket */ err = -EBADF; session = pppol2tp_sock_to_session(sk); if (session == NULL) goto end; /* Special case: if session_id == 0x0000, treat as operation on tunnel */ |
fd558d186 l2tp: Split pppol... |
1372 1373 |
if ((session->session_id == 0) && (session->peer_session_id == 0)) { |
7198c77aa l2tp: avoid using... |
1374 |
tunnel = session->tunnel; |
fd558d186 l2tp: Split pppol... |
1375 |
err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val); |
7198c77aa l2tp: avoid using... |
1376 |
} else { |
fd558d186 l2tp: Split pppol... |
1377 |
err = pppol2tp_session_setsockopt(sk, session, optname, val); |
7198c77aa l2tp: avoid using... |
1378 |
} |
fd558d186 l2tp: Split pppol... |
1379 |
|
fd558d186 l2tp: Split pppol... |
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 |
sock_put(sk); end: return err; } /* Tunnel getsockopt helper. Called with sock locked. */ static int pppol2tp_tunnel_getsockopt(struct sock *sk, struct l2tp_tunnel *tunnel, int optname, int *val) { int err = 0; switch (optname) { case PPPOL2TP_SO_DEBUG: *val = tunnel->debug; |
fba40c632 net: l2tp: ppp: c... |
1396 1397 |
l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: get debug=%x ", |
a4ca44fa5 net: l2tp: Standa... |
1398 |
tunnel->name, tunnel->debug); |
fd558d186 l2tp: Split pppol... |
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 |
break; default: err = -ENOPROTOOPT; break; } return err; } /* Session getsockopt helper. Called with sock locked. */ static int pppol2tp_session_getsockopt(struct sock *sk, struct l2tp_session *session, int optname, int *val) { int err = 0; switch (optname) { case PPPOL2TP_SO_RECVSEQ: *val = session->recv_seq; |
fba40c632 net: l2tp: ppp: c... |
1420 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1421 1422 |
"%s: get recv_seq=%d ", session->name, *val); |
fd558d186 l2tp: Split pppol... |
1423 1424 1425 1426 |
break; case PPPOL2TP_SO_SENDSEQ: *val = session->send_seq; |
fba40c632 net: l2tp: ppp: c... |
1427 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1428 1429 |
"%s: get send_seq=%d ", session->name, *val); |
fd558d186 l2tp: Split pppol... |
1430 1431 1432 1433 |
break; case PPPOL2TP_SO_LNSMODE: *val = session->lns_mode; |
fba40c632 net: l2tp: ppp: c... |
1434 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1435 1436 |
"%s: get lns_mode=%d ", session->name, *val); |
fd558d186 l2tp: Split pppol... |
1437 1438 1439 1440 |
break; case PPPOL2TP_SO_DEBUG: *val = session->debug; |
fba40c632 net: l2tp: ppp: c... |
1441 1442 |
l2tp_info(session, L2TP_MSG_CONTROL, "%s: get debug=%d ", |
a4ca44fa5 net: l2tp: Standa... |
1443 |
session->name, *val); |
fd558d186 l2tp: Split pppol... |
1444 1445 1446 1447 |
break; case PPPOL2TP_SO_REORDERTO: *val = (int) jiffies_to_msecs(session->reorder_timeout); |
fba40c632 net: l2tp: ppp: c... |
1448 |
l2tp_info(session, L2TP_MSG_CONTROL, |
a4ca44fa5 net: l2tp: Standa... |
1449 1450 |
"%s: get reorder_timeout=%d ", session->name, *val); |
fd558d186 l2tp: Split pppol... |
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 |
break; default: err = -ENOPROTOOPT; } return err; } /* Main getsockopt() entry point. * Does API checks, then calls either the tunnel or session getsockopt * handler, according to whether the PPPoX socket is a for a regular session * or the special tunnel type. */ |
e3192690a net: Remove casts... |
1465 1466 |
static int pppol2tp_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) |
fd558d186 l2tp: Split pppol... |
1467 1468 1469 1470 1471 1472 |
{ struct sock *sk = sock->sk; struct l2tp_session *session; struct l2tp_tunnel *tunnel; int val, len; int err; |
fd558d186 l2tp: Split pppol... |
1473 1474 |
if (level != SOL_PPPOL2TP) |
3cf521f7d net/l2tp: don't f... |
1475 |
return -EINVAL; |
fd558d186 l2tp: Split pppol... |
1476 |
|
e3192690a net: Remove casts... |
1477 |
if (get_user(len, optlen)) |
fd558d186 l2tp: Split pppol... |
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 |
return -EFAULT; len = min_t(unsigned int, len, sizeof(int)); if (len < 0) return -EINVAL; err = -ENOTCONN; if (sk->sk_user_data == NULL) goto end; /* Get the session context */ err = -EBADF; session = pppol2tp_sock_to_session(sk); if (session == NULL) goto end; /* Special case: if session_id == 0x0000, treat as operation on tunnel */ |
fd558d186 l2tp: Split pppol... |
1496 1497 |
if ((session->session_id == 0) && (session->peer_session_id == 0)) { |
7198c77aa l2tp: avoid using... |
1498 |
tunnel = session->tunnel; |
fd558d186 l2tp: Split pppol... |
1499 |
err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val); |
321a52a39 l2tp: don't mask ... |
1500 1501 1502 |
if (err) goto end_put_sess; } else { |
fd558d186 l2tp: Split pppol... |
1503 |
err = pppol2tp_session_getsockopt(sk, session, optname, &val); |
321a52a39 l2tp: don't mask ... |
1504 1505 1506 |
if (err) goto end_put_sess; } |
fd558d186 l2tp: Split pppol... |
1507 1508 |
err = -EFAULT; |
e3192690a net: Remove casts... |
1509 |
if (put_user(len, optlen)) |
fd558d186 l2tp: Split pppol... |
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 |
goto end_put_sess; if (copy_to_user((void __user *) optval, &val, len)) goto end_put_sess; err = 0; end_put_sess: sock_put(sk); end: return err; } /***************************************************************************** * /proc filesystem for debug |
f7faffa3f l2tp: Add L2TPv3 ... |
1525 1526 |
* Since the original pppol2tp driver provided /proc/net/pppol2tp for * L2TPv2, we dump only L2TPv2 tunnels and sessions here. |
fd558d186 l2tp: Split pppol... |
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 |
*****************************************************************************/ static unsigned int pppol2tp_net_id; #ifdef CONFIG_PROC_FS struct pppol2tp_seq_data { struct seq_net_private p; int tunnel_idx; /* current tunnel */ int session_idx; /* index of session within current tunnel */ struct l2tp_tunnel *tunnel; struct l2tp_session *session; /* NULL means get next tunnel */ }; static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) { |
0e0c3fee3 l2tp: hold refere... |
1543 1544 1545 |
/* Drop reference taken during previous invocation */ if (pd->tunnel) l2tp_tunnel_dec_refcount(pd->tunnel); |
f7faffa3f l2tp: Add L2TPv3 ... |
1546 |
for (;;) { |
0e0c3fee3 l2tp: hold refere... |
1547 |
pd->tunnel = l2tp_tunnel_get_nth(net, pd->tunnel_idx); |
f7faffa3f l2tp: Add L2TPv3 ... |
1548 |
pd->tunnel_idx++; |
0e0c3fee3 l2tp: hold refere... |
1549 1550 1551 |
/* Only accept L2TPv2 tunnels */ if (!pd->tunnel || pd->tunnel->version == 2) return; |
f7faffa3f l2tp: Add L2TPv3 ... |
1552 |
|
0e0c3fee3 l2tp: hold refere... |
1553 |
l2tp_tunnel_dec_refcount(pd->tunnel); |
f7faffa3f l2tp: Add L2TPv3 ... |
1554 |
} |
fd558d186 l2tp: Split pppol... |
1555 1556 1557 1558 |
} static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) { |
834944073 l2tp: consistent ... |
1559 1560 1561 |
/* Drop reference taken during previous invocation */ if (pd->session) l2tp_session_dec_refcount(pd->session); |
a4346210c l2tp: remove ->re... |
1562 |
pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx); |
fd558d186 l2tp: Split pppol... |
1563 |
pd->session_idx++; |
f7faffa3f l2tp: Add L2TPv3 ... |
1564 |
|
fd558d186 l2tp: Split pppol... |
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 |
if (pd->session == NULL) { pd->session_idx = 0; pppol2tp_next_tunnel(net, pd); } } static void *pppol2tp_seq_start(struct seq_file *m, loff_t *offs) { struct pppol2tp_seq_data *pd = SEQ_START_TOKEN; loff_t pos = *offs; struct net *net; if (!pos) goto out; BUG_ON(m->private == NULL); pd = m->private; net = seq_file_net(m); if (pd->tunnel == NULL) pppol2tp_next_tunnel(net, pd); else pppol2tp_next_session(net, pd); /* NULL tunnel and session indicates end of list */ if ((pd->tunnel == NULL) && (pd->session == NULL)) pd = NULL; out: return pd; } static void *pppol2tp_seq_next(struct seq_file *m, void *v, loff_t *pos) { (*pos)++; return NULL; } static void pppol2tp_seq_stop(struct seq_file *p, void *v) { |
0e0c3fee3 l2tp: hold refere... |
1605 1606 1607 1608 |
struct pppol2tp_seq_data *pd = v; if (!pd || pd == SEQ_START_TOKEN) return; |
834944073 l2tp: consistent ... |
1609 1610 1611 1612 1613 1614 1615 |
/* Drop reference taken by last invocation of pppol2tp_next_session() * or pppol2tp_next_tunnel(). */ if (pd->session) { l2tp_session_dec_refcount(pd->session); pd->session = NULL; } |
5411b6187 l2tp: fix {pppol2... |
1616 |
if (pd->tunnel) { |
0e0c3fee3 l2tp: hold refere... |
1617 |
l2tp_tunnel_dec_refcount(pd->tunnel); |
5411b6187 l2tp: fix {pppol2... |
1618 |
pd->tunnel = NULL; |
5411b6187 l2tp: fix {pppol2... |
1619 |
} |
fd558d186 l2tp: Split pppol... |
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 |
} static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v) { struct l2tp_tunnel *tunnel = v; seq_printf(m, " TUNNEL '%s', %c %d ", tunnel->name, (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N', |
fbea9e076 net, l2tp: conver... |
1631 |
refcount_read(&tunnel->ref_count) - 1); |
7b7c0719c l2tp: avoid deadl... |
1632 1633 |
seq_printf(m, " %08x %ld/%ld/%ld %ld/%ld/%ld ", |
fd558d186 l2tp: Split pppol... |
1634 |
tunnel->debug, |
7b7c0719c l2tp: avoid deadl... |
1635 1636 1637 1638 1639 1640 |
atomic_long_read(&tunnel->stats.tx_packets), atomic_long_read(&tunnel->stats.tx_bytes), atomic_long_read(&tunnel->stats.tx_errors), atomic_long_read(&tunnel->stats.rx_packets), atomic_long_read(&tunnel->stats.rx_bytes), atomic_long_read(&tunnel->stats.rx_errors)); |
fd558d186 l2tp: Split pppol... |
1641 1642 1643 1644 1645 1646 |
} static void pppol2tp_seq_session_show(struct seq_file *m, void *v) { struct l2tp_session *session = v; struct l2tp_tunnel *tunnel = session->tunnel; |
ee40fb2e1 l2tp: protect soc... |
1647 1648 1649 |
unsigned char state; char user_data_ok; struct sock *sk; |
fd558d186 l2tp: Split pppol... |
1650 1651 1652 1653 1654 1655 1656 1657 |
u32 ip = 0; u16 port = 0; if (tunnel->sock) { struct inet_sock *inet = inet_sk(tunnel->sock); ip = ntohl(inet->inet_saddr); port = ntohs(inet->inet_sport); } |
ee40fb2e1 l2tp: protect soc... |
1658 1659 1660 1661 1662 1663 1664 1665 |
sk = pppol2tp_session_get_sock(session); if (sk) { state = sk->sk_state; user_data_ok = (session == sk->sk_user_data) ? 'Y' : 'N'; } else { state = 0; user_data_ok = 'N'; } |
fd558d186 l2tp: Split pppol... |
1666 1667 1668 1669 1670 1671 1672 1673 |
seq_printf(m, " SESSION '%s' %08X/%d %04X/%04X -> " "%04X/%04X %d %c ", session->name, ip, port, tunnel->tunnel_id, session->session_id, tunnel->peer_tunnel_id, session->peer_session_id, |
ee40fb2e1 l2tp: protect soc... |
1674 |
state, user_data_ok); |
fd558d186 l2tp: Split pppol... |
1675 1676 1677 1678 1679 1680 1681 1682 |
seq_printf(m, " %d/%d/%c/%c/%s %08x %u ", session->mtu, session->mru, session->recv_seq ? 'R' : '-', session->send_seq ? 'S' : '-', session->lns_mode ? "LNS" : "LAC", session->debug, jiffies_to_msecs(session->reorder_timeout)); |
7b7c0719c l2tp: avoid deadl... |
1683 1684 |
seq_printf(m, " %hu/%hu %ld/%ld/%ld %ld/%ld/%ld ", |
fd558d186 l2tp: Split pppol... |
1685 |
session->nr, session->ns, |
7b7c0719c l2tp: avoid deadl... |
1686 1687 1688 1689 1690 1691 |
atomic_long_read(&session->stats.tx_packets), atomic_long_read(&session->stats.tx_bytes), atomic_long_read(&session->stats.tx_errors), atomic_long_read(&session->stats.rx_packets), atomic_long_read(&session->stats.rx_bytes), atomic_long_read(&session->stats.rx_errors)); |
9345471bc l2tp: Add ppp dev... |
1692 |
|
ee40fb2e1 l2tp: protect soc... |
1693 1694 |
if (sk) { struct pppox_sock *po = pppox_sk(sk); |
9345471bc l2tp: Add ppp dev... |
1695 1696 |
seq_printf(m, " interface %s ", ppp_dev_name(&po->chan)); |
ee40fb2e1 l2tp: protect soc... |
1697 1698 |
sock_put(sk); } |
fd558d186 l2tp: Split pppol... |
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 |
} static int pppol2tp_seq_show(struct seq_file *m, void *v) { struct pppol2tp_seq_data *pd = v; /* display header on line 1 */ if (v == SEQ_START_TOKEN) { seq_puts(m, "PPPoL2TP driver info, " PPPOL2TP_DRV_VERSION " "); seq_puts(m, "TUNNEL name, user-data-ok session-count "); seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs "); seq_puts(m, " SESSION name, addr/port src-tid/sid " "dest-tid/sid state user-data-ok "); seq_puts(m, " mtu/mru/rcvseq/sendseq/lns debug reorderto "); seq_puts(m, " nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs "); goto out; } |
834944073 l2tp: consistent ... |
1722 |
if (!pd->session) |
fd558d186 l2tp: Split pppol... |
1723 |
pppol2tp_seq_tunnel_show(m, pd->tunnel); |
834944073 l2tp: consistent ... |
1724 |
else |
fd558d186 l2tp: Split pppol... |
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
pppol2tp_seq_session_show(m, pd->session); out: return 0; } static const struct seq_operations pppol2tp_seq_ops = { .start = pppol2tp_seq_start, .next = pppol2tp_seq_next, .stop = pppol2tp_seq_stop, .show = pppol2tp_seq_show, }; |
fd558d186 l2tp: Split pppol... |
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 |
#endif /* CONFIG_PROC_FS */ /***************************************************************************** * Network namespace *****************************************************************************/ static __net_init int pppol2tp_init_net(struct net *net) { struct proc_dir_entry *pde; int err = 0; |
c35063722 proc: introduce p... |
1747 1748 |
pde = proc_create_net("pppol2tp", 0444, net->proc_net, &pppol2tp_seq_ops, sizeof(struct pppol2tp_seq_data)); |
fd558d186 l2tp: Split pppol... |
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 |
if (!pde) { err = -ENOMEM; goto out; } out: return err; } static __net_exit void pppol2tp_exit_net(struct net *net) { |
ece31ffd5 net: proc: change... |
1760 |
remove_proc_entry("pppol2tp", net->proc_net); |
fd558d186 l2tp: Split pppol... |
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 |
} static struct pernet_operations pppol2tp_net_ops = { .init = pppol2tp_init_net, .exit = pppol2tp_exit_net, .id = &pppol2tp_net_id, }; /***************************************************************************** * Init and cleanup *****************************************************************************/ static const struct proto_ops pppol2tp_ops = { .family = AF_PPPOX, .owner = THIS_MODULE, .release = pppol2tp_release, .bind = sock_no_bind, .connect = pppol2tp_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = pppol2tp_getname, |
db5051ead net: convert data... |
1782 |
.poll_mask = datagram_poll_mask, |
fd558d186 l2tp: Split pppol... |
1783 1784 1785 1786 1787 1788 1789 1790 1791 |
.listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = pppol2tp_setsockopt, .getsockopt = pppol2tp_getsockopt, .sendmsg = pppol2tp_sendmsg, .recvmsg = pppol2tp_recvmsg, .mmap = sock_no_mmap, .ioctl = pppox_ioctl, }; |
756e64a0b net: constify som... |
1792 |
static const struct pppox_proto pppol2tp_proto = { |
fd558d186 l2tp: Split pppol... |
1793 |
.create = pppol2tp_create, |
e1558a93b l2tp: add missing... |
1794 1795 |
.ioctl = pppol2tp_ioctl, .owner = THIS_MODULE, |
fd558d186 l2tp: Split pppol... |
1796 |
}; |
309795f4b l2tp: Add netlink... |
1797 1798 1799 1800 |
#ifdef CONFIG_L2TP_V3 static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = { .session_create = pppol2tp_session_create, |
cf2f5c886 l2tp: push all pp... |
1801 |
.session_delete = l2tp_session_delete, |
309795f4b l2tp: Add netlink... |
1802 1803 1804 |
}; #endif /* CONFIG_L2TP_V3 */ |
fd558d186 l2tp: Split pppol... |
1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 |
static int __init pppol2tp_init(void) { int err; err = register_pernet_device(&pppol2tp_net_ops); if (err) goto out; err = proto_register(&pppol2tp_sk_proto, 0); if (err) goto out_unregister_pppol2tp_pernet; err = register_pppox_proto(PX_PROTO_OL2TP, &pppol2tp_proto); if (err) goto out_unregister_pppol2tp_proto; |
309795f4b l2tp: Add netlink... |
1820 1821 1822 1823 1824 |
#ifdef CONFIG_L2TP_V3 err = l2tp_nl_register_ops(L2TP_PWTYPE_PPP, &pppol2tp_nl_cmd_ops); if (err) goto out_unregister_pppox; #endif |
a4ca44fa5 net: l2tp: Standa... |
1825 1826 |
pr_info("PPPoL2TP kernel driver, %s ", PPPOL2TP_DRV_VERSION); |
fd558d186 l2tp: Split pppol... |
1827 1828 1829 |
out: return err; |
309795f4b l2tp: Add netlink... |
1830 1831 1832 1833 1834 |
#ifdef CONFIG_L2TP_V3 out_unregister_pppox: unregister_pppox_proto(PX_PROTO_OL2TP); #endif |
fd558d186 l2tp: Split pppol... |
1835 1836 1837 1838 1839 1840 1841 1842 1843 |
out_unregister_pppol2tp_proto: proto_unregister(&pppol2tp_sk_proto); out_unregister_pppol2tp_pernet: unregister_pernet_device(&pppol2tp_net_ops); goto out; } static void __exit pppol2tp_exit(void) { |
309795f4b l2tp: Add netlink... |
1844 1845 1846 |
#ifdef CONFIG_L2TP_V3 l2tp_nl_unregister_ops(L2TP_PWTYPE_PPP); #endif |
fd558d186 l2tp: Split pppol... |
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 |
unregister_pppox_proto(PX_PROTO_OL2TP); proto_unregister(&pppol2tp_sk_proto); unregister_pernet_device(&pppol2tp_net_ops); } module_init(pppol2tp_init); module_exit(pppol2tp_exit); MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("PPP over L2TP over UDP"); MODULE_LICENSE("GPL"); MODULE_VERSION(PPPOL2TP_DRV_VERSION); |
681b4d88a pppox: use standa... |
1859 |
MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); |
249ee819e l2tp: fix PPP pse... |
1860 |
MODULE_ALIAS_L2TP_PWTYPE(7); |