0e28606f9ae4caae126f32bcabd49d9ae79ce78e
[ppp.git] / pppd / plugins / pppol2tp / pppol2tp.c
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@svana.org>
10  * Modified by jchapman@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
78 /* Hook provided to allow other plugins to handle ACCM changes */
79 void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
80                                 uint32_t send_accm, uint32_t recv_accm) = NULL;
81
82 /* Hook provided to allow other plugins to handle IP up/down */
83 void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up) = NULL;
84
85 static option_t pppol2tp_options[] = {
86         { "pppol2tp", o_special, &setdevname_pppol2tp,
87           "FD for PPPoL2TP socket", OPT_DEVNAM | OPT_A2STRVAL,
88           &pppol2tp_fd_str },
89         { "pppol2tp_lns_mode", o_bool, &pppol2tp_lns_mode,
90           "PPPoL2TP LNS behavior. Default off.",
91           OPT_PRIO | OPRIO_CFGFILE },
92         { "pppol2tp_send_seq", o_bool, &pppol2tp_send_seq,
93           "PPPoL2TP enable sequence numbers in transmitted data packets. "
94           "Default off.",
95           OPT_PRIO | OPRIO_CFGFILE },
96         { "pppol2tp_recv_seq", o_bool, &pppol2tp_recv_seq,
97           "PPPoL2TP enforce sequence numbers in received data packets. "
98           "Default off.",
99           OPT_PRIO | OPRIO_CFGFILE },
100         { "pppol2tp_reorderto", o_int, &pppol2tp_reorder_timeout,
101           "PPPoL2TP data packet reorder timeout. Default 0 (no reordering).",
102           OPT_PRIO },
103         { "pppol2tp_debug_mask", o_int, &pppol2tp_debug_mask,
104           "PPPoL2TP debug mask. Default: no debug.",
105           OPT_PRIO },
106         { "pppol2tp_ifname", o_string, &pppol2tp_ifname,
107           "Set interface name of PPP interface",
108           OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, 16 },
109         { "pppol2tp_tunnel_id", o_int, &pppol2tp_tunnel_id,
110           "PPPoL2TP tunnel_id.",
111           OPT_PRIO },
112         { "pppol2tp_session_id", o_int, &pppol2tp_session_id,
113           "PPPoL2TP session_id.",
114           OPT_PRIO },
115         { NULL }
116 };
117
118 static int setdevname_pppol2tp(char **argv)
119 {
120         union {
121                 char buffer[128];
122                 struct sockaddr pppol2tp;
123         } s;
124         int len = sizeof(s);
125         char **a;
126         int tmp;
127         int tmp_len = sizeof(tmp);
128
129         if (device_got_set)
130                 return 0;
131
132         if (!int_option(*argv, &pppol2tp_fd))
133                 return 0;
134
135         if(getsockname(pppol2tp_fd, (struct sockaddr *)&s, &len) < 0) {
136                 fatal("Given FD for PPPoL2TP socket invalid (%s)",
137                       strerror(errno));
138         }
139         if(s.pppol2tp.sa_family != AF_PPPOX) {
140                 fatal("Socket of not a PPPoX socket");
141         }
142
143         /* Do a test getsockopt() to ensure that the kernel has the necessary
144          * feature available.
145          */
146         if (getsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
147                        &tmp, &tmp_len) < 0) {
148                 fatal("PPPoL2TP kernel driver not installed");
149         }
150
151         /* Setup option defaults. Compression options are disabled! */
152
153         modem = 0;
154
155         lcp_allowoptions[0].neg_accompression = 1;
156         lcp_wantoptions[0].neg_accompression = 0;
157
158         lcp_allowoptions[0].neg_pcompression = 1;
159         lcp_wantoptions[0].neg_pcompression = 0;
160
161         ccp_allowoptions[0].deflate = 0;
162         ccp_wantoptions[0].deflate = 0;
163
164         ipcp_allowoptions[0].neg_vj = 0;
165         ipcp_wantoptions[0].neg_vj = 0;
166
167         ccp_allowoptions[0].bsd_compress = 0;
168         ccp_wantoptions[0].bsd_compress = 0;
169
170         the_channel = &pppol2tp_channel;
171         device_got_set = 1;
172
173         return 1;
174 }
175
176 static int connect_pppol2tp(void)
177 {
178         if(pppol2tp_fd == -1) {
179                 fatal("No PPPoL2TP FD specified");
180         }
181
182         return pppol2tp_fd;
183 }
184
185 static void disconnect_pppol2tp(void)
186 {
187         if (pppol2tp_fd >= 0) {
188                 close(pppol2tp_fd);
189                 pppol2tp_fd = -1;
190         }
191 }
192
193 static void send_config_pppol2tp(int mtu,
194                               u_int32_t asyncmap,
195                               int pcomp,
196                               int accomp)
197 {
198         struct ifreq ifr;
199         int on = 1;
200         int fd;
201         char reorderto[16];
202         char tid[8];
203         char sid[8];
204
205         if (pppol2tp_ifname[0]) {
206                 struct ifreq ifr;
207                 int fd;
208
209                 fd = socket(AF_INET, SOCK_DGRAM, 0);
210                 if (fd >= 0) {
211                         memset (&ifr, '\0', sizeof (ifr));
212                         strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
213                         strlcpy(ifr.ifr_newname, pppol2tp_ifname,
214                                 sizeof(ifr.ifr_name));
215                         ioctl(fd, SIOCSIFNAME, (caddr_t) &ifr);
216                         strlcpy(ifname, pppol2tp_ifname, 32);
217                         if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
218                                 dbglog("ppp%d: interface name %s",
219                                        ifunit, ifname);
220                         }
221                 }
222                 close(fd);
223         }
224
225         if ((lcp_allowoptions[0].mru > 0) && (mtu > lcp_allowoptions[0].mru)) {
226                 warn("Overriding mtu %d to %d", mtu, lcp_allowoptions[0].mru);
227                 mtu = lcp_allowoptions[0].mru;
228         }
229         netif_set_mtu(ifunit, mtu);
230
231         reorderto[0] = '\0';
232         if (pppol2tp_reorder_timeout > 0)
233                 sprintf(&reorderto[0], "%d ", pppol2tp_reorder_timeout);
234         tid[0] = '\0';
235         if (pppol2tp_tunnel_id > 0)
236                 sprintf(&tid[0], "%hu ", pppol2tp_tunnel_id);
237         sid[0] = '\0';
238         if (pppol2tp_session_id > 0)
239                 sprintf(&sid[0], "%hu ", pppol2tp_session_id);
240
241         dbglog("PPPoL2TP options: %s%s%s%s%s%s%s%s%sdebugmask %d",
242                pppol2tp_recv_seq ? "recvseq " : "",
243                pppol2tp_send_seq ? "sendseq " : "",
244                pppol2tp_lns_mode ? "lnsmode " : "",
245                pppol2tp_reorder_timeout ? "reorderto " : "", reorderto,
246                pppol2tp_tunnel_id ? "tid " : "", tid,
247                pppol2tp_session_id ? "sid " : "", sid,
248                pppol2tp_debug_mask);
249
250         if (pppol2tp_recv_seq)
251                 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ,
252                                &on, sizeof(on)) < 0)
253                         fatal("setsockopt(PPPOL2TP_RECVSEQ): %m");
254         if (pppol2tp_send_seq)
255                 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ,
256                                &on, sizeof(on)) < 0)
257                         fatal("setsockopt(PPPOL2TP_SENDSEQ): %m");
258         if (pppol2tp_lns_mode)
259                 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_LNSMODE,
260                                &on, sizeof(on)) < 0)
261                         fatal("setsockopt(PPPOL2TP_LNSMODE): %m");
262         if (pppol2tp_reorder_timeout)
263                 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO,
264                                &pppol2tp_reorder_timeout,
265                                sizeof(pppol2tp_reorder_timeout)) < 0)
266                         fatal("setsockopt(PPPOL2TP_REORDERTO): %m");
267         if (pppol2tp_debug_mask)
268                 if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
269                                &pppol2tp_debug_mask, sizeof(pppol2tp_debug_mask)) < 0)
270                         fatal("setsockopt(PPPOL2TP_DEBUG): %m");
271 }
272
273 static void recv_config_pppol2tp(int mru,
274                               u_int32_t asyncmap,
275                               int pcomp,
276                               int accomp)
277 {
278         if ((lcp_allowoptions[0].mru > 0) && (mru > lcp_allowoptions[0].mru)) {
279                 warn("Overriding mru %d to mtu value %d", mru,
280                      lcp_allowoptions[0].mru);
281                 mru = lcp_allowoptions[0].mru;
282         }
283         if ((ifunit >= 0) && ioctl(pppol2tp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
284                 error("Couldn't set PPP MRU: %m");
285 }
286
287 /*****************************************************************************
288  * Snoop LCP message exchanges to capture negotiated ACCM values.
289  * When asyncmap values have been seen from both sides, give the values to
290  * L2TP.
291  * This code is derived from Roaring Penguin L2TP.
292  *****************************************************************************/
293
294 static void pppol2tp_lcp_snoop(unsigned char *buf, int len, int incoming)
295 {
296         static bool got_send_accm = 0;
297         static bool got_recv_accm = 0;
298         static uint32_t recv_accm = 0xffffffff;
299         static uint32_t send_accm = 0xffffffff;
300         static bool snooping = 1;
301
302         uint16_t protocol;
303         uint16_t lcp_pkt_len;
304         int opt, opt_len;
305         int reject;
306         unsigned char const *opt_data;
307         uint32_t accm;
308
309         /* Skip HDLC header */
310         buf += 2;
311         len -= 2;
312
313         /* Unreasonably short frame?? */
314         if (len <= 0) return;
315
316         /* Get protocol */
317         if (buf[0] & 0x01) {
318                 /* Compressed protcol field */
319                 protocol = buf[0];
320         } else {
321                 protocol = ((unsigned int) buf[0]) * 256 + buf[1];
322         }
323
324         /* If it's a network protocol, stop snooping */
325         if (protocol <= 0x3fff) {
326                 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
327                         dbglog("Turning off snooping: "
328                                "Network protocol %04x found.",
329                                protocol);
330                 }
331                 snooping = 0;
332                 return;
333         }
334
335         /* If it's not LCP, do not snoop */
336         if (protocol != 0xc021) {
337                 return;
338         }
339
340         /* Skip protocol; go to packet data */
341         buf += 2;
342         len -= 2;
343
344         /* Unreasonably short frame?? */
345         if (len <= 0) return;
346
347         /* Look for Configure-Ack or Configure-Reject code */
348         if (buf[0] != CONFACK && buf[0] != CONFREJ) return;
349
350         reject = (buf[0] == CONFREJ);
351
352         lcp_pkt_len = ((unsigned int) buf[2]) * 256 + buf[3];
353
354         /* Something fishy with length field? */
355         if (lcp_pkt_len > len) return;
356
357         /* Skip to options */
358         len = lcp_pkt_len - 4;
359         buf += 4;
360
361         while (len > 0) {
362                 /* Pull off an option */
363                 opt = buf[0];
364                 opt_len = buf[1];
365                 opt_data = &buf[2];
366                 if (opt_len > len || opt_len < 2) break;
367                 len -= opt_len;
368                 buf += opt_len;
369                 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
370                         dbglog("Found option type %02x; len %d", opt, opt_len);
371                 }
372
373                 /* We are specifically interested in ACCM */
374                 if (opt == CI_ASYNCMAP && opt_len == 0x06) {
375                         if (reject) {
376                                 /* ACCM negotiation REJECTED; use default */
377                                 accm = 0xffffffff;
378                                 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
379                                         dbglog("Rejected ACCM negotiation; "
380                                                "defaulting (%s)",
381                                                incoming ? "incoming" : "outgoing");
382                                 }
383                                 recv_accm = accm;
384                                 send_accm = accm;
385                                 got_recv_accm = 1;
386                                 got_send_accm = 1;
387                         } else {
388                                 memcpy(&accm, opt_data, sizeof(accm));
389                                 if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
390                                         dbglog("Found ACCM of %08x (%s)", accm,
391                                                incoming ? "incoming" : "outgoing");
392                                 }
393                                 if (incoming) {
394                                         recv_accm = accm;
395                                         got_recv_accm = 1;
396                                 } else {
397                                         send_accm = accm;
398                                         got_send_accm = 1;
399                                 }
400                         }
401
402                         if (got_recv_accm && got_send_accm) {
403                                 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
404                                         dbglog("Telling L2TP: Send ACCM = %08x; "
405                                                "Receive ACCM = %08x", send_accm, recv_accm);
406                                 }
407                                 if (pppol2tp_send_accm_hook != NULL) {
408                                         (*pppol2tp_send_accm_hook)(pppol2tp_tunnel_id,
409                                                                    pppol2tp_session_id,
410                                                                    send_accm, recv_accm);
411                                 }
412                                 got_recv_accm = 0;
413                                 got_send_accm = 0;
414                         }
415                 }
416         }
417 }
418
419 static void pppol2tp_lcp_snoop_recv(unsigned char *p, int len)
420 {
421         if (old_snoop_recv_hook != NULL)
422                 (*old_snoop_recv_hook)(p, len);
423         pppol2tp_lcp_snoop(p, len, 1);
424 }
425
426 static void pppol2tp_lcp_snoop_send(unsigned char *p, int len)
427 {
428         if (old_snoop_send_hook != NULL)
429                 (*old_snoop_send_hook)(p, len);
430         pppol2tp_lcp_snoop(p, len, 0);
431 }
432
433 /*****************************************************************************
434  * Interface up/down events
435  *****************************************************************************/
436
437 static void pppol2tp_ip_up(void *opaque, int arg)
438 {
439         /* may get called twice (for IPv4 and IPv6) but the hook handles that well */
440         if (pppol2tp_ip_updown_hook != NULL) {
441                 (*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
442                                            pppol2tp_session_id, 1);
443         }
444 }
445
446 static void pppol2tp_ip_down(void *opaque, int arg)
447 {
448         /* may get called twice (for IPv4 and IPv6) but the hook handles that well */
449         if (pppol2tp_ip_updown_hook != NULL) {
450                 (*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
451                                            pppol2tp_session_id, 0);
452         }
453 }
454
455 /*****************************************************************************
456  * Application init
457  *****************************************************************************/
458
459 static void pppol2tp_check_options(void)
460 {
461         /* Enable LCP snooping for ACCM options only for LNS */
462         if (pppol2tp_lns_mode) {
463                 if ((pppol2tp_tunnel_id == 0) || (pppol2tp_session_id == 0)) {
464                         fatal("tunnel_id/session_id values not specified");
465                 }
466                 if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
467                         dbglog("Enabling LCP snooping");
468                 }
469                 old_snoop_recv_hook = snoop_recv_hook;
470                 old_snoop_send_hook = snoop_send_hook;
471
472                 snoop_recv_hook = pppol2tp_lcp_snoop_recv;
473                 snoop_send_hook = pppol2tp_lcp_snoop_send;
474         }
475 }
476
477 /* Called just before pppd exits.
478  */
479 static void pppol2tp_cleanup(void)
480 {
481         if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
482                 dbglog("pppol2tp: exiting.");
483         }
484         disconnect_pppol2tp();
485 }
486
487 void plugin_init(void)
488 {
489 #if defined(__linux__)
490         extern int new_style_driver;    /* From sys-linux.c */
491         if (!ppp_available() && !new_style_driver)
492                 fatal("Kernel doesn't support ppp_generic - "
493                     "needed for PPPoL2TP");
494 #else
495         fatal("No PPPoL2TP support on this OS");
496 #endif
497         add_options(pppol2tp_options);
498
499         /* Hook up ip up/down notifiers to send indicator to openl2tpd
500          * that the link is up
501          */
502         add_notifier(&ip_up_notifier, pppol2tp_ip_up, NULL);
503         add_notifier(&ip_down_notifier, pppol2tp_ip_down, NULL);
504         add_notifier(&ipv6_up_notifier, pppol2tp_ip_up, NULL);
505         add_notifier(&ipv6_down_notifier, pppol2tp_ip_down, NULL);
506 }
507
508 struct channel pppol2tp_channel = {
509     options: pppol2tp_options,
510     process_extra_options: NULL,
511     check_options: &pppol2tp_check_options,
512     connect: &connect_pppol2tp,
513     disconnect: &disconnect_pppol2tp,
514     establish_ppp: &generic_establish_ppp,
515     disestablish_ppp: &generic_disestablish_ppp,
516     send_config: &send_config_pppol2tp,
517     recv_config: &recv_config_pppol2tp,
518     close: NULL,
519     cleanup: NULL
520 };