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