l2tp.c revision 1.2 1 1.2 knakahar /* $NetBSD: l2tp.c,v 1.2 2025/09/19 01:20:54 knakahara Exp $ */
2 1.1 knakahar
3 1.1 knakahar /*
4 1.1 knakahar * Copyright (c) 2017 Internet Initiative Japan Inc.
5 1.1 knakahar * All rights reserved.
6 1.1 knakahar *
7 1.1 knakahar * Redistribution and use in source and binary forms, with or without
8 1.1 knakahar * modification, are permitted provided that the following conditions
9 1.1 knakahar * are met:
10 1.1 knakahar * 1. Redistributions of source code must retain the above copyright
11 1.1 knakahar * notice, this list of conditions and the following disclaimer.
12 1.1 knakahar * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 knakahar * notice, this list of conditions and the following disclaimer in the
14 1.1 knakahar * documentation and/or other materials provided with the distribution.
15 1.1 knakahar *
16 1.1 knakahar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 knakahar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 knakahar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 knakahar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 knakahar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 knakahar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 knakahar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 knakahar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 knakahar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 knakahar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 knakahar * POSSIBILITY OF SUCH DAMAGE.
27 1.1 knakahar */
28 1.1 knakahar
29 1.1 knakahar #include <sys/cdefs.h>
30 1.2 knakahar __RCSID("$NetBSD: l2tp.c,v 1.2 2025/09/19 01:20:54 knakahara Exp $");
31 1.1 knakahar
32 1.1 knakahar #include <sys/param.h>
33 1.1 knakahar #include <sys/ioctl.h>
34 1.1 knakahar
35 1.1 knakahar #include <net/if.h>
36 1.1 knakahar #include <net/if_ether.h>
37 1.1 knakahar #include <net/if_l2tp.h>
38 1.1 knakahar
39 1.1 knakahar #include <ctype.h>
40 1.1 knakahar #include <err.h>
41 1.1 knakahar #include <errno.h>
42 1.1 knakahar #include <string.h>
43 1.1 knakahar #include <stdlib.h>
44 1.1 knakahar #include <stdio.h>
45 1.1 knakahar #include <util.h>
46 1.1 knakahar
47 1.1 knakahar #include "env.h"
48 1.1 knakahar #include "extern.h"
49 1.1 knakahar #include "util.h"
50 1.1 knakahar
51 1.1 knakahar static status_func_t status;
52 1.1 knakahar static usage_func_t usage;
53 1.1 knakahar static cmdloop_branch_t branch;
54 1.1 knakahar
55 1.1 knakahar static void l2tp_constructor(void) __attribute__((constructor));
56 1.1 knakahar static void l2tp_status(prop_dictionary_t, prop_dictionary_t);
57 1.1 knakahar
58 1.1 knakahar static int setl2tpsession(prop_dictionary_t, prop_dictionary_t);
59 1.1 knakahar static int deletel2tpsession(prop_dictionary_t, prop_dictionary_t);
60 1.1 knakahar static int setl2tpcookie(prop_dictionary_t, prop_dictionary_t);
61 1.1 knakahar static int deletel2tpcookie(prop_dictionary_t, prop_dictionary_t);
62 1.1 knakahar
63 1.1 knakahar struct pinteger l2tpremotesession = PINTEGER_INITIALIZER1(&l2tpremotesession,
64 1.1 knakahar "remote session id", 0, UINT_MAX, 10, setl2tpsession, "l2tpremotesession",
65 1.1 knakahar &command_root.pb_parser);
66 1.1 knakahar
67 1.1 knakahar struct pinteger l2tplocalsession = PINTEGER_INITIALIZER1(&l2tplocalsession,
68 1.1 knakahar "local session id", 0, UINT_MAX, 10, NULL, "l2tplocalsession",
69 1.1 knakahar &l2tpremotesession.pi_parser);
70 1.1 knakahar
71 1.1 knakahar struct pinteger l2tpremotecookie = PINTEGER_INITIALIZER1(&l2tpremotecookie,
72 1.1 knakahar "remote cookie", INT64_MIN, INT64_MAX, 10, setl2tpcookie, "l2tpremotecookie",
73 1.1 knakahar &command_root.pb_parser);
74 1.1 knakahar
75 1.1 knakahar struct pinteger l2tpremotecookielen = PINTEGER_INITIALIZER1(&l2tpremotecookielen,
76 1.1 knakahar "remote cookie length", 0, UINT16_MAX, 10, NULL, "l2tpremotecookielen",
77 1.1 knakahar &l2tpremotecookie.pi_parser);
78 1.1 knakahar
79 1.1 knakahar struct pinteger l2tplocalcookie = PINTEGER_INITIALIZER1(&l2tplocalcookie,
80 1.1 knakahar "local cookie", INT64_MIN, INT64_MAX, 10, NULL, "l2tplocalcookie",
81 1.1 knakahar &l2tpremotecookielen.pi_parser);
82 1.1 knakahar
83 1.1 knakahar struct pinteger l2tplocalcookielen = PINTEGER_INITIALIZER1(&l2tplocalcookielen,
84 1.1 knakahar "local cookie length", 0, UINT16_MAX, 10, NULL, "l2tplocalcookielen",
85 1.1 knakahar &l2tplocalcookie.pi_parser);
86 1.1 knakahar
87 1.1 knakahar static const struct kwinst l2tpkw[] = {
88 1.1 knakahar {.k_word = "cookie", .k_nextparser = &l2tplocalcookielen.pi_parser}
89 1.1 knakahar ,{.k_word = "deletecookie", .k_exec = deletel2tpcookie,
90 1.1 knakahar .k_nextparser = &command_root.pb_parser}
91 1.1 knakahar ,{.k_word = "session", .k_nextparser = &l2tplocalsession.pi_parser}
92 1.1 knakahar ,{.k_word = "deletesession", .k_exec = deletel2tpsession,
93 1.1 knakahar .k_nextparser = &command_root.pb_parser}
94 1.1 knakahar };
95 1.1 knakahar
96 1.1 knakahar struct pkw l2tp = PKW_INITIALIZER(&l2tp, "l2tp", NULL, NULL,
97 1.1 knakahar l2tpkw, __arraycount(l2tpkw), NULL);
98 1.1 knakahar
99 1.1 knakahar #define L2TP_COOKIE_LOCAL 0
100 1.1 knakahar #define L2TP_COOKIE_REMOTE 1
101 1.1 knakahar
102 1.1 knakahar static int
103 1.1 knakahar checkifname(prop_dictionary_t env)
104 1.1 knakahar {
105 1.1 knakahar const char *ifname;
106 1.1 knakahar
107 1.1 knakahar if ((ifname = getifname(env)) == NULL)
108 1.1 knakahar return 1;
109 1.1 knakahar
110 1.1 knakahar return strncmp(ifname, "l2tp", 4) != 0 ||
111 1.1 knakahar !isdigit((unsigned char)ifname[4]);
112 1.1 knakahar }
113 1.1 knakahar
114 1.1 knakahar static int
115 1.1 knakahar getl2tp(prop_dictionary_t env, struct l2tp_req *l2tpr, bool quiet)
116 1.1 knakahar {
117 1.1 knakahar memset(l2tpr, 0, sizeof(*l2tpr));
118 1.1 knakahar
119 1.1 knakahar if (checkifname(env)) {
120 1.1 knakahar if (quiet)
121 1.1 knakahar return -1;
122 1.1 knakahar errx(EXIT_FAILURE, "valid only with l2tp(4) interfaces");
123 1.1 knakahar }
124 1.1 knakahar
125 1.1 knakahar if (indirect_ioctl(env, SIOCGL2TP, l2tpr) == -1)
126 1.1 knakahar return -1;
127 1.1 knakahar
128 1.1 knakahar return 0;
129 1.1 knakahar }
130 1.1 knakahar
131 1.1 knakahar int
132 1.1 knakahar deletel2tpsession(prop_dictionary_t env, prop_dictionary_t oenv)
133 1.1 knakahar {
134 1.1 knakahar struct l2tp_req l2tpr;
135 1.1 knakahar
136 1.1 knakahar memset(&l2tpr, 0, sizeof(l2tpr));
137 1.1 knakahar
138 1.1 knakahar if (indirect_ioctl(env, SIOCDL2TPSESSION, &l2tpr) == -1)
139 1.1 knakahar return -1;
140 1.1 knakahar
141 1.1 knakahar l2tpr.state = L2TP_STATE_DOWN;
142 1.1 knakahar
143 1.1 knakahar if (indirect_ioctl(env, SIOCSL2TPSTATE, &l2tpr) == -1)
144 1.1 knakahar return -1;
145 1.1 knakahar
146 1.1 knakahar
147 1.1 knakahar return 0;
148 1.1 knakahar }
149 1.1 knakahar
150 1.1 knakahar int
151 1.1 knakahar setl2tpsession(prop_dictionary_t env, prop_dictionary_t oenv)
152 1.1 knakahar {
153 1.1 knakahar struct l2tp_req l2tpr;
154 1.1 knakahar int64_t local_session;
155 1.1 knakahar int64_t remote_session;
156 1.1 knakahar
157 1.1 knakahar memset(&l2tpr, 0, sizeof(l2tpr));
158 1.1 knakahar
159 1.1 knakahar if (!prop_dictionary_get_int64(env, "l2tplocalsession",
160 1.1 knakahar &local_session)) {
161 1.1 knakahar errno = ENOENT;
162 1.1 knakahar return -1;
163 1.1 knakahar }
164 1.1 knakahar
165 1.1 knakahar if (!prop_dictionary_get_int64(env, "l2tpremotesession",
166 1.1 knakahar &remote_session)) {
167 1.1 knakahar errno = ENOENT;
168 1.1 knakahar return -1;
169 1.1 knakahar }
170 1.1 knakahar
171 1.1 knakahar l2tpr.my_sess_id = local_session;
172 1.1 knakahar l2tpr.peer_sess_id = remote_session;
173 1.1 knakahar
174 1.1 knakahar if (indirect_ioctl(env, SIOCSL2TPSESSION, &l2tpr) == -1)
175 1.1 knakahar return -1;
176 1.1 knakahar
177 1.1 knakahar l2tpr.state = L2TP_STATE_UP;
178 1.1 knakahar
179 1.1 knakahar if (indirect_ioctl(env, SIOCSL2TPSTATE, &l2tpr) == -1)
180 1.1 knakahar return -1;
181 1.1 knakahar
182 1.1 knakahar return 0;
183 1.1 knakahar }
184 1.1 knakahar
185 1.1 knakahar int
186 1.1 knakahar deletel2tpcookie(prop_dictionary_t env, prop_dictionary_t oenv)
187 1.1 knakahar {
188 1.1 knakahar struct l2tp_req l2tpr;
189 1.1 knakahar
190 1.1 knakahar memset(&l2tpr, 0, sizeof(l2tpr));
191 1.1 knakahar
192 1.1 knakahar if (indirect_ioctl(env, SIOCDL2TPCOOKIE, &l2tpr) == -1)
193 1.1 knakahar return -1;
194 1.1 knakahar
195 1.1 knakahar return 0;
196 1.1 knakahar }
197 1.1 knakahar
198 1.1 knakahar int
199 1.1 knakahar setl2tpcookie(prop_dictionary_t env, prop_dictionary_t oenv)
200 1.1 knakahar {
201 1.1 knakahar struct l2tp_req l2tpr;
202 1.1 knakahar uint16_t cookielen;
203 1.1 knakahar uint64_t cookie;
204 1.1 knakahar
205 1.1 knakahar memset(&l2tpr, 0, sizeof(l2tpr));
206 1.1 knakahar
207 1.1 knakahar if (!prop_dictionary_get_uint16(env, "l2tplocalcookielen", &cookielen)) {
208 1.1 knakahar errno = ENOENT;
209 1.1 knakahar return -1;
210 1.1 knakahar }
211 1.1 knakahar if (!prop_dictionary_get_uint64(env, "l2tplocalcookie", &cookie)) {
212 1.1 knakahar errno = ENOENT;
213 1.1 knakahar return -1;
214 1.1 knakahar }
215 1.1 knakahar l2tpr.my_cookie_len = cookielen;
216 1.1 knakahar l2tpr.my_cookie = cookie;
217 1.1 knakahar
218 1.1 knakahar if (!prop_dictionary_get_uint16(env, "l2tpremotecookielen", &cookielen)) {
219 1.1 knakahar errno = ENOENT;
220 1.1 knakahar return -1;
221 1.1 knakahar }
222 1.1 knakahar if (!prop_dictionary_get_uint64(env, "l2tpremotecookie", &cookie)) {
223 1.1 knakahar errno = ENOENT;
224 1.1 knakahar return -1;
225 1.1 knakahar }
226 1.1 knakahar l2tpr.peer_cookie_len = cookielen;
227 1.1 knakahar l2tpr.peer_cookie = cookie;
228 1.1 knakahar
229 1.1 knakahar if (indirect_ioctl(env, SIOCSL2TPCOOKIE, &l2tpr) == -1)
230 1.1 knakahar return -1;
231 1.1 knakahar
232 1.1 knakahar return 0;
233 1.1 knakahar }
234 1.1 knakahar
235 1.1 knakahar static void
236 1.1 knakahar l2tp_status(prop_dictionary_t env, prop_dictionary_t oenv)
237 1.1 knakahar {
238 1.1 knakahar struct l2tp_req l2tpr;
239 1.1 knakahar
240 1.1 knakahar if (getl2tp(env, &l2tpr, true) == -1)
241 1.1 knakahar return;
242 1.1 knakahar
243 1.2 knakahar printf("\tl2tp-state: %s\n", l2tpr.state == L2TP_STATE_UP ? "up" : "down");
244 1.2 knakahar
245 1.1 knakahar if (l2tpr.my_sess_id != 0 || l2tpr.peer_sess_id != 0) {
246 1.1 knakahar printf("\tlocal-session-id: %u\n", l2tpr.my_sess_id);
247 1.1 knakahar printf("\tremote-session-id: %u\n", l2tpr.peer_sess_id);
248 1.1 knakahar }
249 1.1 knakahar
250 1.1 knakahar if (l2tpr.my_cookie != 0 || l2tpr.peer_cookie != 0) {
251 1.1 knakahar printf("\tlocal-cookie: %" PRIu64 "\n", l2tpr.my_cookie);
252 1.1 knakahar printf("\tremote-cookie: %" PRIu64 "\n", l2tpr.peer_cookie);
253 1.1 knakahar }
254 1.1 knakahar }
255 1.1 knakahar
256 1.1 knakahar static void
257 1.1 knakahar l2tp_usage(prop_dictionary_t env)
258 1.1 knakahar {
259 1.1 knakahar fprintf(stderr, "\t[ session local-session-id remote-session-id ]\n");
260 1.1 knakahar fprintf(stderr, "\t[ cookie local-cookie-length local-cookie remote-cookie-length remote-cookie ]\n");
261 1.1 knakahar }
262 1.1 knakahar
263 1.1 knakahar static void
264 1.1 knakahar l2tp_constructor(void)
265 1.1 knakahar {
266 1.1 knakahar cmdloop_branch_init(&branch, &l2tp.pk_parser);
267 1.1 knakahar register_cmdloop_branch(&branch);
268 1.1 knakahar status_func_init(&status, l2tp_status);
269 1.1 knakahar usage_func_init(&usage, l2tp_usage);
270 1.1 knakahar register_status(&status);
271 1.1 knakahar register_usage(&usage);
272 1.1 knakahar }
273