pppol2tp.c revision 1.1 1 /* pppol2tp.c - pppd plugin to implement PPPoL2TP protocol
2 * for Linux using kernel pppol2tp support.
3 *
4 * Requires kernel pppol2tp driver which is integrated into the kernel
5 * from 2.6.23 onwards. For earlier kernels, a version can be obtained
6 * from the OpenL2TP project at
7 * http://www.sourceforge.net/projects/openl2tp/
8 *
9 * Original by Martijn van Oosterhout <kleptog (at) svana.org>
10 * Modified by jchapman (at) katalix.com
11 *
12 * Heavily based upon pppoatm.c: original notice follows
13 *
14 * Copyright 2000 Mitchell Blank Jr.
15 * Based in part on work from Jens Axboe and Paul Mackerras.
16 * Updated to ppp-2.4.1 by Bernhard Kaindl
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version
21 * 2 of the License, or (at your option) any later version.
22 */
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include "pppd.h"
28 #include "pathnames.h"
29 #include "fsm.h"
30 #include "lcp.h"
31 #include "ccp.h"
32 #include "ipcp.h"
33 #include <sys/stat.h>
34 #include <net/if.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <signal.h>
39 #include <linux/version.h>
40 #include <linux/sockios.h>
41 #ifndef aligned_u64
42 /* should be defined in sys/types.h */
43 #define aligned_u64 unsigned long long __attribute__((aligned(8)))
44 #endif
45 #include <linux/types.h>
46 #include <linux/if_ether.h>
47 #include <linux/ppp_defs.h>
48 #include <linux/if_ppp.h>
49 #include <linux/if_pppox.h>
50 #include <linux/if_pppol2tp.h>
51
52 /* should be added to system's socket.h... */
53 #ifndef SOL_PPPOL2TP
54 #define SOL_PPPOL2TP 273
55 #endif
56
57 const char pppd_version[] = VERSION;
58
59 static int setdevname_pppol2tp(char **argv);
60
61 static int pppol2tp_fd = -1;
62 static char *pppol2tp_fd_str;
63 static bool pppol2tp_lns_mode = 0;
64 static bool pppol2tp_recv_seq = 0;
65 static bool pppol2tp_send_seq = 0;
66 static int pppol2tp_debug_mask = 0;
67 static int pppol2tp_reorder_timeout = 0;
68 static char pppol2tp_ifname[32] = { 0, };
69 int pppol2tp_tunnel_id = 0;
70 int pppol2tp_session_id = 0;
71
72 static int device_got_set = 0;
73 struct channel pppol2tp_channel;
74
75 static void (*old_snoop_recv_hook)(unsigned char *p, int len) = NULL;
76 static void (*old_snoop_send_hook)(unsigned char *p, int len) = NULL;
77 static void (*old_ip_up_hook)(void) = NULL;
78 static void (*old_ip_down_hook)(void) = NULL;
79
80 /* Hook provided to allow other plugins to handle ACCM changes */
81 void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
82 uint32_t send_accm, uint32_t recv_accm) = NULL;
83
84 /* Hook provided to allow other plugins to handle IP up/down */
85 void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up) = NULL;
86
87 static option_t pppol2tp_options[] = {
88 { "pppol2tp", o_special, &setdevname_pppol2tp,
89 "FD for PPPoL2TP socket", OPT_DEVNAM | OPT_A2STRVAL,
90 &pppol2tp_fd_str },
91 { "pppol2tp_lns_mode", o_bool, &pppol2tp_lns_mode,
92 "PPPoL2TP LNS behavior. Default off.",
93 OPT_PRIO | OPRIO_CFGFILE },
94 { "pppol2tp_send_seq", o_bool, &pppol2tp_send_seq,
95 "PPPoL2TP enable sequence numbers in transmitted data packets. "
96 "Default off.",
97 OPT_PRIO | OPRIO_CFGFILE },
98 { "pppol2tp_recv_seq", o_bool, &pppol2tp_recv_seq,
99 "PPPoL2TP enforce sequence numbers in received data packets. "
100 "Default off.",
101 OPT_PRIO | OPRIO_CFGFILE },
102 { "pppol2tp_reorderto", o_int, &pppol2tp_reorder_timeout,
103 "PPPoL2TP data packet reorder timeout. Default 0 (no reordering).",
104 OPT_PRIO },
105 { "pppol2tp_debug_mask", o_int, &pppol2tp_debug_mask,
106 "PPPoL2TP debug mask. Default: no debug.",
107 OPT_PRIO },
108 { "pppol2tp_ifname", o_string, &pppol2tp_ifname,
109 "Set interface name of PPP interface",
110 OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, 16 },
111 { "pppol2tp_tunnel_id", o_int, &pppol2tp_tunnel_id,
112 "PPPoL2TP tunnel_id.",
113 OPT_PRIO },
114 { "pppol2tp_session_id", o_int, &pppol2tp_session_id,
115 "PPPoL2TP session_id.",
116 OPT_PRIO },
117 { NULL }
118 };
119
120 static int setdevname_pppol2tp(char **argv)
121 {
122 union {
123 char buffer[128];
124 struct sockaddr pppol2tp;
125 } s;
126 int len = sizeof(s);
127 char **a;
128 int tmp;
129 int tmp_len = sizeof(tmp);
130
131 if (device_got_set)
132 return 0;
133
134 if (!int_option(*argv, &pppol2tp_fd))
135 return 0;
136
137 if(getsockname(pppol2tp_fd, (struct sockaddr *)&s, &len) < 0) {
138 fatal("Given FD for PPPoL2TP socket invalid (%s)",
139 strerror(errno));
140 }
141 if(s.pppol2tp.sa_family != AF_PPPOX) {
142 fatal("Socket of not a PPPoX socket");
143 }
144
145 /* Do a test getsockopt() to ensure that the kernel has the necessary
146 * feature available.
147 */
148 if (getsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
149 &tmp, &tmp_len) < 0) {
150 fatal("PPPoL2TP kernel driver not installed");
151 }
152
153 /* Setup option defaults. Compression options are disabled! */
154
155 modem = 0;
156
157 lcp_allowoptions[0].neg_accompression = 1;
158 lcp_wantoptions[0].neg_accompression = 0;
159
160 lcp_allowoptions[0].neg_pcompression = 1;
161 lcp_wantoptions[0].neg_pcompression = 0;
162
163 ccp_allowoptions[0].deflate = 0;
164 ccp_wantoptions[0].deflate = 0;
165
166 ipcp_allowoptions[0].neg_vj = 0;
167 ipcp_wantoptions[0].neg_vj = 0;
168
169 ccp_allowoptions[0].bsd_compress = 0;
170 ccp_wantoptions[0].bsd_compress = 0;
171
172 the_channel = &pppol2tp_channel;
173 device_got_set = 1;
174
175 return 1;
176 }
177
178 static int connect_pppol2tp(void)
179 {
180 if(pppol2tp_fd == -1) {
181 fatal("No PPPoL2TP FD specified");
182 }
183
184 return pppol2tp_fd;
185 }
186
187 static void disconnect_pppol2tp(void)
188 {
189 if (pppol2tp_fd >= 0) {
190 close(pppol2tp_fd);
191 pppol2tp_fd = -1;
192 }
193 }
194
195 static void send_config_pppol2tp(int mtu,
196 u_int32_t asyncmap,
197 int pcomp,
198 int accomp)
199 {
200 struct ifreq ifr;
201 int on = 1;
202 int fd;
203 char reorderto[16];
204 char tid[8];
205 char sid[8];
206
207 if (pppol2tp_ifname[0]) {
208 struct ifreq ifr;
209 int fd;
210
211 fd = socket(AF_INET, SOCK_DGRAM, 0);
212 if (fd >= 0) {
213 memset (&ifr, '\0', sizeof (ifr));
214 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
215 strlcpy(ifr.ifr_newname, pppol2tp_ifname,
216 sizeof(ifr.ifr_name));
217 ioctl(fd, SIOCSIFNAME, (caddr_t) &ifr);
218 strlcpy(ifname, pppol2tp_ifname, 32);
219 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
220 dbglog("ppp%d: interface name %s",
221 ifunit, ifname);
222 }
223 }
224 close(fd);
225 }
226
227 if ((lcp_allowoptions[0].mru > 0) && (mtu > lcp_allowoptions[0].mru)) {
228 warn("Overriding mtu %d to %d", mtu, lcp_allowoptions[0].mru);
229 mtu = lcp_allowoptions[0].mru;
230 }
231 netif_set_mtu(ifunit, mtu);
232
233 reorderto[0] = '\0';
234 if (pppol2tp_reorder_timeout > 0)
235 sprintf(&reorderto[0], "%d ", pppol2tp_reorder_timeout);
236 tid[0] = '\0';
237 if (pppol2tp_tunnel_id > 0)
238 sprintf(&tid[0], "%hu ", pppol2tp_tunnel_id);
239 sid[0] = '\0';
240 if (pppol2tp_session_id > 0)
241 sprintf(&sid[0], "%hu ", pppol2tp_session_id);
242
243 dbglog("PPPoL2TP options: %s%s%s%s%s%s%s%s%sdebugmask %d",
244 pppol2tp_recv_seq ? "recvseq " : "",
245 pppol2tp_send_seq ? "sendseq " : "",
246 pppol2tp_lns_mode ? "lnsmode " : "",
247 pppol2tp_reorder_timeout ? "reorderto " : "", reorderto,
248 pppol2tp_tunnel_id ? "tid " : "", tid,
249 pppol2tp_session_id ? "sid " : "", sid,
250 pppol2tp_debug_mask);
251
252 if (pppol2tp_recv_seq)
253 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ,
254 &on, sizeof(on)) < 0)
255 fatal("setsockopt(PPPOL2TP_RECVSEQ): %m");
256 if (pppol2tp_send_seq)
257 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ,
258 &on, sizeof(on)) < 0)
259 fatal("setsockopt(PPPOL2TP_SENDSEQ): %m");
260 if (pppol2tp_lns_mode)
261 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_LNSMODE,
262 &on, sizeof(on)) < 0)
263 fatal("setsockopt(PPPOL2TP_LNSMODE): %m");
264 if (pppol2tp_reorder_timeout)
265 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO,
266 &pppol2tp_reorder_timeout,
267 sizeof(pppol2tp_reorder_timeout)) < 0)
268 fatal("setsockopt(PPPOL2TP_REORDERTO): %m");
269 if (pppol2tp_debug_mask)
270 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
271 &pppol2tp_debug_mask, sizeof(pppol2tp_debug_mask)) < 0)
272 fatal("setsockopt(PPPOL2TP_DEBUG): %m");
273 }
274
275 static void recv_config_pppol2tp(int mru,
276 u_int32_t asyncmap,
277 int pcomp,
278 int accomp)
279 {
280 if ((lcp_allowoptions[0].mru > 0) && (mru > lcp_allowoptions[0].mru)) {
281 warn("Overriding mru %d to mtu value %d", mru,
282 lcp_allowoptions[0].mru);
283 mru = lcp_allowoptions[0].mru;
284 }
285 if ((ifunit >= 0) && ioctl(pppol2tp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
286 error("Couldn't set PPP MRU: %m");
287 }
288
289 /*****************************************************************************
290 * Snoop LCP message exchanges to capture negotiated ACCM values.
291 * When asyncmap values have been seen from both sides, give the values to
292 * L2TP.
293 * This code is derived from Roaring Penguin L2TP.
294 *****************************************************************************/
295
296 static void pppol2tp_lcp_snoop(unsigned char *buf, int len, int incoming)
297 {
298 static bool got_send_accm = 0;
299 static bool got_recv_accm = 0;
300 static uint32_t recv_accm = 0xffffffff;
301 static uint32_t send_accm = 0xffffffff;
302 static bool snooping = 1;
303
304 uint16_t protocol;
305 uint16_t lcp_pkt_len;
306 int opt, opt_len;
307 int reject;
308 unsigned char const *opt_data;
309 uint32_t accm;
310
311 /* Skip HDLC header */
312 buf += 2;
313 len -= 2;
314
315 /* Unreasonably short frame?? */
316 if (len <= 0) return;
317
318 /* Get protocol */
319 if (buf[0] & 0x01) {
320 /* Compressed protcol field */
321 protocol = buf[0];
322 } else {
323 protocol = ((unsigned int) buf[0]) * 256 + buf[1];
324 }
325
326 /* If it's a network protocol, stop snooping */
327 if (protocol <= 0x3fff) {
328 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
329 dbglog("Turning off snooping: "
330 "Network protocol %04x found.",
331 protocol);
332 }
333 snooping = 0;
334 return;
335 }
336
337 /* If it's not LCP, do not snoop */
338 if (protocol != 0xc021) {
339 return;
340 }
341
342 /* Skip protocol; go to packet data */
343 buf += 2;
344 len -= 2;
345
346 /* Unreasonably short frame?? */
347 if (len <= 0) return;
348
349 /* Look for Configure-Ack or Configure-Reject code */
350 if (buf[0] != CONFACK && buf[0] != CONFREJ) return;
351
352 reject = (buf[0] == CONFREJ);
353
354 lcp_pkt_len = ((unsigned int) buf[2]) * 256 + buf[3];
355
356 /* Something fishy with length field? */
357 if (lcp_pkt_len > len) return;
358
359 /* Skip to options */
360 len = lcp_pkt_len - 4;
361 buf += 4;
362
363 while (len > 0) {
364 /* Pull off an option */
365 opt = buf[0];
366 opt_len = buf[1];
367 opt_data = &buf[2];
368 if (opt_len > len || opt_len < 2) break;
369 len -= opt_len;
370 buf += opt_len;
371 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
372 dbglog("Found option type %02x; len %d", opt, opt_len);
373 }
374
375 /* We are specifically interested in ACCM */
376 if (opt == CI_ASYNCMAP && opt_len == 0x06) {
377 if (reject) {
378 /* ACCM negotiation REJECTED; use default */
379 accm = 0xffffffff;
380 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
381 dbglog("Rejected ACCM negotiation; "
382 "defaulting (%s)",
383 incoming ? "incoming" : "outgoing");
384 }
385 recv_accm = accm;
386 send_accm = accm;
387 got_recv_accm = 1;
388 got_send_accm = 1;
389 } else {
390 memcpy(&accm, opt_data, sizeof(accm));
391 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
392 dbglog("Found ACCM of %08x (%s)", accm,
393 incoming ? "incoming" : "outgoing");
394 }
395 if (incoming) {
396 recv_accm = accm;
397 got_recv_accm = 1;
398 } else {
399 send_accm = accm;
400 got_send_accm = 1;
401 }
402 }
403
404 if (got_recv_accm && got_send_accm) {
405 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
406 dbglog("Telling L2TP: Send ACCM = %08x; "
407 "Receive ACCM = %08x", send_accm, recv_accm);
408 }
409 if (pppol2tp_send_accm_hook != NULL) {
410 (*pppol2tp_send_accm_hook)(pppol2tp_tunnel_id,
411 pppol2tp_session_id,
412 send_accm, recv_accm);
413 }
414 got_recv_accm = 0;
415 got_send_accm = 0;
416 }
417 }
418 }
419 }
420
421 static void pppol2tp_lcp_snoop_recv(unsigned char *p, int len)
422 {
423 if (old_snoop_recv_hook != NULL)
424 (*old_snoop_recv_hook)(p, len);
425 pppol2tp_lcp_snoop(p, len, 1);
426 }
427
428 static void pppol2tp_lcp_snoop_send(unsigned char *p, int len)
429 {
430 if (old_snoop_send_hook != NULL)
431 (*old_snoop_send_hook)(p, len);
432 pppol2tp_lcp_snoop(p, len, 0);
433 }
434
435 /*****************************************************************************
436 * Interface up/down events
437 *****************************************************************************/
438
439 static void pppol2tp_ip_up_hook(void)
440 {
441 if (old_ip_up_hook != NULL)
442 (*old_ip_up_hook)();
443
444 if (pppol2tp_ip_updown_hook != NULL) {
445 (*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
446 pppol2tp_session_id, 1);
447 }
448 }
449
450 static void pppol2tp_ip_down_hook(void)
451 {
452 if (old_ip_down_hook != NULL)
453 (*old_ip_down_hook)();
454
455 if (pppol2tp_ip_updown_hook != NULL) {
456 (*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
457 pppol2tp_session_id, 0);
458 }
459 }
460
461 /*****************************************************************************
462 * Application init
463 *****************************************************************************/
464
465 static void pppol2tp_check_options(void)
466 {
467 /* Enable LCP snooping for ACCM options only for LNS */
468 if (pppol2tp_lns_mode) {
469 if ((pppol2tp_tunnel_id == 0) || (pppol2tp_session_id == 0)) {
470 fatal("tunnel_id/session_id values not specified");
471 }
472 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
473 dbglog("Enabling LCP snooping");
474 }
475 old_snoop_recv_hook = snoop_recv_hook;
476 old_snoop_send_hook = snoop_send_hook;
477
478 snoop_recv_hook = pppol2tp_lcp_snoop_recv;
479 snoop_send_hook = pppol2tp_lcp_snoop_send;
480 }
481
482 /* Hook up ip up/down hooks to send indicator to openl2tpd
483 * that the link is up
484 */
485 old_ip_up_hook = ip_up_hook;
486 ip_up_hook = pppol2tp_ip_up_hook;
487 old_ip_down_hook = ip_down_hook;
488 ip_down_hook = pppol2tp_ip_down_hook;
489 }
490
491 /* Called just before pppd exits.
492 */
493 static void pppol2tp_cleanup(void)
494 {
495 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
496 dbglog("pppol2tp: exiting.");
497 }
498 disconnect_pppol2tp();
499 }
500
501 void plugin_init(void)
502 {
503 #if defined(__linux__)
504 extern int new_style_driver; /* From sys-linux.c */
505 if (!ppp_available() && !new_style_driver)
506 fatal("Kernel doesn't support ppp_generic - "
507 "needed for PPPoL2TP");
508 #else
509 fatal("No PPPoL2TP support on this OS");
510 #endif
511 add_options(pppol2tp_options);
512 }
513
514 struct channel pppol2tp_channel = {
515 options: pppol2tp_options,
516 process_extra_options: NULL,
517 check_options: &pppol2tp_check_options,
518 connect: &connect_pppol2tp,
519 disconnect: &disconnect_pppol2tp,
520 establish_ppp: &generic_establish_ppp,
521 disestablish_ppp: &generic_disestablish_ppp,
522 send_config: &send_config_pppol2tp,
523 recv_config: &recv_config_pppol2tp,
524 close: NULL,
525 cleanup: NULL
526 };
527