1/*
2 * Copyright (c) 2000 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
25#include <sys/systm.h>
26#include <sys/malloc.h>
27#include <sys/mbuf.h>
28#include <sys/socket.h>
29#include <sys/syslog.h>
30#include <sys/protosw.h>
31#include <kern/locks.h>
32
33#include <net/if_types.h>
34#include <net/if.h>
35
36#include "../../../Family/ppp_defs.h"
37#include "../../../Family/if_ppplink.h"
38#include "../../../Family/if_ppp.h"
39#include "../../../Family/ppp_domain.h"
40
41
42#include "PPTP.h"
43#include "pptp_proto.h"
44#include "pptp_rfc.h"
45#include "pptp_wan.h"
46
47
48/* -----------------------------------------------------------------------------
49Definitions
50----------------------------------------------------------------------------- */
51/* Wcast-align fix - cast away alignment warning when buffer is aligned */
52#define ALIGNED_CAST(type)	(type)(void *)
53
54
55/* -----------------------------------------------------------------------------
56Declarations
57----------------------------------------------------------------------------- */
58
59void pptp_init();
60int pptp_ctloutput(struct socket *so, struct sockopt *sopt);
61int pptp_usrreq();
62
63int pptp_attach(struct socket *, int, struct proc *);
64int pptp_detach(struct socket *);
65int pptp_control(struct socket *so, u_long cmd, caddr_t data,
66                  struct ifnet *ifp, struct proc *p);
67
68// callback from rfc layer
69int pptp_input(void *data, mbuf_t m);
70void pptp_event(void *data, u_int32_t event, u_int32_t msg);
71
72/* -----------------------------------------------------------------------------
73Globals
74----------------------------------------------------------------------------- */
75struct pr_usrreqs 	pptp_usr;	/* pr_usrreqs extension to the protosw */
76struct protosw 		pptp;		/* describe the protocol switch */
77
78extern lck_mtx_t	*ppp_domain_mutex;
79
80/* -----------------------------------------------------------------------------
81--------------------------------------------------------------------------------
82--------------------------------------------------------------------------------
83----------- Admistrative functions, called by ppp_domain -----------------------
84--------------------------------------------------------------------------------
85--------------------------------------------------------------------------------
86----------------------------------------------------------------------------- */
87
88/* -----------------------------------------------------------------------------
89 PPTP Timer, at 500 ms. Replaces pptp_slowtimo, which is deprecated.
90 ----------------------------------------------------------------------------- */
91static uint8_t pptp_timer_thread_is_dying = 0; /* > 0 if dying */
92static uint8_t pptp_timer_thread_is_dead = 0; /* > 0 if dead */
93
94static void pptp_timer()
95{
96    struct timespec ts = {0};
97
98    /* timeout of 500 ms */
99    ts.tv_nsec = 500 * 1000 * 1000;
100    ts.tv_sec = 0;
101
102    lck_mtx_lock(ppp_domain_mutex);
103    while (TRUE) {
104        if (pptp_timer_thread_is_dying > 0) {
105            break;
106        }
107
108        pptp_rfc_slowtimer();
109
110        msleep(&pptp_timer_thread_is_dying, ppp_domain_mutex, PSOCK, "pptp_timer_sleep", &ts);
111    }
112
113    pptp_timer_thread_is_dead++;
114    wakeup(&pptp_timer_thread_is_dead);
115    lck_mtx_unlock(ppp_domain_mutex);
116
117    thread_terminate(current_thread());
118}
119
120/* -----------------------------------------------------------------------------
121Called when we need to add the PPTP protocol to the domain
122Typically, ppp_add is called by ppp_domain when we add the domain,
123but we can add the protocol anytime later, if the domain is present
124----------------------------------------------------------------------------- */
125int pptp_add(struct domain *domain)
126{
127    int 	 err;
128    thread_t pptp_timer_thread = NULL;
129
130    bzero(&pptp_usr, sizeof(struct pr_usrreqs));
131    pptp_usr.pru_abort 	= pru_abort_notsupp;
132    pptp_usr.pru_accept 	= pru_accept_notsupp;
133    pptp_usr.pru_attach 	= pptp_attach;
134    pptp_usr.pru_bind 		= pru_bind_notsupp;
135    pptp_usr.pru_connect 	= pru_connect_notsupp;
136    pptp_usr.pru_connect2 	= pru_connect2_notsupp;
137    pptp_usr.pru_control 	= pptp_control;
138    pptp_usr.pru_detach 	= pptp_detach;
139    pptp_usr.pru_disconnect 	= pru_disconnect_notsupp;
140    pptp_usr.pru_listen 	= pru_listen_notsupp;
141    pptp_usr.pru_peeraddr 	= pru_peeraddr_notsupp;
142    pptp_usr.pru_rcvd 		= pru_rcvd_notsupp;
143    pptp_usr.pru_rcvoob 	= pru_rcvoob_notsupp;
144    pptp_usr.pru_send 		= pru_send_notsupp;
145    pptp_usr.pru_sense 		= pru_sense_null;
146    pptp_usr.pru_shutdown 	= pru_shutdown_notsupp;
147    pptp_usr.pru_sockaddr 	= pru_sockaddr_notsupp;
148    pptp_usr.pru_sosend 	= sosend;
149    pptp_usr.pru_soreceive 	= soreceive;
150    pptp_usr.pru_sopoll 	= pru_sopoll_notsupp;
151
152
153    bzero(&pptp, sizeof(struct protosw));
154    pptp.pr_type		= SOCK_DGRAM;
155    pptp.pr_domain		= domain;
156    pptp.pr_protocol 	= PPPPROTO_PPTP;
157    pptp.pr_flags		= PR_ATOMIC | PR_PROTOLOCK;
158    pptp.pr_ctloutput 	= pptp_ctloutput;
159    pptp.pr_init		= pptp_init;
160    pptp.pr_usrreqs 	= &pptp_usr;
161
162    pptp_timer_thread_is_dying = 0;
163    if (kernel_thread_start((thread_continue_t)pptp_timer, NULL, &pptp_timer_thread) == KERN_SUCCESS) {
164        thread_deallocate(pptp_timer_thread);
165    }
166
167    err = net_add_proto(&pptp, domain);
168    if (err)
169        return err;
170
171    return KERN_SUCCESS;
172}
173
174/* -----------------------------------------------------------------------------
175Called when we need to remove the PPTP protocol from the domain
176----------------------------------------------------------------------------- */
177int pptp_remove(struct domain *domain)
178{
179    int err;
180
181    lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
182
183    /* Cleanup timer thread */
184    if (pptp_timer_thread_is_dead == 0) {
185        pptp_timer_thread_is_dying++;           /* Tell thread to die */
186        wakeup(&pptp_timer_thread_is_dying);    /* Wake thread */
187        msleep(&pptp_timer_thread_is_dying, ppp_domain_mutex, PSOCK, "pptp_timer_sleep", 0);
188    }
189
190    err = net_del_proto(pptp.pr_type, pptp.pr_protocol, domain);
191    if (err)
192        return err;
193
194    // shall we test that all the pcbs have been freed ?
195
196    return KERN_SUCCESS;
197}
198
199/* -----------------------------------------------------------------------------
200--------------------------------------------------------------------------------
201--------------------------------------------------------------------------------
202--------------------------- protosw functions ----------------------------------
203--------------------------------------------------------------------------------
204--------------------------------------------------------------------------------
205----------------------------------------------------------------------------- */
206
207/* -----------------------------------------------------------------------------
208This function is called by socket layer when the protocol is added
209----------------------------------------------------------------------------- */
210void pptp_init()
211{
212    //IOLog("pptp_init\n");
213}
214
215/* -----------------------------------------------------------------------------
216This function is called by socket layer to handle get/set-socketoption
217----------------------------------------------------------------------------- */
218int pptp_ctloutput(struct socket *so, struct sockopt *sopt)
219{
220    int		error, optval;
221    u_int32_t	lval, cmd = 0;
222    u_int16_t	val;
223
224	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
225
226    //IOLog("pptp_ctloutput, so = %p\n", so);
227
228    error = optval = 0;
229    if (sopt->sopt_level != PPPPROTO_PPTP) {
230        return EINVAL;
231    }
232
233    switch (sopt->sopt_dir) {
234        case SOPT_SET:
235            switch (sopt->sopt_name) {
236                case PPTP_OPT_FLAGS:
237                case PPTP_OPT_OURADDRESS:
238                case PPTP_OPT_PEERADDRESS:
239                case PPTP_OPT_BAUDRATE:
240                    if (sopt->sopt_valsize != 4)
241                        error = EMSGSIZE;
242                    else if ((error = sooptcopyin(sopt, &lval, 4, 4)) == 0) {
243                        switch (sopt->sopt_name) {
244                            case PPTP_OPT_OURADDRESS: 	cmd = PPTP_CMD_SETOURADDR; break;
245                            case PPTP_OPT_PEERADDRESS: 	cmd = PPTP_CMD_SETPEERADDR; break;
246                            case PPTP_OPT_FLAGS: 	cmd = PPTP_CMD_SETFLAGS; break;
247                            case PPTP_OPT_BAUDRATE: 	cmd = PPTP_CMD_SETBAUDRATE; break;
248                        }
249                        pptp_rfc_command(so->so_pcb, cmd , &lval);
250                    }
251                    break;
252                case PPTP_OPT_CALL_ID:
253                case PPTP_OPT_PEER_CALL_ID:
254                case PPTP_OPT_WINDOW:
255                case PPTP_OPT_PEER_WINDOW:
256                case PPTP_OPT_PEER_PPD:
257                case PPTP_OPT_MAXTIMEOUT:
258                    if (sopt->sopt_valsize != 2)
259                        error = EMSGSIZE;
260                    else if ((error = sooptcopyin(sopt, &val, 2, 2)) == 0) {
261                        switch (sopt->sopt_name) {
262                            case PPTP_OPT_CALL_ID: 	cmd = PPTP_CMD_SETCALLID; break;
263                            case PPTP_OPT_PEER_CALL_ID: cmd = PPTP_CMD_SETPEERCALLID; break;
264                            case PPTP_OPT_WINDOW: 	cmd = PPTP_CMD_SETWINDOW; break;
265                            case PPTP_OPT_PEER_WINDOW: 	cmd = PPTP_CMD_SETPEERWINDOW; break;
266                            case PPTP_OPT_PEER_PPD: 	cmd = PPTP_CMD_SETPEERPPD; break;
267                            case PPTP_OPT_MAXTIMEOUT: 	cmd = PPTP_CMD_SETMAXTIMEOUT; break;
268                        }
269                        pptp_rfc_command(so->so_pcb, cmd , &val);
270                    }
271                    break;
272                default:
273                    error = ENOPROTOOPT;
274            }
275            break;
276
277        case SOPT_GET:
278            error = ENOPROTOOPT;
279            break;
280
281    }
282    return error;
283}
284
285/* -----------------------------------------------------------------------------
286--------------------------------------------------------------------------------
287--------------------------------------------------------------------------------
288------------------------- pr_usrreqs functions ---------------------------------
289--------------------------------------------------------------------------------
290--------------------------------------------------------------------------------
291----------------------------------------------------------------------------- */
292
293/* -----------------------------------------------------------------------------
294Called by socket layer when a new socket is created
295Should create all the structures and prepare for pptp dialog
296----------------------------------------------------------------------------- */
297int pptp_attach (struct socket *so, int proto, struct proc *p)
298{
299    int			error;
300
301    //IOLog("pptp_attach, so = %p, dom_ref = %d\n", so, so->so_proto->pr_domain->dom_refs);
302    if (so->so_pcb)
303        return EINVAL;
304
305    if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
306        error = soreserve(so, 8192, 8192);
307        if (error)
308            return error;
309    }
310
311    // call pptp init with the rfc specific structure
312	lck_mtx_lock(ppp_domain_mutex);
313    if (pptp_rfc_new_client(so, (void**)&(so->so_pcb), pptp_input, pptp_event)) {
314		lck_mtx_unlock(ppp_domain_mutex);
315        return ENOMEM;
316    }
317
318	lck_mtx_unlock(ppp_domain_mutex);
319    return 0;
320}
321
322/* -----------------------------------------------------------------------------
323Called by socket layer when the socket is closed
324Should free all the pptp structures
325----------------------------------------------------------------------------- */
326int pptp_detach(struct socket *so)
327{
328
329	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
330
331    //IOLog("pptp_detach, so = %p, dom_ref = %d\n", so, so->so_proto->pr_domain->dom_refs);
332
333    if (so->so_tpcb) {
334        pptp_wan_detach(ALIGNED_CAST(struct ppp_link *)so->so_tpcb);
335        so->so_tpcb = 0;
336    }
337    if (so->so_pcb) {
338        pptp_rfc_free_client(so->so_pcb);
339        so->so_pcb = 0;
340    }
341	so->so_flags |= SOF_PCBCLEARING;
342    return 0;
343}
344
345/* -----------------------------------------------------------------------------
346Called by socket layer to handle ioctl
347----------------------------------------------------------------------------- */
348int pptp_control(struct socket *so, u_long cmd, caddr_t data,
349                  struct ifnet *ifp, struct proc *p)
350{
351    int 		error = 0;
352    u_int32_t aligned_data;
353
354	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
355
356    //IOLog("pptp_control : so = %p, cmd = %d\n", so, cmd);
357
358    switch (cmd) {
359	case PPPIOCGCHAN:
360            //IOLog("pptp_control : PPPIOCGCHAN\n");
361            if (!so->so_tpcb)
362                return EINVAL;// not attached
363            aligned_data = (ALIGNED_CAST(struct ppp_link *)so->so_tpcb)->lk_index;              // Wcast-align fix - we malloc so->so_tpcb - lk_index is u_1616_t copying to u_int32_t
364            memcpy(data, &aligned_data, sizeof(u_int32_t));                                     // Wcast-align fix - memcpy for unaligned move
365            break;
366	case PPPIOCATTACH:
367            //IOLog("pptp_control : PPPIOCATTACH\n");
368           if (so->so_tpcb)
369                return EINVAL;// already attached
370            error = pptp_wan_attach(so->so_pcb, ALIGNED_CAST(struct ppp_link **)&so->so_tpcb);
371            break;
372	case PPPIOCDETACH:
373            //IOLog("pptp_control : PPPIOCDETACH\n");
374            if (!so->so_tpcb)
375                return EINVAL;// already detached
376            pptp_wan_detach(ALIGNED_CAST(struct ppp_link *)so->so_tpcb);
377            so->so_tpcb = 0;
378            break;
379        default:
380            ;
381    }
382
383    return error;
384}
385
386/* -----------------------------------------------------------------------------
387--------------------------------------------------------------------------------
388--------------------------------------------------------------------------------
389------------------------- callbacks from pptp rfc or from dlil ----------------
390--------------------------------------------------------------------------------
391--------------------------------------------------------------------------------
392----------------------------------------------------------------------------- */
393
394
395/* -----------------------------------------------------------------------------
396called from pptp_rfc when data are present
397----------------------------------------------------------------------------- */
398int pptp_input(void *data, mbuf_t m)
399{
400    struct socket 	*so = (struct socket *)data;
401
402	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
403
404    if (so->so_tpcb) {
405        // we are hooked to ppp
406	return pptp_wan_input(ALIGNED_CAST(struct ppp_link *)so->so_tpcb, m);
407    }
408
409    mbuf_freem(m);
410    IOLog("pptp_input unexpected, so = %p, len = %lu\n", so, mbuf_pkthdr_len(m));
411    return 0;
412}
413
414/* -----------------------------------------------------------------------------
415----------------------------------------------------------------------------- */
416void pptp_event(void *data, u_int32_t event, u_int32_t msg)
417{
418    struct socket 	*so = (struct socket *)data;
419
420	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
421
422    if (so->so_tpcb) {
423        switch (event) {
424            case PPTP_EVT_XMIT_FULL:
425                pptp_wan_xmit_full(ALIGNED_CAST(struct ppp_link *)so->so_tpcb);         // Wcast-align fix - we malloc so->so_tpcb
426                break;
427            case PPTP_EVT_XMIT_OK:
428                pptp_wan_xmit_ok(ALIGNED_CAST(struct ppp_link *)so->so_tpcb);
429                break;
430            case PPTP_EVT_INPUTERROR:
431                pptp_wan_input_error(ALIGNED_CAST(struct ppp_link *)so->so_tpcb);
432                break;
433        }
434    }
435}
436