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 pppoe 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 (does not include escapes...)
38*     ifnet.if_obytes = nb of correct PPP bytes sent (does not include escapes...)
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 "PPPoE.h"
71#include "pppoe_rfc.h"
72#include "pppoe_wan.h"
73
74
75/* -----------------------------------------------------------------------------
76Definitions
77----------------------------------------------------------------------------- */
78
79struct pppoe_wan {
80    /* first, the ifnet structure... */
81    struct ppp_link 	link;			/* ppp link structure */
82
83    /* administrative info */
84    TAILQ_ENTRY(pppoe_wan) next;
85    void 		*rfc;			/* pppoe 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	pppoe_wan_output(struct ppp_link *link, mbuf_t m);
101static int 	pppoe_wan_ioctl(struct ppp_link *link, u_long cmd, void *data);
102static int 	pppoe_wan_findfreeunit(u_short *freeunit);
103
104/* -----------------------------------------------------------------------------
105Globals
106----------------------------------------------------------------------------- */
107
108static TAILQ_HEAD(, pppoe_wan) 	pppoe_wan_head;
109
110extern lck_mtx_t   *ppp_domain_mutex;
111
112/* -----------------------------------------------------------------------------
113----------------------------------------------------------------------------- */
114int pppoe_wan_init()
115{
116
117    TAILQ_INIT(&pppoe_wan_head);
118    return 0;
119}
120
121/* -----------------------------------------------------------------------------
122----------------------------------------------------------------------------- */
123int pppoe_wan_dispose()
124{
125
126    // don't detach if links are in use
127    if (TAILQ_FIRST(&pppoe_wan_head))
128        return EBUSY;
129
130    return 0;
131}
132
133/* -----------------------------------------------------------------------------
134detach pppoe interface dlil layer
135----------------------------------------------------------------------------- */
136int pppoe_wan_attach(void *rfc, struct ppp_link **link)
137{
138    int 		ret;
139    struct pppoe_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 pppoe_wan *, sizeof(struct pppoe_wan), M_TEMP, M_WAITOK);
149    if (!wan)
150        return ENOMEM;
151
152    if (pppoe_wan_findfreeunit(&unit)) {
153        FREE(wan, M_TEMP);
154        return ENOMEM;
155    }
156
157    bzero(wan, sizeof(struct pppoe_wan));
158
159    TAILQ_INSERT_TAIL(&pppoe_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*)PPPOE_NAME;
164    lk->lk_mtu 		= PPPOE_MTU;
165    lk->lk_mru 		= PPPOE_MTU;;
166    lk->lk_type 	= PPP_TYPE_PPPoE;
167    lk->lk_hdrlen 	= 14; // ethernet header len
168    //ld->lk_if.link_lk_baudrate = tp->t_ospeed;
169    lk->lk_ioctl 	= pppoe_wan_ioctl;
170    lk->lk_output 	= pppoe_wan_output;
171    lk->lk_unit 	= unit;
172    lk->lk_support 	= PPP_LINK_DEL_AC;
173    wan->rfc = rfc;
174
175    ret = ppp_link_attach((struct ppp_link *)wan);
176    if (ret) {
177        IOLog("pppoe_wan_attach, error = %d, (ld = %p)\n", ret, wan);
178        TAILQ_REMOVE(&pppoe_wan_head, wan, next);
179        FREE(wan, M_TEMP);
180        return ret;
181    }
182
183    //IOLog("pppoe_wan_attach, link index = %d, (ld = %p)\n", lk->lk_index, lk);
184
185    *link = lk;
186
187    return 0;
188}
189
190/* -----------------------------------------------------------------------------
191detach pppoe interface dlil layer
192----------------------------------------------------------------------------- */
193void pppoe_wan_detach(struct ppp_link *link)
194{
195    struct pppoe_wan  	*wan = (struct pppoe_wan *)link;
196
197	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
198
199    ppp_link_detach(link);
200    TAILQ_REMOVE(&pppoe_wan_head, wan, next);
201    FREE(wan, M_TEMP);
202}
203
204/* -----------------------------------------------------------------------------
205find a free unit in the interface list
206----------------------------------------------------------------------------- */
207int pppoe_wan_findfreeunit(u_short *freeunit)
208{
209    struct pppoe_wan  	*wan = TAILQ_FIRST(&pppoe_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(&pppoe_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 pppoe_rfc when data are present
228----------------------------------------------------------------------------- */
229int pppoe_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    //getmicrotime(&link->lk_last_recv);
238	nanouptime(&tv);
239	link->lk_last_recv = tv.tv_sec;
240
241    ppp_link_input(link, m);
242    return 0;
243}
244
245/* -----------------------------------------------------------------------------
246Process an ioctl request to the ppp interface
247----------------------------------------------------------------------------- */
248int pppoe_wan_ioctl(struct ppp_link *link, u_long cmd, void *data)
249{
250    //struct pppoe_wan 	*wan = (struct pppoe_wan *)link;;
251    int error = 0;
252
253	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
254
255    //LOGDBG(ifp, ("pppoe_wan_ioctl, cmd = 0x%x\n", cmd));
256
257    switch (cmd) {
258        default:
259            error = ENOTSUP;
260    }
261    return error;
262}
263
264/* -----------------------------------------------------------------------------
265This gets called at splnet from if_ppp.c at various times
266when there is data ready to be sent
267----------------------------------------------------------------------------- */
268int pppoe_wan_output(struct ppp_link *link, mbuf_t m)
269{
270    struct pppoe_wan 	*wan = (struct pppoe_wan *)link;
271    int			err;
272	struct timespec tv;
273
274	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
275
276    if ((err = pppoe_rfc_output(wan->rfc, m))) {
277        link->lk_oerrors++;
278        return err;
279    }
280
281    link->lk_opackets++;
282    link->lk_obytes += mbuf_pkthdr_len(m);
283    //getmicrotime(link->lk_last_xmit);
284	nanouptime(&tv);
285	link->lk_last_xmit = tv.tv_sec;
286    return 0;
287}
288