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