Commit f7faffa3ff8ef6ae712ef16312b8a2aa7a1c95fe
Committed by
David S. Miller
1 parent
9345471bca
Exists in
master
and in
39 other branches
l2tp: Add L2TPv3 protocol support
The L2TPv3 protocol changes the layout of the L2TP packet header. Tunnel and session ids change from 16-bit to 32-bit values, data sequence numbers change from 16-bit to 24-bit values and PPP-specific fields are moved into protocol-specific subheaders. Although this patch introduces L2TPv3 protocol support, there are no userspace interfaces to create L2TPv3 sessions yet. 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>
Showing 4 changed files with 484 additions and 148 deletions Side-by-side Diff
net/l2tp/Kconfig
... | ... | @@ -19,6 +19,10 @@ |
19 | 19 | connections. L2TP is also used as a VPN protocol, popular |
20 | 20 | with home workers to connect to their offices. |
21 | 21 | |
22 | + L2TPv3 allows other protocols as well as PPP to be carried | |
23 | + over L2TP tunnels. L2TPv3 is defined in RFC 3931 | |
24 | + <http://www.ietf.org/rfc/rfc3931.txt>. | |
25 | + | |
22 | 26 | The kernel component handles only L2TP data packets: a |
23 | 27 | userland daemon handles L2TP the control protocol (tunnel |
24 | 28 | and session setup). One such daemon is OpenL2TP |
... | ... | @@ -26,4 +30,25 @@ |
26 | 30 | |
27 | 31 | If you don't need L2TP, say N. To compile all L2TP code as |
28 | 32 | modules, choose M here. |
33 | + | |
34 | +config L2TP_V3 | |
35 | + bool "L2TPv3 support (EXPERIMENTAL)" | |
36 | + depends on EXPERIMENTAL && L2TP | |
37 | + help | |
38 | + Layer Two Tunneling Protocol Version 3 | |
39 | + | |
40 | + From RFC 3931 <http://www.ietf.org/rfc/rfc3931.txt>. | |
41 | + | |
42 | + The Layer Two Tunneling Protocol (L2TP) provides a dynamic | |
43 | + mechanism for tunneling Layer 2 (L2) "circuits" across a | |
44 | + packet-oriented data network (e.g., over IP). L2TP, as | |
45 | + originally defined in RFC 2661, is a standard method for | |
46 | + tunneling Point-to-Point Protocol (PPP) [RFC1661] sessions. | |
47 | + L2TP has since been adopted for tunneling a number of other | |
48 | + L2 protocols, including ATM, Frame Relay, HDLC and even raw | |
49 | + ethernet frames. | |
50 | + | |
51 | + If you are connecting to L2TPv3 equipment, or you want to | |
52 | + tunnel raw ethernet frames using L2TP, say Y here. If | |
53 | + unsure, say N. |
net/l2tp/l2tp_core.c
... | ... | @@ -65,6 +65,7 @@ |
65 | 65 | |
66 | 66 | #define L2TP_HDR_VER_MASK 0x000F |
67 | 67 | #define L2TP_HDR_VER_2 0x0002 |
68 | +#define L2TP_HDR_VER_3 0x0003 | |
68 | 69 | |
69 | 70 | /* L2TPv3 default L2-specific sublayer */ |
70 | 71 | #define L2TP_SLFLAG_S 0x40000000 |
... | ... | @@ -85,7 +86,7 @@ |
85 | 86 | /* Private data stored for received packets in the skb. |
86 | 87 | */ |
87 | 88 | struct l2tp_skb_cb { |
88 | - u16 ns; | |
89 | + u32 ns; | |
89 | 90 | u16 has_seq; |
90 | 91 | u16 length; |
91 | 92 | unsigned long expires; |
... | ... | @@ -101,6 +102,8 @@ |
101 | 102 | struct l2tp_net { |
102 | 103 | struct list_head l2tp_tunnel_list; |
103 | 104 | rwlock_t l2tp_tunnel_list_lock; |
105 | + struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; | |
106 | + rwlock_t l2tp_session_hlist_lock; | |
104 | 107 | }; |
105 | 108 | |
106 | 109 | static inline struct l2tp_net *l2tp_pernet(struct net *net) |
... | ... | @@ -110,6 +113,40 @@ |
110 | 113 | return net_generic(net, l2tp_net_id); |
111 | 114 | } |
112 | 115 | |
116 | +/* Session hash global list for L2TPv3. | |
117 | + * The session_id SHOULD be random according to RFC3931, but several | |
118 | + * L2TP implementations use incrementing session_ids. So we do a real | |
119 | + * hash on the session_id, rather than a simple bitmask. | |
120 | + */ | |
121 | +static inline struct hlist_head * | |
122 | +l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) | |
123 | +{ | |
124 | + return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)]; | |
125 | + | |
126 | +} | |
127 | + | |
128 | +/* Lookup a session by id in the global session list | |
129 | + */ | |
130 | +static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) | |
131 | +{ | |
132 | + struct l2tp_net *pn = l2tp_pernet(net); | |
133 | + struct hlist_head *session_list = | |
134 | + l2tp_session_id_hash_2(pn, session_id); | |
135 | + struct l2tp_session *session; | |
136 | + struct hlist_node *walk; | |
137 | + | |
138 | + read_lock_bh(&pn->l2tp_session_hlist_lock); | |
139 | + hlist_for_each_entry(session, walk, session_list, global_hlist) { | |
140 | + if (session->session_id == session_id) { | |
141 | + read_unlock_bh(&pn->l2tp_session_hlist_lock); | |
142 | + return session; | |
143 | + } | |
144 | + } | |
145 | + read_unlock_bh(&pn->l2tp_session_hlist_lock); | |
146 | + | |
147 | + return NULL; | |
148 | +} | |
149 | + | |
113 | 150 | /* Session hash list. |
114 | 151 | * The session_id SHOULD be random according to RFC2661, but several |
115 | 152 | * L2TP implementations (Cisco and Microsoft) use incrementing |
116 | 153 | |
117 | 154 | |
... | ... | @@ -124,13 +161,20 @@ |
124 | 161 | |
125 | 162 | /* Lookup a session by id |
126 | 163 | */ |
127 | -struct l2tp_session *l2tp_session_find(struct l2tp_tunnel *tunnel, u32 session_id) | |
164 | +struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id) | |
128 | 165 | { |
129 | - struct hlist_head *session_list = | |
130 | - l2tp_session_id_hash(tunnel, session_id); | |
166 | + struct hlist_head *session_list; | |
131 | 167 | struct l2tp_session *session; |
132 | 168 | struct hlist_node *walk; |
133 | 169 | |
170 | + /* In L2TPv3, session_ids are unique over all tunnels and we | |
171 | + * sometimes need to look them up before we know the | |
172 | + * tunnel. | |
173 | + */ | |
174 | + if (tunnel == NULL) | |
175 | + return l2tp_session_find_2(net, session_id); | |
176 | + | |
177 | + session_list = l2tp_session_id_hash(tunnel, session_id); | |
134 | 178 | read_lock_bh(&tunnel->hlist_lock); |
135 | 179 | hlist_for_each_entry(session, walk, session_list, hlist) { |
136 | 180 | if (session->session_id == session_id) { |
... | ... | @@ -218,7 +262,7 @@ |
218 | 262 | { |
219 | 263 | struct sk_buff *skbp; |
220 | 264 | struct sk_buff *tmp; |
221 | - u16 ns = L2TP_SKB_CB(skb)->ns; | |
265 | + u32 ns = L2TP_SKB_CB(skb)->ns; | |
222 | 266 | |
223 | 267 | spin_lock_bh(&session->reorder_q.lock); |
224 | 268 | skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { |
... | ... | @@ -259,6 +303,11 @@ |
259 | 303 | if (L2TP_SKB_CB(skb)->has_seq) { |
260 | 304 | /* Bump our Nr */ |
261 | 305 | session->nr++; |
306 | + if (tunnel->version == L2TP_HDR_VER_2) | |
307 | + session->nr &= 0xffff; | |
308 | + else | |
309 | + session->nr &= 0xffffff; | |
310 | + | |
262 | 311 | PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, |
263 | 312 | "%s: updated nr to %hu\n", session->name, session->nr); |
264 | 313 | } |
... | ... | @@ -291,8 +340,8 @@ |
291 | 340 | session->stats.rx_seq_discards++; |
292 | 341 | session->stats.rx_errors++; |
293 | 342 | PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, |
294 | - "%s: oos pkt %hu len %d discarded (too old), " | |
295 | - "waiting for %hu, reorder_q_len=%d\n", | |
343 | + "%s: oos pkt %u len %d discarded (too old), " | |
344 | + "waiting for %u, reorder_q_len=%d\n", | |
296 | 345 | session->name, L2TP_SKB_CB(skb)->ns, |
297 | 346 | L2TP_SKB_CB(skb)->length, session->nr, |
298 | 347 | skb_queue_len(&session->reorder_q)); |
... | ... | @@ -306,8 +355,8 @@ |
306 | 355 | if (L2TP_SKB_CB(skb)->has_seq) { |
307 | 356 | if (L2TP_SKB_CB(skb)->ns != session->nr) { |
308 | 357 | PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, |
309 | - "%s: holding oos pkt %hu len %d, " | |
310 | - "waiting for %hu, reorder_q_len=%d\n", | |
358 | + "%s: holding oos pkt %u len %d, " | |
359 | + "waiting for %u, reorder_q_len=%d\n", | |
311 | 360 | session->name, L2TP_SKB_CB(skb)->ns, |
312 | 361 | L2TP_SKB_CB(skb)->length, session->nr, |
313 | 362 | skb_queue_len(&session->reorder_q)); |
314 | 363 | |
315 | 364 | |
316 | 365 | |
317 | 366 | |
... | ... | @@ -352,101 +401,74 @@ |
352 | 401 | return __skb_checksum_complete(skb); |
353 | 402 | } |
354 | 403 | |
355 | -/* Internal UDP receive frame. Do the real work of receiving an L2TP data frame | |
356 | - * here. The skb is not on a list when we get here. | |
357 | - * Returns 0 if the packet was a data packet and was successfully passed on. | |
358 | - * Returns 1 if the packet was not a good data packet and could not be | |
359 | - * forwarded. All such packets are passed up to userspace to deal with. | |
404 | +/* Do receive processing of L2TP data frames. We handle both L2TPv2 | |
405 | + * and L2TPv3 data frames here. | |
406 | + * | |
407 | + * L2TPv2 Data Message Header | |
408 | + * | |
409 | + * 0 1 2 3 | |
410 | + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
411 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
412 | + * |T|L|x|x|S|x|O|P|x|x|x|x| Ver | Length (opt) | | |
413 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
414 | + * | Tunnel ID | Session ID | | |
415 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
416 | + * | Ns (opt) | Nr (opt) | | |
417 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
418 | + * | Offset Size (opt) | Offset pad... (opt) | |
419 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
420 | + * | |
421 | + * Data frames are marked by T=0. All other fields are the same as | |
422 | + * those in L2TP control frames. | |
423 | + * | |
424 | + * L2TPv3 Data Message Header | |
425 | + * | |
426 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
427 | + * | L2TP Session Header | | |
428 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
429 | + * | L2-Specific Sublayer | | |
430 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
431 | + * | Tunnel Payload ... | |
432 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
433 | + * | |
434 | + * L2TPv3 Session Header Over IP | |
435 | + * | |
436 | + * 0 1 2 3 | |
437 | + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
438 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
439 | + * | Session ID | | |
440 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
441 | + * | Cookie (optional, maximum 64 bits)... | |
442 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
443 | + * | | |
444 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
445 | + * | |
446 | + * L2TPv3 L2-Specific Sublayer Format | |
447 | + * | |
448 | + * 0 1 2 3 | |
449 | + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
450 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
451 | + * |x|S|x|x|x|x|x|x| Sequence Number | | |
452 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
453 | + * | |
454 | + * Cookie value, sublayer format and offset (pad) are negotiated with | |
455 | + * the peer when the session is set up. Unlike L2TPv2, we do not need | |
456 | + * to parse the packet header to determine if optional fields are | |
457 | + * present. | |
458 | + * | |
459 | + * Caller must already have parsed the frame and determined that it is | |
460 | + * a data (not control) frame before coming here. Fields up to the | |
461 | + * session-id have already been parsed and ptr points to the data | |
462 | + * after the session-id. | |
360 | 463 | */ |
361 | -int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |
362 | - int (*payload_hook)(struct sk_buff *skb)) | |
464 | +void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | |
465 | + unsigned char *ptr, unsigned char *optr, u16 hdrflags, | |
466 | + int length, int (*payload_hook)(struct sk_buff *skb)) | |
363 | 467 | { |
364 | - struct l2tp_session *session = NULL; | |
365 | - unsigned char *ptr, *optr; | |
366 | - u16 hdrflags; | |
367 | - u32 tunnel_id, session_id; | |
368 | - int length; | |
468 | + struct l2tp_tunnel *tunnel = session->tunnel; | |
369 | 469 | int offset; |
370 | - u16 version; | |
371 | - u16 ns, nr; | |
470 | + u32 ns, nr; | |
372 | 471 | |
373 | - if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) | |
374 | - goto discard_bad_csum; | |
375 | - | |
376 | - /* UDP always verifies the packet length. */ | |
377 | - __skb_pull(skb, sizeof(struct udphdr)); | |
378 | - | |
379 | - /* Short packet? */ | |
380 | - if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) { | |
381 | - PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
382 | - "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); | |
383 | - goto error; | |
384 | - } | |
385 | - | |
386 | - /* Point to L2TP header */ | |
387 | - optr = ptr = skb->data; | |
388 | - | |
389 | - /* Trace packet contents, if enabled */ | |
390 | - if (tunnel->debug & L2TP_MSG_DATA) { | |
391 | - length = min(32u, skb->len); | |
392 | - if (!pskb_may_pull(skb, length)) | |
393 | - goto error; | |
394 | - | |
395 | - printk(KERN_DEBUG "%s: recv: ", tunnel->name); | |
396 | - | |
397 | - offset = 0; | |
398 | - do { | |
399 | - printk(" %02X", ptr[offset]); | |
400 | - } while (++offset < length); | |
401 | - | |
402 | - printk("\n"); | |
403 | - } | |
404 | - | |
405 | - /* Get L2TP header flags */ | |
406 | - hdrflags = ntohs(*(__be16 *)ptr); | |
407 | - | |
408 | - /* Check protocol version */ | |
409 | - version = hdrflags & L2TP_HDR_VER_MASK; | |
410 | - if (version != tunnel->version) { | |
411 | - PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
412 | - "%s: recv protocol version mismatch: got %d expected %d\n", | |
413 | - tunnel->name, version, tunnel->version); | |
414 | - goto error; | |
415 | - } | |
416 | - | |
417 | - /* Get length of L2TP packet */ | |
418 | - length = skb->len; | |
419 | - | |
420 | - /* If type is control packet, it is handled by userspace. */ | |
421 | - if (hdrflags & L2TP_HDRFLAG_T) { | |
422 | - PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG, | |
423 | - "%s: recv control packet, len=%d\n", tunnel->name, length); | |
424 | - goto error; | |
425 | - } | |
426 | - | |
427 | - /* Skip flags */ | |
428 | - ptr += 2; | |
429 | - | |
430 | - /* If length is present, skip it */ | |
431 | - if (hdrflags & L2TP_HDRFLAG_L) | |
432 | - ptr += 2; | |
433 | - | |
434 | - /* Extract tunnel and session ID */ | |
435 | - tunnel_id = ntohs(*(__be16 *) ptr); | |
436 | - ptr += 2; | |
437 | - session_id = ntohs(*(__be16 *) ptr); | |
438 | - ptr += 2; | |
439 | - | |
440 | - /* Find the session context */ | |
441 | - session = l2tp_session_find(tunnel, session_id); | |
442 | - if (!session) { | |
443 | - /* Not found? Pass to userspace to deal with */ | |
444 | - PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
445 | - "%s: no session found (%hu/%hu). Passing up.\n", | |
446 | - tunnel->name, tunnel_id, session_id); | |
447 | - goto error; | |
448 | - } | |
449 | - | |
450 | 472 | /* The ref count is increased since we now hold a pointer to |
451 | 473 | * the session. Take care to decrement the refcnt when exiting |
452 | 474 | * this function from now on... |
... | ... | @@ -455,6 +477,18 @@ |
455 | 477 | if (session->ref) |
456 | 478 | (*session->ref)(session); |
457 | 479 | |
480 | + /* Parse and check optional cookie */ | |
481 | + if (session->peer_cookie_len > 0) { | |
482 | + if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { | |
483 | + PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
484 | + "%s: cookie mismatch (%u/%u). Discarding.\n", | |
485 | + tunnel->name, tunnel->tunnel_id, session->session_id); | |
486 | + session->stats.rx_cookie_discards++; | |
487 | + goto discard; | |
488 | + } | |
489 | + ptr += session->peer_cookie_len; | |
490 | + } | |
491 | + | |
458 | 492 | /* Handle the optional sequence numbers. Sequence numbers are |
459 | 493 | * in different places for L2TPv2 and L2TPv3. |
460 | 494 | * |
461 | 495 | |
462 | 496 | |
463 | 497 | |
... | ... | @@ -464,21 +498,40 @@ |
464 | 498 | */ |
465 | 499 | ns = nr = 0; |
466 | 500 | L2TP_SKB_CB(skb)->has_seq = 0; |
467 | - if (hdrflags & L2TP_HDRFLAG_S) { | |
468 | - ns = (u16) ntohs(*(__be16 *) ptr); | |
469 | - ptr += 2; | |
470 | - nr = ntohs(*(__be16 *) ptr); | |
471 | - ptr += 2; | |
501 | + if (tunnel->version == L2TP_HDR_VER_2) { | |
502 | + if (hdrflags & L2TP_HDRFLAG_S) { | |
503 | + ns = ntohs(*(__be16 *) ptr); | |
504 | + ptr += 2; | |
505 | + nr = ntohs(*(__be16 *) ptr); | |
506 | + ptr += 2; | |
472 | 507 | |
473 | - /* Store L2TP info in the skb */ | |
474 | - L2TP_SKB_CB(skb)->ns = ns; | |
475 | - L2TP_SKB_CB(skb)->has_seq = 1; | |
508 | + /* Store L2TP info in the skb */ | |
509 | + L2TP_SKB_CB(skb)->ns = ns; | |
510 | + L2TP_SKB_CB(skb)->has_seq = 1; | |
476 | 511 | |
477 | - PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, | |
478 | - "%s: recv data ns=%hu, nr=%hu, session nr=%hu\n", | |
479 | - session->name, ns, nr, session->nr); | |
512 | + PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, | |
513 | + "%s: recv data ns=%u, nr=%u, session nr=%u\n", | |
514 | + session->name, ns, nr, session->nr); | |
515 | + } | |
516 | + } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { | |
517 | + u32 l2h = ntohl(*(__be32 *) ptr); | |
518 | + | |
519 | + if (l2h & 0x40000000) { | |
520 | + ns = l2h & 0x00ffffff; | |
521 | + | |
522 | + /* Store L2TP info in the skb */ | |
523 | + L2TP_SKB_CB(skb)->ns = ns; | |
524 | + L2TP_SKB_CB(skb)->has_seq = 1; | |
525 | + | |
526 | + PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, | |
527 | + "%s: recv data ns=%u, session nr=%u\n", | |
528 | + session->name, ns, session->nr); | |
529 | + } | |
480 | 530 | } |
481 | 531 | |
532 | + /* Advance past L2-specific header, if present */ | |
533 | + ptr += session->l2specific_len; | |
534 | + | |
482 | 535 | if (L2TP_SKB_CB(skb)->has_seq) { |
483 | 536 | /* Received a packet with sequence numbers. If we're the LNS, |
484 | 537 | * check if we sre sending sequence numbers and if not, |
... | ... | @@ -489,6 +542,7 @@ |
489 | 542 | "%s: requested to enable seq numbers by LNS\n", |
490 | 543 | session->name); |
491 | 544 | session->send_seq = -1; |
545 | + l2tp_session_set_header_len(session, tunnel->version); | |
492 | 546 | } |
493 | 547 | } else { |
494 | 548 | /* No sequence numbers. |
... | ... | @@ -512,6 +566,7 @@ |
512 | 566 | "%s: requested to disable seq numbers by LNS\n", |
513 | 567 | session->name); |
514 | 568 | session->send_seq = 0; |
569 | + l2tp_session_set_header_len(session, tunnel->version); | |
515 | 570 | } else if (session->send_seq) { |
516 | 571 | PRINTK(session->debug, L2TP_MSG_SEQ, KERN_WARNING, |
517 | 572 | "%s: recv data has no seq numbers when required. " |
... | ... | @@ -521,11 +576,19 @@ |
521 | 576 | } |
522 | 577 | } |
523 | 578 | |
524 | - /* If offset bit set, skip it. */ | |
525 | - if (hdrflags & L2TP_HDRFLAG_O) { | |
526 | - offset = ntohs(*(__be16 *)ptr); | |
527 | - ptr += 2 + offset; | |
528 | - } | |
579 | + /* Session data offset is handled differently for L2TPv2 and | |
580 | + * L2TPv3. For L2TPv2, there is an optional 16-bit value in | |
581 | + * the header. For L2TPv3, the offset is negotiated using AVPs | |
582 | + * in the session setup control protocol. | |
583 | + */ | |
584 | + if (tunnel->version == L2TP_HDR_VER_2) { | |
585 | + /* If offset bit set, skip it. */ | |
586 | + if (hdrflags & L2TP_HDRFLAG_O) { | |
587 | + offset = ntohs(*(__be16 *)ptr); | |
588 | + ptr += 2 + offset; | |
589 | + } | |
590 | + } else | |
591 | + ptr += session->offset; | |
529 | 592 | |
530 | 593 | offset = ptr - optr; |
531 | 594 | if (!pskb_may_pull(skb, offset)) |
... | ... | @@ -564,8 +627,8 @@ |
564 | 627 | if (L2TP_SKB_CB(skb)->ns != session->nr) { |
565 | 628 | session->stats.rx_seq_discards++; |
566 | 629 | PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, |
567 | - "%s: oos pkt %hu len %d discarded, " | |
568 | - "waiting for %hu, reorder_q_len=%d\n", | |
630 | + "%s: oos pkt %u len %d discarded, " | |
631 | + "waiting for %u, reorder_q_len=%d\n", | |
569 | 632 | session->name, L2TP_SKB_CB(skb)->ns, |
570 | 633 | L2TP_SKB_CB(skb)->length, session->nr, |
571 | 634 | skb_queue_len(&session->reorder_q)); |
... | ... | @@ -586,7 +649,7 @@ |
586 | 649 | |
587 | 650 | l2tp_session_dec_refcount(session); |
588 | 651 | |
589 | - return 0; | |
652 | + return; | |
590 | 653 | |
591 | 654 | discard: |
592 | 655 | session->stats.rx_errors++; |
593 | 656 | |
... | ... | @@ -596,7 +659,112 @@ |
596 | 659 | (*session->deref)(session); |
597 | 660 | |
598 | 661 | l2tp_session_dec_refcount(session); |
662 | +} | |
663 | +EXPORT_SYMBOL(l2tp_recv_common); | |
599 | 664 | |
665 | +/* Internal UDP receive frame. Do the real work of receiving an L2TP data frame | |
666 | + * here. The skb is not on a list when we get here. | |
667 | + * Returns 0 if the packet was a data packet and was successfully passed on. | |
668 | + * Returns 1 if the packet was not a good data packet and could not be | |
669 | + * forwarded. All such packets are passed up to userspace to deal with. | |
670 | + */ | |
671 | +int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |
672 | + int (*payload_hook)(struct sk_buff *skb)) | |
673 | +{ | |
674 | + struct l2tp_session *session = NULL; | |
675 | + unsigned char *ptr, *optr; | |
676 | + u16 hdrflags; | |
677 | + u32 tunnel_id, session_id; | |
678 | + int offset; | |
679 | + u16 version; | |
680 | + int length; | |
681 | + | |
682 | + if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) | |
683 | + goto discard_bad_csum; | |
684 | + | |
685 | + /* UDP always verifies the packet length. */ | |
686 | + __skb_pull(skb, sizeof(struct udphdr)); | |
687 | + | |
688 | + /* Short packet? */ | |
689 | + if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) { | |
690 | + PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
691 | + "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); | |
692 | + goto error; | |
693 | + } | |
694 | + | |
695 | + /* Point to L2TP header */ | |
696 | + optr = ptr = skb->data; | |
697 | + | |
698 | + /* Trace packet contents, if enabled */ | |
699 | + if (tunnel->debug & L2TP_MSG_DATA) { | |
700 | + length = min(32u, skb->len); | |
701 | + if (!pskb_may_pull(skb, length)) | |
702 | + goto error; | |
703 | + | |
704 | + printk(KERN_DEBUG "%s: recv: ", tunnel->name); | |
705 | + | |
706 | + offset = 0; | |
707 | + do { | |
708 | + printk(" %02X", ptr[offset]); | |
709 | + } while (++offset < length); | |
710 | + | |
711 | + printk("\n"); | |
712 | + } | |
713 | + | |
714 | + /* Get L2TP header flags */ | |
715 | + hdrflags = ntohs(*(__be16 *) ptr); | |
716 | + | |
717 | + /* Check protocol version */ | |
718 | + version = hdrflags & L2TP_HDR_VER_MASK; | |
719 | + if (version != tunnel->version) { | |
720 | + PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
721 | + "%s: recv protocol version mismatch: got %d expected %d\n", | |
722 | + tunnel->name, version, tunnel->version); | |
723 | + goto error; | |
724 | + } | |
725 | + | |
726 | + /* Get length of L2TP packet */ | |
727 | + length = skb->len; | |
728 | + | |
729 | + /* If type is control packet, it is handled by userspace. */ | |
730 | + if (hdrflags & L2TP_HDRFLAG_T) { | |
731 | + PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG, | |
732 | + "%s: recv control packet, len=%d\n", tunnel->name, length); | |
733 | + goto error; | |
734 | + } | |
735 | + | |
736 | + /* Skip flags */ | |
737 | + ptr += 2; | |
738 | + | |
739 | + if (tunnel->version == L2TP_HDR_VER_2) { | |
740 | + /* If length is present, skip it */ | |
741 | + if (hdrflags & L2TP_HDRFLAG_L) | |
742 | + ptr += 2; | |
743 | + | |
744 | + /* Extract tunnel and session ID */ | |
745 | + tunnel_id = ntohs(*(__be16 *) ptr); | |
746 | + ptr += 2; | |
747 | + session_id = ntohs(*(__be16 *) ptr); | |
748 | + ptr += 2; | |
749 | + } else { | |
750 | + ptr += 2; /* skip reserved bits */ | |
751 | + tunnel_id = tunnel->tunnel_id; | |
752 | + session_id = ntohl(*(__be32 *) ptr); | |
753 | + ptr += 4; | |
754 | + } | |
755 | + | |
756 | + /* Find the session context */ | |
757 | + session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); | |
758 | + if (!session) { | |
759 | + /* Not found? Pass to userspace to deal with */ | |
760 | + PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO, | |
761 | + "%s: no session found (%u/%u). Passing up.\n", | |
762 | + tunnel->name, tunnel_id, session_id); | |
763 | + goto error; | |
764 | + } | |
765 | + | |
766 | + l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); | |
767 | + | |
600 | 768 | return 0; |
601 | 769 | |
602 | 770 | discard_bad_csum: |
603 | 771 | |
604 | 772 | |
... | ... | @@ -651,11 +819,11 @@ |
651 | 819 | |
652 | 820 | /* Build an L2TP header for the session into the buffer provided. |
653 | 821 | */ |
654 | -static void l2tp_build_l2tpv2_header(struct l2tp_tunnel *tunnel, | |
655 | - struct l2tp_session *session, | |
656 | - void *buf) | |
822 | +static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) | |
657 | 823 | { |
824 | + struct l2tp_tunnel *tunnel = session->tunnel; | |
658 | 825 | __be16 *bufp = buf; |
826 | + __be16 *optr = buf; | |
659 | 827 | u16 flags = L2TP_HDR_VER_2; |
660 | 828 | u32 tunnel_id = tunnel->peer_tunnel_id; |
661 | 829 | u32 session_id = session->peer_session_id; |
662 | 830 | |
663 | 831 | |
664 | 832 | |
665 | 833 | |
666 | 834 | |
667 | 835 | |
... | ... | @@ -671,19 +839,51 @@ |
671 | 839 | *bufp++ = htons(session->ns); |
672 | 840 | *bufp++ = 0; |
673 | 841 | session->ns++; |
842 | + session->ns &= 0xffff; | |
674 | 843 | PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, |
675 | - "%s: updated ns to %hu\n", session->name, session->ns); | |
844 | + "%s: updated ns to %u\n", session->name, session->ns); | |
676 | 845 | } |
846 | + | |
847 | + return bufp - optr; | |
677 | 848 | } |
678 | 849 | |
679 | -void l2tp_build_l2tp_header(struct l2tp_session *session, void *buf) | |
850 | +static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) | |
680 | 851 | { |
681 | - struct l2tp_tunnel *tunnel = session->tunnel; | |
852 | + char *bufp = buf; | |
853 | + char *optr = bufp; | |
854 | + u16 flags = L2TP_HDR_VER_3; | |
682 | 855 | |
683 | - BUG_ON(tunnel->version != L2TP_HDR_VER_2); | |
684 | - l2tp_build_l2tpv2_header(tunnel, session, buf); | |
856 | + /* Setup L2TP header. */ | |
857 | + *((__be16 *) bufp) = htons(flags); | |
858 | + bufp += 2; | |
859 | + *((__be16 *) bufp) = 0; | |
860 | + bufp += 2; | |
861 | + *((__be32 *) bufp) = htonl(session->peer_session_id); | |
862 | + bufp += 4; | |
863 | + if (session->cookie_len) { | |
864 | + memcpy(bufp, &session->cookie[0], session->cookie_len); | |
865 | + bufp += session->cookie_len; | |
866 | + } | |
867 | + if (session->l2specific_len) { | |
868 | + if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) { | |
869 | + u32 l2h = 0; | |
870 | + if (session->send_seq) { | |
871 | + l2h = 0x40000000 | session->ns; | |
872 | + session->ns++; | |
873 | + session->ns &= 0xffffff; | |
874 | + PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG, | |
875 | + "%s: updated ns to %u\n", session->name, session->ns); | |
876 | + } | |
877 | + | |
878 | + *((__be32 *) bufp) = htonl(l2h); | |
879 | + } | |
880 | + bufp += session->l2specific_len; | |
881 | + } | |
882 | + if (session->offset) | |
883 | + bufp += session->offset; | |
884 | + | |
885 | + return bufp - optr; | |
685 | 886 | } |
686 | -EXPORT_SYMBOL_GPL(l2tp_build_l2tp_header); | |
687 | 887 | |
688 | 888 | int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len) |
689 | 889 | { |
... | ... | @@ -694,7 +894,7 @@ |
694 | 894 | /* Debug */ |
695 | 895 | if (session->send_seq) |
696 | 896 | PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG, |
697 | - "%s: send %Zd bytes, ns=%hu\n", session->name, | |
897 | + "%s: send %Zd bytes, ns=%u\n", session->name, | |
698 | 898 | data_len, session->ns - 1); |
699 | 899 | else |
700 | 900 | PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG, |
... | ... | @@ -780,7 +980,7 @@ |
780 | 980 | skb->truesize += new_headroom - old_headroom; |
781 | 981 | |
782 | 982 | /* Setup L2TP header */ |
783 | - l2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); | |
983 | + session->build_header(session, __skb_push(skb, hdr_len)); | |
784 | 984 | udp_len = sizeof(struct udphdr) + hdr_len + data_len; |
785 | 985 | |
786 | 986 | /* Setup UDP header */ |
... | ... | @@ -791,7 +991,6 @@ |
791 | 991 | uh->source = inet->inet_sport; |
792 | 992 | uh->dest = inet->inet_dport; |
793 | 993 | uh->len = htons(udp_len); |
794 | - | |
795 | 994 | uh->check = 0; |
796 | 995 | |
797 | 996 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
... | ... | @@ -911,6 +1110,14 @@ |
911 | 1110 | |
912 | 1111 | write_unlock_bh(&tunnel->hlist_lock); |
913 | 1112 | |
1113 | + if (tunnel->version != L2TP_HDR_VER_2) { | |
1114 | + struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | |
1115 | + | |
1116 | + write_lock_bh(&pn->l2tp_session_hlist_lock); | |
1117 | + hlist_del_init(&session->global_hlist); | |
1118 | + write_unlock_bh(&pn->l2tp_session_hlist_lock); | |
1119 | + } | |
1120 | + | |
914 | 1121 | if (session->session_close != NULL) |
915 | 1122 | (*session->session_close)(session); |
916 | 1123 | |
... | ... | @@ -997,9 +1204,6 @@ |
997 | 1204 | goto err; |
998 | 1205 | } |
999 | 1206 | |
1000 | - if (version != L2TP_HDR_VER_2) | |
1001 | - goto err; | |
1002 | - | |
1003 | 1207 | tunnel = kzalloc(sizeof(struct l2tp_tunnel), GFP_KERNEL); |
1004 | 1208 | if (tunnel == NULL) { |
1005 | 1209 | err = -ENOMEM; |
... | ... | @@ -1077,6 +1281,15 @@ |
1077 | 1281 | hlist_del_init(&session->hlist); |
1078 | 1282 | write_unlock_bh(&tunnel->hlist_lock); |
1079 | 1283 | |
1284 | + /* Unlink from the global hash if not L2TPv2 */ | |
1285 | + if (tunnel->version != L2TP_HDR_VER_2) { | |
1286 | + struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | |
1287 | + | |
1288 | + write_lock_bh(&pn->l2tp_session_hlist_lock); | |
1289 | + hlist_del_init(&session->global_hlist); | |
1290 | + write_unlock_bh(&pn->l2tp_session_hlist_lock); | |
1291 | + } | |
1292 | + | |
1080 | 1293 | if (session->session_id != 0) |
1081 | 1294 | atomic_dec(&l2tp_session_count); |
1082 | 1295 | |
... | ... | @@ -1095,6 +1308,22 @@ |
1095 | 1308 | } |
1096 | 1309 | EXPORT_SYMBOL_GPL(l2tp_session_free); |
1097 | 1310 | |
1311 | +/* We come here whenever a session's send_seq, cookie_len or | |
1312 | + * l2specific_len parameters are set. | |
1313 | + */ | |
1314 | +void l2tp_session_set_header_len(struct l2tp_session *session, int version) | |
1315 | +{ | |
1316 | + if (version == L2TP_HDR_VER_2) { | |
1317 | + session->hdr_len = 6; | |
1318 | + if (session->send_seq) | |
1319 | + session->hdr_len += 4; | |
1320 | + } else { | |
1321 | + session->hdr_len = 8 + session->cookie_len + session->l2specific_len + session->offset; | |
1322 | + } | |
1323 | + | |
1324 | +} | |
1325 | +EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); | |
1326 | + | |
1098 | 1327 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) |
1099 | 1328 | { |
1100 | 1329 | struct l2tp_session *session; |
... | ... | @@ -1106,6 +1335,7 @@ |
1106 | 1335 | |
1107 | 1336 | session->session_id = session_id; |
1108 | 1337 | session->peer_session_id = peer_session_id; |
1338 | + session->nr = 1; | |
1109 | 1339 | |
1110 | 1340 | sprintf(&session->name[0], "sess %u/%u", |
1111 | 1341 | tunnel->tunnel_id, session->session_id); |
1112 | 1342 | |
1113 | 1343 | |
1114 | 1344 | |
1115 | 1345 | |
... | ... | @@ -1113,20 +1343,36 @@ |
1113 | 1343 | skb_queue_head_init(&session->reorder_q); |
1114 | 1344 | |
1115 | 1345 | INIT_HLIST_NODE(&session->hlist); |
1346 | + INIT_HLIST_NODE(&session->global_hlist); | |
1116 | 1347 | |
1117 | 1348 | /* Inherit debug options from tunnel */ |
1118 | 1349 | session->debug = tunnel->debug; |
1119 | 1350 | |
1120 | 1351 | if (cfg) { |
1352 | + session->pwtype = cfg->pw_type; | |
1121 | 1353 | session->debug = cfg->debug; |
1122 | - session->hdr_len = cfg->hdr_len; | |
1123 | 1354 | session->mtu = cfg->mtu; |
1124 | 1355 | session->mru = cfg->mru; |
1125 | 1356 | session->send_seq = cfg->send_seq; |
1126 | 1357 | session->recv_seq = cfg->recv_seq; |
1127 | 1358 | session->lns_mode = cfg->lns_mode; |
1359 | + session->reorder_timeout = cfg->reorder_timeout; | |
1360 | + session->offset = cfg->offset; | |
1361 | + session->l2specific_type = cfg->l2specific_type; | |
1362 | + session->l2specific_len = cfg->l2specific_len; | |
1363 | + session->cookie_len = cfg->cookie_len; | |
1364 | + memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len); | |
1365 | + session->peer_cookie_len = cfg->peer_cookie_len; | |
1366 | + memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len); | |
1128 | 1367 | } |
1129 | 1368 | |
1369 | + if (tunnel->version == L2TP_HDR_VER_2) | |
1370 | + session->build_header = l2tp_build_l2tpv2_header; | |
1371 | + else | |
1372 | + session->build_header = l2tp_build_l2tpv3_header; | |
1373 | + | |
1374 | + l2tp_session_set_header_len(session, tunnel->version); | |
1375 | + | |
1130 | 1376 | /* Bump the reference count. The session context is deleted |
1131 | 1377 | * only when this drops to zero. |
1132 | 1378 | */ |
... | ... | @@ -1142,6 +1388,16 @@ |
1142 | 1388 | l2tp_session_id_hash(tunnel, session_id)); |
1143 | 1389 | write_unlock_bh(&tunnel->hlist_lock); |
1144 | 1390 | |
1391 | + /* And to the global session list if L2TPv3 */ | |
1392 | + if (tunnel->version != L2TP_HDR_VER_2) { | |
1393 | + struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | |
1394 | + | |
1395 | + write_lock_bh(&pn->l2tp_session_hlist_lock); | |
1396 | + hlist_add_head(&session->global_hlist, | |
1397 | + l2tp_session_id_hash_2(pn, session_id)); | |
1398 | + write_unlock_bh(&pn->l2tp_session_hlist_lock); | |
1399 | + } | |
1400 | + | |
1145 | 1401 | /* Ignore management session in session count value */ |
1146 | 1402 | if (session->session_id != 0) |
1147 | 1403 | atomic_inc(&l2tp_session_count); |
... | ... | @@ -1159,6 +1415,7 @@ |
1159 | 1415 | { |
1160 | 1416 | struct l2tp_net *pn; |
1161 | 1417 | int err; |
1418 | + int hash; | |
1162 | 1419 | |
1163 | 1420 | pn = kzalloc(sizeof(*pn), GFP_KERNEL); |
1164 | 1421 | if (!pn) |
... | ... | @@ -1166,6 +1423,11 @@ |
1166 | 1423 | |
1167 | 1424 | INIT_LIST_HEAD(&pn->l2tp_tunnel_list); |
1168 | 1425 | rwlock_init(&pn->l2tp_tunnel_list_lock); |
1426 | + | |
1427 | + for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) | |
1428 | + INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]); | |
1429 | + | |
1430 | + rwlock_init(&pn->l2tp_session_hlist_lock); | |
1169 | 1431 | |
1170 | 1432 | err = net_assign_generic(net, l2tp_net_id, pn); |
1171 | 1433 | if (err) |
net/l2tp/l2tp_core.h
... | ... | @@ -15,9 +15,14 @@ |
15 | 15 | #define L2TP_TUNNEL_MAGIC 0x42114DDA |
16 | 16 | #define L2TP_SESSION_MAGIC 0x0C04EB7D |
17 | 17 | |
18 | +/* Per tunnel, session hash table size */ | |
18 | 19 | #define L2TP_HASH_BITS 4 |
19 | 20 | #define L2TP_HASH_SIZE (1 << L2TP_HASH_BITS) |
20 | 21 | |
22 | +/* System-wide, session hash table size */ | |
23 | +#define L2TP_HASH_BITS_2 8 | |
24 | +#define L2TP_HASH_SIZE_2 (1 << L2TP_HASH_BITS_2) | |
25 | + | |
21 | 26 | /* Debug message categories for the DEBUG socket option */ |
22 | 27 | enum { |
23 | 28 | L2TP_MSG_DEBUG = (1 << 0), /* verbose debug (if |
... | ... | @@ -28,6 +33,21 @@ |
28 | 33 | L2TP_MSG_DATA = (1 << 3), /* data packets */ |
29 | 34 | }; |
30 | 35 | |
36 | +enum l2tp_pwtype { | |
37 | + L2TP_PWTYPE_NONE = 0x0000, | |
38 | + L2TP_PWTYPE_ETH_VLAN = 0x0004, | |
39 | + L2TP_PWTYPE_ETH = 0x0005, | |
40 | + L2TP_PWTYPE_PPP = 0x0007, | |
41 | + L2TP_PWTYPE_PPP_AC = 0x0008, | |
42 | + L2TP_PWTYPE_IP = 0x000b, | |
43 | + __L2TP_PWTYPE_MAX | |
44 | +}; | |
45 | + | |
46 | +enum l2tp_l2spec_type { | |
47 | + L2TP_L2SPECTYPE_NONE, | |
48 | + L2TP_L2SPECTYPE_DEFAULT, | |
49 | +}; | |
50 | + | |
31 | 51 | struct sk_buff; |
32 | 52 | |
33 | 53 | struct l2tp_stats { |
... | ... | @@ -39,6 +59,7 @@ |
39 | 59 | u64 rx_seq_discards; |
40 | 60 | u64 rx_oos_packets; |
41 | 61 | u64 rx_errors; |
62 | + u64 rx_cookie_discards; | |
42 | 63 | }; |
43 | 64 | |
44 | 65 | struct l2tp_tunnel; |
... | ... | @@ -47,6 +68,7 @@ |
47 | 68 | * packets and transmit outgoing ones. |
48 | 69 | */ |
49 | 70 | struct l2tp_session_cfg { |
71 | + enum l2tp_pwtype pw_type; | |
50 | 72 | unsigned data_seq:2; /* data sequencing level |
51 | 73 | * 0 => none, 1 => IP only, |
52 | 74 | * 2 => all |
53 | 75 | |
... | ... | @@ -60,12 +82,17 @@ |
60 | 82 | * control of LNS. */ |
61 | 83 | int debug; /* bitmask of debug message |
62 | 84 | * categories */ |
63 | - int offset; /* offset to payload */ | |
85 | + u16 offset; /* offset to payload */ | |
86 | + u16 l2specific_len; /* Layer 2 specific length */ | |
87 | + u16 l2specific_type; /* Layer 2 specific type */ | |
88 | + u8 cookie[8]; /* optional cookie */ | |
89 | + int cookie_len; /* 0, 4 or 8 bytes */ | |
90 | + u8 peer_cookie[8]; /* peer's cookie */ | |
91 | + int peer_cookie_len; /* 0, 4 or 8 bytes */ | |
64 | 92 | int reorder_timeout; /* configured reorder timeout |
65 | 93 | * (in jiffies) */ |
66 | 94 | int mtu; |
67 | 95 | int mru; |
68 | - int hdr_len; | |
69 | 96 | }; |
70 | 97 | |
71 | 98 | struct l2tp_session { |
... | ... | @@ -76,8 +103,17 @@ |
76 | 103 | * context */ |
77 | 104 | u32 session_id; |
78 | 105 | u32 peer_session_id; |
79 | - u16 nr; /* session NR state (receive) */ | |
80 | - u16 ns; /* session NR state (send) */ | |
106 | + u8 cookie[8]; | |
107 | + int cookie_len; | |
108 | + u8 peer_cookie[8]; | |
109 | + int peer_cookie_len; | |
110 | + u16 offset; /* offset from end of L2TP header | |
111 | + to beginning of data */ | |
112 | + u16 l2specific_len; | |
113 | + u16 l2specific_type; | |
114 | + u16 hdr_len; | |
115 | + u32 nr; /* session NR state (receive) */ | |
116 | + u32 ns; /* session NR state (send) */ | |
81 | 117 | struct sk_buff_head reorder_q; /* receive reorder queue */ |
82 | 118 | struct hlist_node hlist; /* Hash list node */ |
83 | 119 | atomic_t ref_count; |
84 | 120 | |
85 | 121 | |
... | ... | @@ -100,9 +136,11 @@ |
100 | 136 | * (in jiffies) */ |
101 | 137 | int mtu; |
102 | 138 | int mru; |
103 | - int hdr_len; | |
139 | + enum l2tp_pwtype pwtype; | |
104 | 140 | struct l2tp_stats stats; |
141 | + struct hlist_node global_hlist; /* Global hash list node */ | |
105 | 142 | |
143 | + int (*build_header)(struct l2tp_session *session, void *buf); | |
106 | 144 | void (*recv_skb)(struct l2tp_session *session, struct sk_buff *skb, int data_len); |
107 | 145 | void (*session_close)(struct l2tp_session *session); |
108 | 146 | void (*ref)(struct l2tp_session *session); |
... | ... | @@ -132,7 +170,6 @@ |
132 | 170 | char name[20]; /* for logging */ |
133 | 171 | int debug; /* bitmask of debug message |
134 | 172 | * categories */ |
135 | - int hdr_len; | |
136 | 173 | struct l2tp_stats stats; |
137 | 174 | |
138 | 175 | struct list_head list; /* Keep a list of all tunnels */ |
... | ... | @@ -178,7 +215,7 @@ |
178 | 215 | return tunnel; |
179 | 216 | } |
180 | 217 | |
181 | -extern struct l2tp_session *l2tp_session_find(struct l2tp_tunnel *tunnel, u32 session_id); | |
218 | +extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id); | |
182 | 219 | extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); |
183 | 220 | extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); |
184 | 221 | extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); |
185 | 222 | |
186 | 223 | |
... | ... | @@ -187,14 +224,15 @@ |
187 | 224 | extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); |
188 | 225 | extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); |
189 | 226 | extern void l2tp_session_free(struct l2tp_session *session); |
227 | +extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); | |
190 | 228 | extern int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, int (*payload_hook)(struct sk_buff *skb)); |
191 | 229 | extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb); |
192 | 230 | |
193 | -extern void l2tp_build_l2tp_header(struct l2tp_session *session, void *buf); | |
194 | 231 | extern int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len); |
195 | 232 | extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len); |
196 | 233 | extern void l2tp_tunnel_destruct(struct sock *sk); |
197 | 234 | extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); |
235 | +extern void l2tp_session_set_header_len(struct l2tp_session *session, int version); | |
198 | 236 | |
199 | 237 | /* Tunnel reference counts. Incremented per session that is added to |
200 | 238 | * the tunnel. |
net/l2tp/l2tp_ppp.c
... | ... | @@ -670,7 +670,7 @@ |
670 | 670 | |
671 | 671 | /* Check that this session doesn't already exist */ |
672 | 672 | error = -EEXIST; |
673 | - session = l2tp_session_find(tunnel, sp->pppol2tp.s_session); | |
673 | + session = l2tp_session_find(sock_net(sk), tunnel, sp->pppol2tp.s_session); | |
674 | 674 | if (session != NULL) |
675 | 675 | goto end; |
676 | 676 | |
... | ... | @@ -678,7 +678,6 @@ |
678 | 678 | * headers. |
679 | 679 | */ |
680 | 680 | cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
681 | - cfg.hdr_len = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; | |
682 | 681 | cfg.debug = tunnel->debug; |
683 | 682 | |
684 | 683 | /* Allocate and initialize a new session context. */ |
... | ... | @@ -999,7 +998,7 @@ |
999 | 998 | if (stats.session_id != 0) { |
1000 | 999 | /* resend to session ioctl handler */ |
1001 | 1000 | struct l2tp_session *session = |
1002 | - l2tp_session_find(tunnel, stats.session_id); | |
1001 | + l2tp_session_find(sock_net(sk), tunnel, stats.session_id); | |
1003 | 1002 | if (session != NULL) |
1004 | 1003 | err = pppol2tp_session_ioctl(session, cmd, arg); |
1005 | 1004 | else |
... | ... | @@ -1375,6 +1374,8 @@ |
1375 | 1374 | |
1376 | 1375 | /***************************************************************************** |
1377 | 1376 | * /proc filesystem for debug |
1377 | + * Since the original pppol2tp driver provided /proc/net/pppol2tp for | |
1378 | + * L2TPv2, we dump only L2TPv2 tunnels and sessions here. | |
1378 | 1379 | *****************************************************************************/ |
1379 | 1380 | |
1380 | 1381 | static unsigned int pppol2tp_net_id; |
1381 | 1382 | |
... | ... | @@ -1391,14 +1392,24 @@ |
1391 | 1392 | |
1392 | 1393 | static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) |
1393 | 1394 | { |
1394 | - pd->tunnel = l2tp_tunnel_find_nth(net, pd->tunnel_idx); | |
1395 | - pd->tunnel_idx++; | |
1395 | + for (;;) { | |
1396 | + pd->tunnel = l2tp_tunnel_find_nth(net, pd->tunnel_idx); | |
1397 | + pd->tunnel_idx++; | |
1398 | + | |
1399 | + if (pd->tunnel == NULL) | |
1400 | + break; | |
1401 | + | |
1402 | + /* Ignore L2TPv3 tunnels */ | |
1403 | + if (pd->tunnel->version < 3) | |
1404 | + break; | |
1405 | + } | |
1396 | 1406 | } |
1397 | 1407 | |
1398 | 1408 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) |
1399 | 1409 | { |
1400 | 1410 | pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); |
1401 | 1411 | pd->session_idx++; |
1412 | + | |
1402 | 1413 | if (pd->session == NULL) { |
1403 | 1414 | pd->session_idx = 0; |
1404 | 1415 | pppol2tp_next_tunnel(net, pd); |