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