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*  Theory of operation :
27*
28*  this file implements the ppp domain, which is used to communicate
29*  between pppd and the interface/link layer
30*
31----------------------------------------------------------------------------- */
32
33/* -----------------------------------------------------------------------------
34Includes
35----------------------------------------------------------------------------- */
36
37#include <sys/systm.h>
38#include <sys/mbuf.h>
39#include <sys/socket.h>
40#include <sys/syslog.h>
41#include <sys/protosw.h>
42#include <sys/domain.h>
43#include <sys/sysctl.h>
44#include <kern/locks.h>
45#include <net/if.h>
46#include <netinet/in.h>
47
48#include "if_ppplink.h"		// public link API
49#include "ppp_domain.h"
50#include "ppp_defs.h"		// public ppp values
51#include "if_ppp.h"		// public ppp API
52#include "ppp_if.h"
53#include "ppp_link.h"
54
55/* -----------------------------------------------------------------------------
56Definitions
57----------------------------------------------------------------------------- */
58
59#define TYPE_IF		1
60#define TYPE_LINK 	2
61
62/* -----------------------------------------------------------------------------
63Forward declarations
64----------------------------------------------------------------------------- */
65
66int ppp_proto_attach(struct socket *, int, struct proc *);
67int ppp_proto_detach(struct socket *so);
68int ppp_proto_connect(struct socket *, struct sockaddr *, struct proc *);
69int ppp_proto_ioctl(struct socket *, u_long cmd, caddr_t , struct ifnet *, struct proc *);
70int ppp_proto_send(struct socket *, int , struct mbuf * , struct sockaddr *, struct mbuf *, struct proc *);
71
72/* -----------------------------------------------------------------------------
73Globals
74----------------------------------------------------------------------------- */
75
76struct domain ppp_domain =
77{	PF_PPP, PPP_NAME, NULL,
78	NULL, NULL, NULL, NULL, NULL,
79	0, 0, 0, 0
80};
81
82struct pr_usrreqs ppp_usr =
83{       pru_abort_notsupp, pru_accept_notsupp, ppp_proto_attach, pru_bind_notsupp,
84        ppp_proto_connect, pru_connect2_notsupp, ppp_proto_ioctl, ppp_proto_detach,
85        pru_disconnect_notsupp, pru_listen_notsupp, pru_peeraddr_notsupp,
86        pru_rcvd_notsupp, pru_rcvoob_notsupp, ppp_proto_send,
87        pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp,
88        sosend, soreceive, pru_sopoll_notsupp
89};
90
91struct protosw ppp_proto =
92{       SOCK_RAW, &ppp_domain, PPPPROTO_CTL, PR_ATOMIC|PR_CONNREQUIRED|PR_PROTOLOCK,
93        NULL, NULL, NULL, NULL,
94        NULL, NULL,
95        NULL, NULL, NULL, NULL, &ppp_usr
96};
97
98u_char pppproto_inited = 0;
99
100lck_mtx_t   *ppp_domain_mutex;
101
102SYSCTL_NODE(_net, PF_PPP, ppp, CTLFLAG_RW, 0, "");
103
104/* -----------------------------------------------------------------------------
105Initialization function
106----------------------------------------------------------------------------- */
107int ppp_domain_init()
108{
109
110    // add domain cannot fail, just add the domain struct to the linked list
111    net_add_domain(&ppp_domain);
112	ppp_domain_mutex = ppp_domain.dom_mtx;
113	ppp_domain.dom_flags = DOM_REENTRANT;  // tell dlil not to take our lock
114
115    sysctl_register_oid(&sysctl__net_ppp);
116
117    return 0;
118}
119
120/* -----------------------------------------------------------------------------
121Initialization function
122----------------------------------------------------------------------------- */
123int ppp_proto_add()
124{
125    int ret;
126
127    ret = net_add_proto(&ppp_proto, &ppp_domain);
128    if (ret) {
129        net_del_domain(&ppp_domain);
130		LOGRETURN(ret, ret, "ppp_proto_add : can't add proto to PPP domain, error = 0x%x\n");
131    }
132
133    pppproto_inited = 1;
134
135    return 0;
136}
137
138/* -----------------------------------------------------------------------------
139Dispose function
140----------------------------------------------------------------------------- */
141int ppp_proto_remove()
142{
143    int ret;
144
145    if (pppproto_inited) {
146        ret = net_del_proto(ppp_proto.pr_type, ppp_proto.pr_protocol, ppp_proto.pr_domain);
147        LOGRETURN(ret, ret, "ppp_domain_terminate : can't del proto from PPP domain, error = 0x%x\n");
148		pppproto_inited = 0;
149    }
150
151    return 0;
152}
153
154/* -----------------------------------------------------------------------------
155Dispose function
156----------------------------------------------------------------------------- */
157int ppp_domain_dispose()
158{
159    int ret;
160
161    ret = net_del_domain(&ppp_domain);
162	LOGRETURN(ret, ret, "ppp_domain_terminate : can't del PPP domain, error = 0x%x\n");
163
164    sysctl_unregister_oid(&sysctl__net_ppp);
165
166    return 0;
167}
168
169/* -----------------------------------------------------------------------------
170Called by socket layer when a new socket is created
171----------------------------------------------------------------------------- */
172int ppp_proto_attach (struct socket *so, int proto, struct proc *p)
173{
174    int	error = 0;
175
176    //IOLog("ppp_proto_attach, so = %p\n", so);
177
178    if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0)
179        error = soreserve(so, 8192, 8192);
180
181    return error;
182}
183
184/* -----------------------------------------------------------------------------
185Called by socket layer when the socket is closed
186----------------------------------------------------------------------------- */
187int ppp_proto_detach(struct socket *so)
188{
189    //IOLog("ppp_proto_detach, so = %p\n", so);
190
191    ppp_proto_free(so);
192    return 0;
193}
194
195/* -----------------------------------------------------------------------------
196Called by socket layer to connect the protocol (PR_CONNREQUIRED)
197----------------------------------------------------------------------------- */
198int ppp_proto_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
199{
200    soisconnected(so);
201    return 0;
202}
203
204/* -----------------------------------------------------------------------------
205Called by socket layer to handle ioctl
206----------------------------------------------------------------------------- */
207int ppp_proto_ioctl(struct socket *so, u_long cmd, caddr_t data,
208                  struct ifnet *ifp, struct proc *p)
209{
210    int 	error = 0;
211    u_int16_t	unit;
212    u_int32_t   data_aligned;
213
214    //IOLog("ppp_proto_control : so = %p, cmd = %d\n", so, cmd);
215
216    switch (cmd) {
217        case PPPIOCNEWUNIT:
218            // this ioctl must be done before connecting the socket
219            //IOLog("ppp_proto_control : PPPIOCNEWUNIT\n");
220            memcpy(&data_aligned, data, sizeof(u_int32_t));         // Wcast-align fix - memcpy for unaligned move
221            unit = data_aligned;
222            error = ppp_if_attach(&unit);
223            if (error)
224                return error;
225            data_aligned = unit;
226            memcpy(data, &data_aligned, sizeof(u_int32_t));         // Wcast-align fix - memcpy for unaligned move
227            // no break; PPPIOCNEWUNIT implicitlty attach the client
228
229        case PPPIOCATTACH:
230            //IOLog("ppp_proto_control : PPPIOCATTACH\n");
231            memcpy(&data_aligned, data, sizeof(u_int32_t));         // Wcast-align fix - memcpy for unaligned move
232            unit = data_aligned;
233            error = ppp_if_attachclient(unit, so, (ifnet_t *)&so->so_pcb);
234            if (!error)
235                so->so_tpcb = (caddr_t)TYPE_IF;
236            break;
237
238        case PPPIOCATTCHAN:
239            //IOLog("ppp_proto_control : PPPIOCATTCHAN\n");
240            memcpy(&data_aligned, data, sizeof(u_int32_t));         // Wcast-align fix - memcpy for unaligned move
241            unit = data_aligned;
242            error = ppp_link_attachclient(unit, so, (struct ppp_link **)&so->so_pcb);
243            if (!error)
244                so->so_tpcb = (caddr_t)TYPE_LINK;
245            break;
246
247        case PPPIOCDETACH:
248            //IOLog("ppp_proto_control : PPPIOCDETACH\n");
249            ppp_proto_free(so);
250            break;
251
252        default:
253            switch ((uintptr_t)so->so_tpcb) {
254                case TYPE_IF:
255                    error = ppp_if_control((ifnet_t)so->so_pcb, cmd, data);
256                    break;
257                case TYPE_LINK:
258                    error = ppp_link_control((struct ppp_link *)so->so_pcb, cmd, data);
259                    break;
260                default:
261                    error = EINVAL;
262            }
263    }
264
265    return error;
266}
267
268/* -----------------------------------------------------------------------------
269Called by socket layer to send data out
270----------------------------------------------------------------------------- */
271int ppp_proto_send(struct socket *so, int flags, struct mbuf *m,
272               struct sockaddr *nam, struct mbuf *control, struct proc *p)
273{
274    int error = 0;
275
276    switch ((uintptr_t)so->so_tpcb) {
277        case TYPE_IF:
278            error = ppp_if_send((ifnet_t)so->so_pcb, (mbuf_t)m);
279            break;
280        case TYPE_LINK:
281            error = ppp_link_send((struct ppp_link *)so->so_pcb, (mbuf_t)m);
282            break;
283        default:
284            error = EINVAL;
285			if (m)
286				mbuf_freem((mbuf_t)m);
287    }
288	if (control)
289		mbuf_freem((mbuf_t)control);
290    return error;
291}
292
293/* -----------------------------------------------------------------------------
294called from ppp_if or ppp_link when data struct disappears
295----------------------------------------------------------------------------- */
296void ppp_proto_free(void *data)
297{
298    struct socket *so = (struct socket *)data;
299
300	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
301
302    if (!so)
303        return;
304
305    switch ((uintptr_t)so->so_tpcb) {
306        case TYPE_IF:
307            ppp_if_detachclient((ifnet_t)so->so_pcb, so);
308            break;
309        case TYPE_LINK:
310            ppp_link_detachclient((struct ppp_link *)so->so_pcb, so);
311            break;
312    }
313    so->so_pcb = 0;
314    so->so_tpcb = 0;
315	so->so_flags |= SOF_PCBCLEARING;
316}
317
318/* -----------------------------------------------------------------------------
319called from ppp_link when data are present
320----------------------------------------------------------------------------- */
321int ppp_proto_input(void *data, mbuf_t m)
322{
323    struct socket *so = (struct socket *)data;
324
325	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
326
327    //IOLog("ppp_proto_input, so = %p, len = %d\n", pcb->socket, m->m_pkthdr.len);
328
329    // use this flag to be sure the app receive packets with End OF Record
330    mbuf_setflags(m, mbuf_flags(m) | MBUF_EOR);
331
332    // if there is no pppd attached yet, or if buffer is full, free the packet
333    if (!so || sbspace(&so->so_rcv) < mbuf_pkthdr_len(m)) {
334        if (so)
335	  IOLog("ppp_proto_input no space, so = %p, len = %d\n", so, mbuf_pkthdr_len(m));
336        mbuf_freem(m);
337        return 0;
338    }
339
340//    IOLog("----------- ppp_proto_input, link %d, packet %x %x %x %x %x %x %x %x \n", *(u_short *)p, p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
341
342    sbappendrecord(&so->so_rcv, (struct mbuf*)m);
343    sorwakeup(so);
344    return 0;
345}
346
347
348/* -----------------------------------------------------------------------------
349queue utilities
350----------------------------------------------------------------------------- */
351int ppp_qfull(struct pppqueue *pppq)
352{
353	return pppq->len >= pppq->maxlen;
354}
355
356void ppp_drop(struct pppqueue *pppq)
357{
358	pppq->drops++;
359}
360
361void ppp_enqueue(struct pppqueue *pppq, mbuf_t m)
362{
363	mbuf_setnextpkt(m, 0);
364	if (pppq->tail == 0)
365		pppq->head = m;
366	else
367		mbuf_setnextpkt(pppq->tail, m);
368	pppq->tail = m;
369	pppq->len++;
370}
371
372mbuf_t ppp_dequeue(struct pppqueue *pppq)
373{
374	mbuf_t m = pppq->head;
375	if (m) {
376		if ((pppq->head = mbuf_nextpkt(m)) == 0)
377			pppq->tail = 0;
378		mbuf_setnextpkt(m, 0);
379		pppq->len--;
380	}
381	return m;
382}
383
384void ppp_prepend(struct pppqueue *pppq, mbuf_t m)
385{
386	mbuf_setnextpkt(m, pppq->head);
387	if (pppq->tail == 0)
388		pppq->tail = m;
389	pppq->head = m;
390	pppq->len++;
391}
392
393