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*
26*  History :
27*
28*  Aug 2000 - 	Christophe Allie - created.
29*
30*  Theory of operation :
31*
32*  this file implements the pptp driver for the ppp family
33*
34*  it's the responsability of the driver to update the statistics
35*  whenever that makes sense
36*     ifnet.if_lastchange = a packet is present, a packet starts to be sent
37*     ifnet.if_ibytes = nb of correct PPP bytes received
38*     ifnet.if_obytes = nb of correct PPP bytes sent
39*     ifnet.if_ipackets = nb of PPP packet received
40*     ifnet.if_opackets = nb of PPP packet sent
41*     ifnet.if_ierrors = nb on input packets in error
42*     ifnet.if_oerrors = nb on ouptut packets in error
43*
44----------------------------------------------------------------------------- */
45
46
47/* -----------------------------------------------------------------------------
48Includes
49----------------------------------------------------------------------------- */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/mbuf.h>
54#include <sys/socket.h>
55#include <sys/malloc.h>
56#include <sys/syslog.h>
57#include <sys/sockio.h>
58#include <sys/kernel.h>
59#include <net/if_types.h>
60#include <net/dlil.h>
61#include <kern/clock.h>
62#include <kern/locks.h>
63
64
65
66#include "../../../Family/ppp_domain.h"
67#include "../../../Family/if_ppplink.h"
68#include "../../../Family/ppp_defs.h"
69#include "../../../Family/if_ppp.h"
70#include "PPTP.h"
71#include "pptp_rfc.h"
72#include "pptp_wan.h"
73
74
75/* -----------------------------------------------------------------------------
76Definitions
77----------------------------------------------------------------------------- */
78
79struct pptp_wan {
80    /* first, the ifnet structure... */
81    struct ppp_link 	link;			/* ppp link structure */
82
83    /* administrative info */
84    TAILQ_ENTRY(pptp_wan) next;
85    void 		*rfc;			/* pptp protocol structure */
86
87    /* settings */
88
89    /* output data */
90
91    /* input data */
92
93    /* log purpose */
94};
95
96/* -----------------------------------------------------------------------------
97Forward declarations
98----------------------------------------------------------------------------- */
99
100static int	pptp_wan_output(struct ppp_link *link, mbuf_t m);
101static int 	pptp_wan_ioctl(struct ppp_link *link, u_long cmd, void *data);
102static int 	pptp_wan_findfreeunit(u_short *freeunit);
103
104/* -----------------------------------------------------------------------------
105Globals
106----------------------------------------------------------------------------- */
107
108static TAILQ_HEAD(, pptp_wan) 	pptp_wan_head;
109
110extern lck_mtx_t   *ppp_domain_mutex;
111
112/* -----------------------------------------------------------------------------
113----------------------------------------------------------------------------- */
114int pptp_wan_init()
115{
116
117    TAILQ_INIT(&pptp_wan_head);
118    return 0;
119}
120
121/* -----------------------------------------------------------------------------
122----------------------------------------------------------------------------- */
123int pptp_wan_dispose()
124{
125
126    // don't detach if links are in use
127    if (TAILQ_FIRST(&pptp_wan_head))
128        return EBUSY;
129
130    return 0;
131}
132
133/* -----------------------------------------------------------------------------
134detach pptp interface dlil layer
135----------------------------------------------------------------------------- */
136int pptp_wan_attach(void *rfc, struct ppp_link **link)
137{
138    int 		ret;
139    struct pptp_wan  	*wan;
140    struct ppp_link  	*lk;
141    u_short 		unit;
142
143	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
144
145    // Note : we allocate/find number/insert in queue in that specific order
146    // because of funnels and race condition issues
147
148    MALLOC(wan, struct pptp_wan *, sizeof(struct pptp_wan), M_TEMP, M_WAITOK);
149    if (!wan)
150        return ENOMEM;
151
152    if (pptp_wan_findfreeunit(&unit)) {
153        FREE(wan, M_TEMP);
154        return ENOMEM;
155    }
156
157    bzero(wan, sizeof(struct pptp_wan));
158
159    TAILQ_INSERT_TAIL(&pptp_wan_head, wan, next);
160    lk = (struct ppp_link *) wan;
161
162    // it's time now to register our brand new link
163    lk->lk_name 	= (u_char*)PPTP_NAME;
164    lk->lk_mtu 		= PPTP_MTU;
165    lk->lk_mru 		= PPTP_MTU;;
166    lk->lk_type 	= PPP_TYPE_PPTP;
167    lk->lk_hdrlen 	= 80;	// ???
168	pptp_rfc_command(rfc, PPTP_CMD_GETBAUDRATE, &lk->lk_baudrate);
169    lk->lk_ioctl 	= pptp_wan_ioctl;
170    lk->lk_output 	= pptp_wan_output;
171    lk->lk_unit 	= unit;
172    lk->lk_support 	= 0;
173    wan->rfc = rfc;
174
175    ret = ppp_link_attach((struct ppp_link *)wan);
176    if (ret) {
177        IOLog("pptp_wan_attach, error = %d, (ld = %p)\n", ret, wan);
178        TAILQ_REMOVE(&pptp_wan_head, wan, next);
179        FREE(wan, M_TEMP);
180        return ret;
181    }
182
183    //IOLog("pptp_wan_attach, link index = %d, (ld = %p)\n", lk->lk_index, lk);
184
185    *link = lk;
186
187    return 0;
188}
189
190/* -----------------------------------------------------------------------------
191detach pptp interface dlil layer
192----------------------------------------------------------------------------- */
193void pptp_wan_detach(struct ppp_link *link)
194{
195    struct pptp_wan  	*wan = (struct pptp_wan *)link;
196
197	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
198
199    ppp_link_detach(link);
200    TAILQ_REMOVE(&pptp_wan_head, wan, next);
201    FREE(wan, M_TEMP);
202}
203
204/* -----------------------------------------------------------------------------
205find a free unit in the interface list
206----------------------------------------------------------------------------- */
207int pptp_wan_findfreeunit(u_short *freeunit)
208{
209    struct pptp_wan  	*wan = TAILQ_FIRST(&pptp_wan_head);
210    u_short 		unit = 0;
211
212	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
213
214    while (wan) {
215    	if (wan->link.lk_unit == unit) {
216            unit++;
217            wan = TAILQ_FIRST(&pptp_wan_head); // restart
218        }
219        else
220            wan = TAILQ_NEXT(wan, next); // continue
221    }
222    *freeunit = unit;
223    return 0;
224}
225
226/* -----------------------------------------------------------------------------
227called from pptp_rfc when data are present
228----------------------------------------------------------------------------- */
229int pptp_wan_input(struct ppp_link *link, mbuf_t m)
230{
231	struct timespec tv;
232
233    lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
234
235    link->lk_ipackets++;
236    link->lk_ibytes += mbuf_pkthdr_len(m);
237	nanouptime(&tv);
238	link->lk_last_recv = tv.tv_sec;
239    ppp_link_input(link, m);
240    return 0;
241}
242
243/* -----------------------------------------------------------------------------
244called from pptp_rfc when xmit is full
245----------------------------------------------------------------------------- */
246void pptp_wan_xmit_full(struct ppp_link *link)
247{
248	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
249
250    link->lk_flags |= SC_XMIT_FULL;
251}
252
253/* -----------------------------------------------------------------------------
254called from pptp_rfc when there is an input error
255----------------------------------------------------------------------------- */
256void pptp_wan_input_error(struct ppp_link *link)
257{
258
259	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
260
261    ppp_link_event(link, PPP_LINK_EVT_INPUTERROR, 0);
262}
263
264/* -----------------------------------------------------------------------------
265called from pptp_rfc when xmit is ok again
266----------------------------------------------------------------------------- */
267void pptp_wan_xmit_ok(struct ppp_link *link)
268{
269	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
270    link->lk_flags &= ~SC_XMIT_FULL;
271    ppp_link_event(link, PPP_LINK_EVT_XMIT_OK, 0);
272}
273
274/* -----------------------------------------------------------------------------
275Process an ioctl request to the ppp interface
276----------------------------------------------------------------------------- */
277int pptp_wan_ioctl(struct ppp_link *link, u_long cmd, void *data)
278{
279    //struct pptp_wan 	*wan = (struct pptp_wan *)link;;
280    int error = 0;
281
282	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
283
284    //LOGDBG(ifp, ("pptp_wan_ioctl, cmd = 0x%x\n", cmd));
285
286    switch (cmd) {
287        default:
288            error = ENOTSUP;
289    }
290    return error;
291}
292
293/* -----------------------------------------------------------------------------
294This gets called at splnet from if_ppp.c at various times
295when there is data ready to be sent
296----------------------------------------------------------------------------- */
297int pptp_wan_output(struct ppp_link *link, mbuf_t m)
298{
299    struct pptp_wan 	*wan = (struct pptp_wan *)link;
300    u_int32_t		len = mbuf_pkthdr_len(m);	// take it now, as output will change the mbuf
301    int			err;
302	struct timespec tv;
303
304	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
305
306    if ((err = pptp_rfc_output(wan->rfc, m))) {
307        link->lk_oerrors++;
308        return err;
309    }
310
311    link->lk_opackets++;
312    link->lk_obytes += len;
313	nanouptime(&tv);
314	link->lk_last_xmit = tv.tv_sec;
315    return 0;
316}
317