1/* 2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/systm.h> 25#include <sys/mbuf.h> 26#include <sys/socket.h> 27#include <sys/syslog.h> 28#include <sys/protosw.h> 29#include <kern/locks.h> 30 31#include <net/if_types.h> 32#include <net/if.h> 33#include <net/route.h> 34#include <netinet/in.h> 35#include <netinet/in_pcb.h> 36#include <netinet/in_systm.h> 37#include <netinet/in_var.h> 38#include <netinet/udp.h> 39 40#include <kern/thread.h> 41#include <kern/task.h> 42#include <kern/kern_types.h> 43#include <kern/sched_prim.h> 44#include <sys/sysctl.h> 45 46#include "l2tpk.h" 47#include "l2tp_rfc.h" 48#include "l2tp_udp.h" 49#include "../../../Family/ppp_domain.h" 50 51 52/* ----------------------------------------------------------------------------- 53Definitions 54----------------------------------------------------------------------------- */ 55 56struct l2tp_udp_thread { 57 thread_t thread; 58 int wakeup; 59 int terminate; 60 struct pppqueue outq; 61 int nbclient; 62 63 lck_mtx_t *mtx; 64} ; 65 66#define L2TP_UDP_MAX_THREADS 16 67#define L2TP_UDP_DEF_OUTQ_SIZE 1024 68 69void l2tp_ip_input(mbuf_t , int len); 70void l2tp_udp_thread_func(struct l2tp_udp_thread *thread_socket); 71kern_return_t thread_terminate(register thread_act_t act); 72int l2tp_udp_init_threads(int nb_threads); 73void l2tp_udp_dispose_threads(); 74#if !TARGET_OS_EMBEDDED 75static int sysctl_nb_threads SYSCTL_HANDLER_ARGS; 76#endif 77 78/* ----------------------------------------------------------------------------- 79Globals 80----------------------------------------------------------------------------- */ 81extern lck_mtx_t *ppp_domain_mutex; 82static struct l2tp_udp_thread *l2tp_udp_threads = 0; 83static int l2tp_udp_thread_outq_size = L2TP_UDP_DEF_OUTQ_SIZE; 84static int l2tp_udp_nb_threads = 0; 85static int l2tp_udp_inited = 0; 86 87static lck_rw_t *l2tp_udp_mtx; 88static lck_attr_t *l2tp_udp_mtx_attr; 89static lck_grp_t *l2tp_udp_mtx_grp; 90static lck_grp_attr_t *l2tp_udp_mtx_grp_attr; 91 92#if !TARGET_OS_EMBEDDED 93SYSCTL_PROC(_net_ppp_l2tp, OID_AUTO, nb_threads, CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_NOAUTO|CTLFLAG_KERN, 94 &l2tp_udp_nb_threads, 0, sysctl_nb_threads, "I", "Number of l2tp output threads 0 - 16"); 95SYSCTL_INT(_net_ppp_l2tp, OID_AUTO, thread_outq_size, CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_NOAUTO|CTLFLAG_KERN, 96 &l2tp_udp_thread_outq_size, 0, "Queue size for each l2tp output thread"); 97#endif 98 99/* ----------------------------------------------------------------------------- 100intialize L2TP/UDP layer 101----------------------------------------------------------------------------- */ 102int l2tp_udp_init() 103{ 104 int err = ENOMEM; 105 106 if (l2tp_udp_inited) 107 return 0; 108 109 // allocate lock group attribute and group for udp the list 110 l2tp_udp_mtx_grp_attr = lck_grp_attr_alloc_init(); 111 LOGNULLFAIL(l2tp_udp_mtx_grp_attr, "l2tp_udp_init: can't alloc mutex group attributes\n"); 112 113 lck_grp_attr_setstat(l2tp_udp_mtx_grp_attr); 114 115 l2tp_udp_mtx_grp = lck_grp_alloc_init("l2tp_udp", l2tp_udp_mtx_grp_attr); 116 LOGNULLFAIL(l2tp_udp_mtx_grp, "l2tp_udp_init: can't alloc mutex group\n"); 117 118 l2tp_udp_mtx_attr = lck_attr_alloc_init(); 119 LOGNULLFAIL(l2tp_udp_mtx_attr, "l2tp_udp_init: can't alloc mutex attributes\n"); 120 121 lck_attr_setdebug(l2tp_udp_mtx_attr); 122 123 l2tp_udp_mtx = lck_rw_alloc_init(l2tp_udp_mtx_grp, l2tp_udp_mtx_attr); 124 LOGNULLFAIL(l2tp_udp_mtx, "l2tp_udp_init: can't alloc mutex\n") 125 126 // init threads 127 err = l2tp_udp_init_threads(0); 128 if (err) 129 goto fail; 130 131#if !TARGET_OS_EMBEDDED 132 sysctl_register_oid(&sysctl__net_ppp_l2tp_nb_threads); 133 sysctl_register_oid(&sysctl__net_ppp_l2tp_thread_outq_size); 134#endif 135 l2tp_udp_inited = 1; 136 137 return 0; 138 139fail: 140 if (l2tp_udp_mtx) { 141 lck_rw_free(l2tp_udp_mtx, l2tp_udp_mtx_grp); 142 l2tp_udp_mtx = 0; 143 } 144 if (l2tp_udp_mtx_attr) { 145 lck_attr_free(l2tp_udp_mtx_attr); 146 l2tp_udp_mtx_attr = 0; 147 } 148 if (l2tp_udp_mtx_grp) { 149 lck_grp_free(l2tp_udp_mtx_grp); 150 l2tp_udp_mtx_grp = 0; 151 } 152 if (l2tp_udp_mtx_grp_attr) { 153 lck_grp_attr_free(l2tp_udp_mtx_grp_attr); 154 l2tp_udp_mtx_grp_attr = 0; 155 } 156 return err; 157} 158 159/* ----------------------------------------------------------------------------- 160dispose L2TP/UDP layer 161----------------------------------------------------------------------------- */ 162int l2tp_udp_dispose() 163{ 164 if (!l2tp_udp_inited) 165 return 0; 166 167#if !TARGET_OS_EMBEDDED 168 sysctl_unregister_oid(&sysctl__net_ppp_l2tp_nb_threads); 169 sysctl_unregister_oid(&sysctl__net_ppp_l2tp_thread_outq_size); 170#endif 171 172 l2tp_udp_dispose_threads(); 173 174 lck_rw_free(l2tp_udp_mtx, l2tp_udp_mtx_grp); 175 l2tp_udp_mtx = 0; 176 lck_attr_free(l2tp_udp_mtx_attr); 177 l2tp_udp_mtx_attr = 0; 178 lck_grp_free(l2tp_udp_mtx_grp); 179 l2tp_udp_mtx_grp = 0; 180 lck_grp_attr_free(l2tp_udp_mtx_grp_attr); 181 l2tp_udp_mtx_grp_attr = 0; 182 183 l2tp_udp_inited = 0; 184 return 0; 185} 186 187#if !TARGET_OS_EMBEDDED 188/* ----------------------------------------------------------------------------- 189sysctl to change the number of threads 190----------------------------------------------------------------------------- */ 191static int sysctl_nb_threads SYSCTL_HANDLER_ARGS 192{ 193 int error, s; 194 195 s = *(int *)oidp->oid_arg1; 196 197 error = sysctl_handle_int(oidp, &s, 0, req); 198 if (error || !req->newptr) 199 return error; 200 201 lck_mtx_lock(ppp_domain_mutex); 202 error = l2tp_udp_init_threads(s); 203 lck_mtx_unlock(ppp_domain_mutex); 204 205 return error; 206} 207#endif 208 209/* ----------------------------------------------------------------------------- 210initialize the worker threads 211----------------------------------------------------------------------------- */ 212int l2tp_udp_init_threads(int nb_threads) 213{ 214 int i; 215 errno_t err; 216 217 if (nb_threads < 0) 218 nb_threads = 0; 219 else 220 if (nb_threads > L2TP_UDP_MAX_THREADS) 221 nb_threads = L2TP_UDP_MAX_THREADS; 222 223 if (l2tp_udp_nb_threads == nb_threads) 224 return 0; 225 226 IOLog("l2tp_udp_init_threads: changing # of threads from %d to %d\n", l2tp_udp_nb_threads, nb_threads); 227 228 l2tp_udp_dispose_threads(); 229 230 if (nb_threads == 0) 231 return 0; 232 233 l2tp_udp_threads = (struct l2tp_udp_thread *)_MALLOC(sizeof(struct l2tp_udp_thread) * nb_threads, M_TEMP, M_WAITOK); 234 if (!l2tp_udp_threads) 235 return ENOMEM; 236 237 bzero(l2tp_udp_threads, sizeof(struct l2tp_udp_thread) * nb_threads); 238 239 for (i = 0; i < nb_threads; i++) { 240 241 err = ENOMEM; 242 243 l2tp_udp_threads[i].mtx = lck_mtx_alloc_init(l2tp_udp_mtx_grp, l2tp_udp_mtx_attr); 244 LOGNULLFAIL(l2tp_udp_threads[i].mtx, "l2tp_udp_init_threads: can't alloc mutex\n"); 245 246 // Start up working thread 247 err = kernel_thread_start((thread_continue_t)l2tp_udp_thread_func, &l2tp_udp_threads[i], &l2tp_udp_threads[i].thread); 248 LOGGOTOFAIL(err, "l2tp_udp_init_threads: kernel_thread_start failed, error %d\n"); 249 250 l2tp_udp_nb_threads++; 251 } 252 253 return 0; 254 255fail: 256 257 if (l2tp_udp_threads[i].mtx) { 258 lck_mtx_free(l2tp_udp_threads[i].mtx, l2tp_udp_mtx_grp); 259 l2tp_udp_threads[i].mtx = 0; 260 } 261 262 l2tp_udp_dispose_threads(); 263 return err; 264} 265 266/* ----------------------------------------------------------------------------- 267dispose threads 268----------------------------------------------------------------------------- */ 269void l2tp_udp_dispose_threads() 270{ 271 int i; 272 273 if (!l2tp_udp_nb_threads) 274 return; 275 276 lck_rw_lock_exclusive(l2tp_udp_mtx); 277 278 for (i = 0; i < l2tp_udp_nb_threads; i++) { 279 280 if (l2tp_udp_threads[i].thread) { 281 282 lck_mtx_lock(l2tp_udp_threads[i].mtx); 283 l2tp_udp_threads[i].terminate = 1; 284 wakeup(&l2tp_udp_threads[i].wakeup); 285 msleep(&l2tp_udp_threads[i].terminate, l2tp_udp_threads[i].mtx, PZERO + 1, "l2tp_udp_dispose_threads", 0); 286 lck_mtx_unlock(l2tp_udp_threads[i].mtx); 287 288 thread_terminate(l2tp_udp_threads[i].thread); 289 thread_deallocate(l2tp_udp_threads[i].thread); 290 291 lck_mtx_free(l2tp_udp_threads[i].mtx, l2tp_udp_mtx_grp); 292 } 293 } 294 295 _FREE(l2tp_udp_threads, M_TEMP); 296 l2tp_udp_nb_threads = 0; 297 298 lck_rw_unlock_exclusive(l2tp_udp_mtx); 299 300} 301 302/* ----------------------------------------------------------------------------- 303callback from udp 304----------------------------------------------------------------------------- */ 305void l2tp_udp_input(socket_t so, void *arg, int waitflag) 306{ 307 mbuf_t mp = 0; 308 size_t recvlen = 1000000000; 309 struct sockaddr from; 310 struct msghdr msg; 311 312 do { 313 314 bzero(&from, sizeof(from)); 315 bzero(&msg, sizeof(msg)); 316 msg.msg_namelen = sizeof(from); 317 msg.msg_name = &from; 318 319 if (sock_receivembuf(so, &msg, &mp, MSG_DONTWAIT, &recvlen) != 0) 320 break; 321 322 if (mp == 0) 323 break; 324 325 lck_mtx_lock(ppp_domain_mutex); 326 l2tp_rfc_lower_input(so, mp, &from); 327 lck_mtx_unlock(ppp_domain_mutex); 328 329 } while (1); 330 331} 332 333/* ----------------------------------------------------------------------------- 334called from ppp_proto when data need to be sent 335----------------------------------------------------------------------------- */ 336int l2tp_udp_output(socket_t so, int thread, mbuf_t m, struct sockaddr* to) 337{ 338 int err = 0; 339 340 if (so == 0 || to == 0) { 341 mbuf_freem(m); 342 return EINVAL; 343 } 344 345 if (thread < 0) 346 goto no_thread; 347 348 lck_rw_lock_shared(l2tp_udp_mtx); 349 if (!l2tp_udp_nb_threads) { 350 lck_rw_unlock_shared(l2tp_udp_mtx); 351 goto no_thread; 352 } 353 354 if (thread >= l2tp_udp_nb_threads) 355 thread %= l2tp_udp_nb_threads; 356 357 if (l2tp_udp_threads[thread].outq.len >= l2tp_udp_thread_outq_size) { 358 lck_rw_unlock_shared(l2tp_udp_mtx); 359 mbuf_free(m); 360 return EBUSY; 361 } 362 363 if ((err = mbuf_prepend(&m, sizeof(socket_t), M_NOWAIT))) { 364 lck_rw_unlock_shared(l2tp_udp_mtx); 365 return err; 366 } 367 368 memcpy(mbuf_data(m), &so, sizeof(so)); 369 sock_retain(so); 370 371 lck_mtx_lock(l2tp_udp_threads[thread].mtx); 372 ppp_enqueue(&l2tp_udp_threads[thread].outq, m); 373 wakeup(&l2tp_udp_threads[thread].wakeup); 374 lck_mtx_unlock(l2tp_udp_threads[thread].mtx); 375 376 lck_rw_unlock_shared(l2tp_udp_mtx); 377 378 return 0; 379 380no_thread: 381 lck_mtx_unlock(ppp_domain_mutex); 382 err = sock_sendmbuf(so, 0, m, MSG_DONTWAIT, 0); 383 lck_mtx_lock(ppp_domain_mutex); 384 return err; 385} 386 387/* ----------------------------------------------------------------------------- 388----------------------------------------------------------------------------- */ 389int l2tp_udp_setpeer(socket_t so, struct sockaddr *addr) 390{ 391 int result; 392 393 if (so == 0) 394 return EINVAL; 395 396 lck_mtx_unlock(ppp_domain_mutex); 397 result = sock_connect(so, addr, 0); 398 lck_mtx_lock(ppp_domain_mutex); 399 400 return result; 401} 402 403/* ----------------------------------------------------------------------------- 404----------------------------------------------------------------------------- */ 405void l2tp_udp_thread_func(struct l2tp_udp_thread *thread_socket) 406{ 407 mbuf_t m; 408 socket_t so; 409 410 for (;;) { 411 412 lck_mtx_lock(thread_socket->mtx); 413dequeue: 414 m = ppp_dequeue(&thread_socket->outq); 415 if (m == NULL) { 416 if (thread_socket->terminate) { 417 wakeup(&thread_socket->terminate); 418 // just sleep again. caller will terminate the thread. 419 msleep(&thread_socket->thread, thread_socket->mtx, PZERO + 1, "l2tp_udp_thread_func terminate", 0); 420 /* NOT REACHED */ 421 } 422 msleep(&thread_socket->wakeup, thread_socket->mtx, PZERO + 1, "l2tp_udp_thread_func", 0); 423 goto dequeue; 424 } 425 lck_mtx_unlock(thread_socket->mtx); 426 427 memcpy((void *)&so, mbuf_data(m), sizeof(so)); 428 mbuf_adj(m, sizeof(socket_t)); 429 430 // should have a kpi to sendmbuf and release at the same time 431 // to avoid too extra lock/unlock 432 sock_sendmbuf(so, 0, m, MSG_DONTWAIT, 0); 433 sock_release(so); 434 435 } 436 437 /* NOTREACHED */ 438} 439 440/* ----------------------------------------------------------------------------- 441----------------------------------------------------------------------------- */ 442int l2tp_udp_attach(socket_t *socket, struct sockaddr *addr, int *thread, int nocksum, int delegated_process) 443{ 444 int val; 445 errno_t err; 446 socket_t so = 0; 447 u_int32_t i, min; 448 449 lck_mtx_unlock(ppp_domain_mutex); 450 451 /* open a UDP socket for use by the L2TP client */ 452 if ((err = sock_socket(AF_INET, SOCK_DGRAM, 0, l2tp_udp_input, 0, &so))) 453 goto fail; 454 455 /* configure the socket to reuse port */ 456 val = 1; 457 if ((err = sock_setsockopt(so, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)))) 458 goto fail; 459 460 if (nocksum) { 461 val = 1; 462 if ((err = sock_setsockopt(so, IPPROTO_UDP, UDP_NOCKSUM, &val, sizeof(val)))) 463 goto fail; 464 } 465 466 /* set the delegate process for traffic statistics */ 467 if (delegated_process) 468 if ((err = sock_setsockopt(so, SOL_SOCKET, SO_DELEGATED, &delegated_process, sizeof(delegated_process)))) 469 goto fail; 470 471 if ((err = sock_bind(so, addr))) 472 goto fail; 473 474 /* fill in the incomplete part of the address assigned by UDP */ 475 if ((err = sock_getsockname(so, addr, addr->sa_len))) 476 goto fail; 477 478 lck_mtx_lock(ppp_domain_mutex); 479 *socket = so; 480 481 if (l2tp_udp_nb_threads) { 482 min = 0; 483 for (i = 1; i < l2tp_udp_nb_threads; i++) 484 if (l2tp_udp_threads[i].nbclient < l2tp_udp_threads[min].nbclient) 485 min = i; 486 *thread = min; 487 l2tp_udp_threads[min].nbclient += 1; 488 //IOLog("l2tp_udp_attach: worker thread #%d (total client for thread is now %d)\n", *thread, l2tp_udp_threads[*thread].nbclient); 489 } 490 else 491 *thread = -1; 492 493 return 0; 494 495fail: 496 if (so) 497 sock_close(so); 498 lck_mtx_lock(ppp_domain_mutex); 499 return err; 500} 501 502/* ----------------------------------------------------------------------------- 503----------------------------------------------------------------------------- */ 504int l2tp_udp_detach(socket_t so, int thread) 505{ 506 507 if (so) { 508 if (thread >= 0 && thread < l2tp_udp_nb_threads) { 509 if (l2tp_udp_threads[thread].nbclient > 0) 510 l2tp_udp_threads[thread].nbclient -= 1; 511 //IOLog("l2tp_udp_detach: worker thread #%d (total client for thread is now %d)\n", thread, l2tp_udp_threads[thread].nbclient); 512 } 513 514 lck_mtx_unlock(ppp_domain_mutex); 515 sock_close(so); /* close the UDP socket */ 516 lck_mtx_lock(ppp_domain_mutex); 517 } 518 519 return 0; 520} 521 522/* ----------------------------------------------------------------------------- 523----------------------------------------------------------------------------- */ 524void l2tp_udp_clear_INP_INADDR_ANY(socket_t so) 525{ 526 if (so) { 527 528 lck_mtx_unlock(ppp_domain_mutex); 529 inp_clear_INP_INADDR_ANY((struct socket *)so); 530 lck_mtx_lock(ppp_domain_mutex); 531 } 532 533} 534