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