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 interface driver for the ppp family
29*
30*  it's the responsability of the driver to update the statistics
31*  whenever that makes sense
32*     ifnet.if_lastchange = a packet is present, a packet starts to be sent
33*     ifnet.if_ibytes = nb of correct PPP bytes received (does not include escapes...)
34*     ifnet.if_obytes = nb of correct PPP bytes sent (does not include escapes...)
35*     ifnet.if_ipackets = nb of PPP packet received
36*     ifnet.if_opackets = nb of PPP packet sent
37*     ifnet.if_ierrors = nb on input packets in error
38*     ifnet.if_oerrors = nb on ouptut packets in error
39*
40----------------------------------------------------------------------------- */
41
42
43/* -----------------------------------------------------------------------------
44Includes
45----------------------------------------------------------------------------- */
46
47#include <sys/param.h>
48#include <sys/systm.h>
49#include <sys/kpi_mbuf.h>
50#include <sys/socket.h>
51#include <sys/malloc.h>
52#include <sys/syslog.h>
53#include <sys/sockio.h>
54#include <sys/kernel.h>
55#include <kern/clock.h>
56
57#include <net/if_types.h>
58#include <netinet/in.h>
59#include <netinet/tcp.h>
60#include <netinet/in_systm.h>
61#include <net/bpf.h>
62#include <net/kpi_interface.h>
63#include <net/if.h>
64
65#include "slcompress.h"
66#include "ppp_defs.h"		// public ppp values
67#include "if_ppp.h"		// public ppp API
68#include "if_ppplink.h"		// public link API
69#include "ppp_domain.h"
70#include "ppp_if.h"
71#include "ppp_ip.h"
72#include "ppp_ipv6.h"
73#include "ppp_compress.h"
74#include "ppp_comp.h"
75#include "ppp_link.h"
76
77
78/* -----------------------------------------------------------------------------
79Definitions
80----------------------------------------------------------------------------- */
81
82/* -----------------------------------------------------------------------------
83Forward declarations
84----------------------------------------------------------------------------- */
85
86static void ppp_if_start(ifnet_t interface);
87static errno_t ppp_if_output(ifnet_t ifp, mbuf_t m);
88static void ppp_if_if_free(ifnet_t ifp);
89static errno_t ppp_if_ioctl(ifnet_t ifp, u_long cmd, void *data);
90static int  ppp_if_demux(ifnet_t ifp, mbuf_t m, char *frame_header,
91                  protocol_family_t *protocol_family);
92static int  ppp_if_add_proto(ifnet_t ifp, protocol_family_t protocol_family,
93			const struct ifnet_demux_desc *demux_list, u_int32_t demux_count);
94static int  ppp_if_del_proto(ifnet_t ifp, protocol_family_t protocol_family);
95#if KPI_INTERFACE_EMBEDDED
96static errno_t  ppp_if_frameout(ifnet_t ifp, mbuf_t *m0,
97								const struct sockaddr *ndest, const char *edst, const char *ppp_type,
98								u_int32_t *pre, u_int32_t *post);
99#else /* KPI_INTERFACE_EMBEDDED */
100static errno_t  ppp_if_frameout(ifnet_t ifp, mbuf_t *m0,
101                     const struct sockaddr *ndest, const char *edst, const char *ppp_type);
102#endif /* !KPI_INTERFACE_EMBEDDED */
103
104static int 	ppp_if_detach(ifnet_t ifp);
105static struct ppp_if *ppp_if_findunit(u_short unit);
106static int ppp_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, bpf_packet_func func);
107
108/* -----------------------------------------------------------------------------
109Globals
110----------------------------------------------------------------------------- */
111
112static TAILQ_HEAD(, ppp_if) 	ppp_if_head;
113static lck_grp_attr_t			*ppp_if_lck_grp_attr = 0;
114static lck_attr_t				*ppp_if_lck_attr = 0;
115static lck_grp_t				*ppp_if_lck_grp = 0;
116
117extern lck_mtx_t				*ppp_domain_mutex;
118
119/* -----------------------------------------------------------------------------
120----------------------------------------------------------------------------- */
121int ppp_if_init()
122{
123    TAILQ_INIT(&ppp_if_head);
124
125	ppp_if_lck_grp_attr = lck_grp_attr_alloc_init();
126	LOGNULLFAIL(ppp_if_lck_grp_attr, "ppp_if_init: lck_grp_attr_alloc_init failed\n");
127
128	lck_grp_attr_setdefault(ppp_if_lck_grp_attr);
129
130	ppp_if_lck_grp = lck_grp_alloc_init("PPP", ppp_if_lck_grp_attr);
131	LOGNULLFAIL(ppp_if_lck_grp, "ppp_if_init: lck_grp_alloc_init failed\n");
132
133	ppp_if_lck_attr = lck_attr_alloc_init();
134	LOGNULLFAIL(ppp_if_lck_attr, "ppp_if_init: lck_attr_alloc_init failed\n");
135
136	lck_attr_setdefault(ppp_if_lck_attr);
137	//lck_attr_setdebug(ppp_if_lck_attr);
138
139    return 0;
140
141fail:
142	if (ppp_if_lck_grp) {
143		lck_grp_free(ppp_if_lck_grp);
144		ppp_if_lck_grp = 0;
145	}
146	if (ppp_if_lck_grp_attr) {
147		lck_grp_attr_free(ppp_if_lck_grp_attr);
148		ppp_if_lck_grp_attr = 0;
149	}
150	if (ppp_if_lck_attr) {
151		lck_attr_free(ppp_if_lck_attr);
152		ppp_if_lck_attr = 0;
153	}
154	return KERN_FAILURE;
155
156}
157
158/* -----------------------------------------------------------------------------
159----------------------------------------------------------------------------- */
160int ppp_if_dispose()
161{
162
163    // can't dispose if interface are in use
164    if (!TAILQ_EMPTY(&ppp_if_head))
165        return EBUSY;
166
167	lck_grp_free(ppp_if_lck_grp);
168	ppp_if_lck_grp = 0;
169
170	lck_grp_attr_free(ppp_if_lck_grp_attr);
171	ppp_if_lck_grp_attr = 0;
172
173	lck_attr_free(ppp_if_lck_attr);
174	ppp_if_lck_attr = 0;
175
176    return 0;
177}
178
179/* -----------------------------------------------------------------------------
180----------------------------------------------------------------------------- */
181int ppp_if_attach(u_short *unit)
182{
183    int 		ret = 0;
184    struct ppp_if  	*wan, *wan1;
185	struct ifnet_init_eparams init;
186	struct ifnet_stats_param stats;
187
188    MALLOC(wan, struct ppp_if *, sizeof(struct ppp_if), M_TEMP, M_WAITOK);
189    if (!wan)
190        return ENOMEM;
191
192    bzero(wan, sizeof(struct ppp_if));
193	wan->unit = 0xFFFF;
194
195	wan1 = TAILQ_FIRST(&ppp_if_head);
196
197    if (*unit != 0xFFFF) {
198		// if a specific nuber has been requested, find if not in use, and insert it
199		while (wan1) {
200			if (wan1->unit == *unit) {
201				// in use, just return error.
202				lck_mtx_unlock(ppp_domain_mutex);
203				ret = EINVAL;
204				goto error_nolock;
205			}
206			if (wan1->unit > *unit)
207				break;
208			wan1 = TAILQ_NEXT(wan1, next);
209		}
210    }
211	else {
212		// find a free unit and insert it, keep the list ordered
213		*unit = 0;
214		wan1 = TAILQ_FIRST(&ppp_if_head);
215		while (wan1) {
216			if (wan1->unit > *unit)
217				break;
218			*unit = wan1->unit + 1;
219			wan1 = TAILQ_NEXT(wan1, next);
220		}
221	}
222
223	wan->mtx = lck_mtx_alloc_init(ppp_if_lck_grp, ppp_if_lck_attr);
224	if (wan->mtx == 0) {
225		lck_mtx_unlock(ppp_domain_mutex);
226		ret = ENOMEM;
227		goto error_nolock;
228	}
229
230	wan->unit = *unit;
231	if (wan1)
232		TAILQ_INSERT_BEFORE(wan1, wan, next);
233	else
234		TAILQ_INSERT_TAIL(&ppp_if_head, wan, next);
235
236	bzero(&init, sizeof(init));
237	init.ver = IFNET_INIT_CURRENT_VERSION;
238	init.len = sizeof(init);
239	init.name = APPLE_PPP_NAME;
240	init.unit = *unit;
241	init.family = IFNET_FAMILY_PPP;
242	init.type = IFT_PPP;
243	init.start = ppp_if_start;
244	init.demux = ppp_if_demux;
245	init.add_proto = ppp_if_add_proto;
246	init.del_proto = ppp_if_del_proto;
247	init.framer = ppp_if_frameout;
248	init.softc = wan;
249	init.ioctl = ppp_if_ioctl;
250	init.detach = ppp_if_if_free;
251	init.set_bpf_tap = ppp_if_set_bpf_tap;
252
253	lck_mtx_unlock(ppp_domain_mutex);
254
255	ret = ifnet_allocate_extended(&init, &wan->net);
256    if (ret)
257        goto error_nolock;
258
259    TAILQ_INIT(&wan->link_head);
260
261	ifnet_set_hdrlen(wan->net, PPP_HDRLEN);
262	ifnet_set_flags(wan->net, IFF_POINTOPOINT | IFF_MULTICAST, 0xFFFF); // || IFF_RUNNING
263	ifnet_set_mtu(wan->net, PPP_MTU);
264	ifnet_set_baudrate(wan->net, 0 /* 10 Mbits/s ??? */);
265	bzero(&stats, sizeof(stats));
266	ifnet_set_stat(wan->net, &stats);
267	/*
268	 * A PPP interface does generate its own IPv6 LinkLocal address
269	 */
270	ifnet_set_eflags(wan->net, IFEF_NOAUTOIPV6LL, IFEF_NOAUTOIPV6LL);
271	ifnet_touch_lastchange(wan->net);
272
273    ret = ifnet_attach(wan->net, NULL);
274    if (ret)
275        goto error_nolock;
276
277    bpfattach(wan->net, DLT_PPP, PPP_HDRLEN);
278
279    // attach network protocols
280
281    wan->sndq.maxlen = IFQ_MAXLEN;
282    wan->npmode[NP_IP] = NPMODE_ERROR;
283    wan->npmode[NP_IPV6] = NPMODE_ERROR;
284
285	lck_mtx_lock(ppp_domain_mutex);
286    return 0;
287
288error_nolock:
289    if (wan->net)
290        ifnet_release(wan->net);
291	if (wan->mtx)
292		lck_mtx_free(wan->mtx, ppp_if_lck_grp);
293	lck_mtx_lock(ppp_domain_mutex);
294	if (wan->unit != 0xFFFF) {
295		TAILQ_REMOVE(&ppp_if_head, wan, next);
296	}
297	FREE(wan, M_TEMP);
298    return ret;
299}
300
301/* -----------------------------------------------------------------------------
302detach ppp interface from dlil layer
303----------------------------------------------------------------------------- */
304int ppp_if_detach(ifnet_t ifp)
305{
306    struct ppp_if  	*wan = ifnet_softc(ifp);
307    int				ret;
308    struct ppp_link	*link;
309    mbuf_t			m;
310
311    // need to remove all ref to ifnet in link structures
312    TAILQ_FOREACH(link, &wan->link_head, lk_bdl_next) {
313        // do we need a free function ?
314        link->lk_ifnet = 0;
315    }
316
317    ppp_comp_close(wan);
318
319    // detach protocols when detaching interface, just in case pppd forgot...
320
321	lck_mtx_unlock(ppp_domain_mutex);
322    ppp_ipv6_detach(ifp, PF_INET6);
323    ppp_ip_detach(ifp, PF_INET);
324	lck_mtx_lock(ppp_domain_mutex);
325
326    if (wan->vjcomp) {
327	FREE(wan->vjcomp, M_TEMP);
328	wan->vjcomp = 0;
329    }
330
331	wan->state |= PPP_IF_STATE_DETACHING;
332	lck_mtx_unlock(ppp_domain_mutex);
333    ret = ifnet_detach(ifp);
334	if (ret) {
335		wan->state &= ~PPP_IF_STATE_DETACHING;
336		lck_mtx_lock(ppp_domain_mutex);
337		return KERN_FAILURE;
338	}
339
340	lck_mtx_lock(wan->mtx);
341	/* interface release is in progress, wait for callback */
342	if (wan->state & PPP_IF_STATE_DETACHING)
343		msleep(ifp, wan->mtx, PZERO+1, 0, 0);
344	lck_mtx_unlock(wan->mtx);
345
346	//sleep(ifp, PZERO+1);
347	lck_mtx_lock(ppp_domain_mutex);
348
349    do {
350        m = ppp_dequeue(&wan->sndq);
351        mbuf_freem(m);
352    } while (m);
353
354	lck_mtx_unlock(ppp_domain_mutex);
355    ifnet_release(ifp);
356	lck_mtx_lock(ppp_domain_mutex);
357    TAILQ_REMOVE(&ppp_if_head, wan, next);
358	lck_mtx_free(wan->mtx, ppp_if_lck_grp);
359    FREE(wan, M_TEMP);
360
361    return 0;
362}
363
364/* -----------------------------------------------------------------------------
365----------------------------------------------------------------------------- */
366int ppp_if_attachclient(u_short unit, void *host, ifnet_t *ifp)
367{
368    struct ppp_if  	*wan;
369
370    wan = ppp_if_findunit(unit);
371    if (!wan)
372        return ENODEV;
373
374    *ifp = wan->net;
375    if (!wan->host)    // don't override the first attachment (use a list ?)
376        wan->host = host;
377    wan->nbclients++;
378
379    return 0;
380}
381
382/* -----------------------------------------------------------------------------
383----------------------------------------------------------------------------- */
384void ppp_if_detachclient(ifnet_t ifp, void *host)
385{
386    struct ppp_if  	*wan = ifnet_softc(ifp);
387
388    if (wan->host) {
389        if (wan->host == host)
390            wan->host = 0;
391        wan->nbclients--;
392        if (!wan->nbclients)
393            ppp_if_detach(ifp);
394    }
395}
396
397/* -----------------------------------------------------------------------------
398find a the unit number in the interface list
399----------------------------------------------------------------------------- */
400struct ppp_if *ppp_if_findunit(u_short unit)
401{
402    struct ppp_if  	*wan;
403
404    TAILQ_FOREACH(wan, &ppp_if_head, next) {
405        if (wan->unit == unit)
406            return wan;
407    }
408    return NULL;
409}
410
411/* -----------------------------------------------------------------------------
412----------------------------------------------------------------------------- */
413static errno_t
414ppp_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode,
415				bpf_packet_func func)
416{
417    struct ppp_if 	*wan = ifnet_softc(ifp);
418
419	lck_mtx_lock(ppp_domain_mutex);
420
421    switch (mode) {
422        case BPF_MODE_DISABLED:
423            wan->bpf_input = wan->bpf_output = NULL;
424            break;
425
426        case BPF_MODE_INPUT:
427            wan->bpf_input = func;
428            break;
429
430        case BPF_MODE_OUTPUT:
431			wan->bpf_output = func;
432            break;
433
434        case BPF_MODE_INPUT_OUTPUT:
435            wan->bpf_input = wan->bpf_output = func;
436            break;
437        default:
438            break;
439    }
440	lck_mtx_unlock(ppp_domain_mutex);
441    return 0;
442}
443
444/* -----------------------------------------------------------------------------
445mbuf debugging
446----------------------------------------------------------------------------- */
447
448#ifdef LOGDATA
449
450static void
451snprintf_mbuf(char *s, size_t len, mbuf_t m, const char *prefix, const char *suffix)
452{
453    if (m) {
454        if ((mbuf_flags(m) & MBUF_PKTHDR))
455            snprintf(s, len,
456                     "%s%p type %u len %u data %p maxlen %u datastart %p next %p flags %x pktlen %u nextpkt %p header %p%s",
457                     prefix ? prefix : "",
458                     m, mbuf_type(m), mbuf_len(m), mbuf_data(m), mbuf_maxlen(m), mbuf_datastart(m), mbuf_next(m),
459                     mbuf_flags(m), mbuf_pkthdr_len(m), mbuf_nextpkt(m), mbuf_pkthdr_header(m),
460                     suffix ? suffix : "");
461        else
462            snprintf(s, len,
463                     "%s%p type %u len %u data %p maxlen %u datastart %p next %p flags %x%s",
464                     prefix ? prefix : "",
465                     m, mbuf_type(m), mbuf_len(m), mbuf_data(m), mbuf_maxlen(m), mbuf_datastart(m), mbuf_next(m),
466                     mbuf_flags(m),
467                     suffix ? suffix : "");
468    } else
469        snprintf(s, len, "%s<NULL>%s", prefix, suffix);
470}
471
472static void
473DumpHex(char *line, size_t maxline, unsigned char *buffer, size_t len)
474{
475    size_t			i;
476	int				n = 0;
477
478    for (i = 0; i < len; i += 16) {
479        size_t		j;
480
481		if (n > maxline) return;
482        n += snprintf(line + n, maxline - n, "%06d: ", i);
483        for (j = i; j < len && j < i + 16; j++) {
484			if (n > maxline) return;
485            n += snprintf(line + n, maxline - n, "%02x ", buffer[j]);
486        }
487        for (; j < i + 16; j++) {
488			if (n > maxline) return;
489            n += snprintf(line + n, maxline - n, "   ");
490        }
491        for (j = i; j < len && j < i + 16; j++) {
492            int	c = buffer[j];
493
494            if (c < 0x20 || c > 0x7E)
495                c = '.';
496			if (n > maxline) return;
497            n += snprintf(line + n, maxline - n, "%c", c);
498        }
499        n += snprintf(line + n, maxline - n, "\n");
500    }
501}
502
503static void
504log_mbuf(ifnet_t ifp, mbuf_t m, const char *msg)
505{
506    char        mbuf_str[160];
507    char        data_str[160];
508
509    snprintf_mbuf(mbuf_str, sizeof(mbuf_str), m, NULL, NULL);
510    DumpHex(data_str, sizeof(data_str), mbuf_data(m), MIN(mbuf_len(m), 32));
511    LOGDBG(ifp, ("ppp%d: %s: %s\n", ifnet_unit(ifp), msg, mbuf_str));
512    LOGDBG(ifp, ("%s\n", data_str));
513}
514
515#endif /* LOGDATA */
516
517/* -----------------------------------------------------------------------------
518called when data are present
519----------------------------------------------------------------------------- */
520int ppp_if_input(ifnet_t ifp, mbuf_t m, u_int16_t proto, u_int16_t hdrlen)
521{
522    struct ppp_if 	*wan = ifnet_softc(ifp);
523    int 		inlen, vjlen;
524    u_char		*iphdr, *p = mbuf_data(m);	// no alignment issue as p is *u_char.
525    u_int 		hlen;
526    int 		error = ENOMEM;
527	struct timespec tv;
528	struct		ifnet_stat_increment_param statsinc;
529    u_int16_t   aligned_short;
530
531	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
532
533    mbuf_pkthdr_setheader(m, p);		// header point to the protocol header (0x21 or 0x0021)
534    mbuf_adj(m, hdrlen);			// the packet points to the real data (0x45)
535    p = mbuf_data(m);
536
537    if (wan->sc_flags & SC_DECOMP_RUN) {
538        switch (proto) {
539            case PPP_COMP:
540                if (ppp_comp_decompress(wan, &m) != DECOMP_OK) {
541                    LOGDBG(ifp, ("ppp%d: decompression error\n", ifnet_unit(ifp)));
542                    goto free;
543                }
544                p = mbuf_data(m);
545                proto = p[0];
546                hdrlen = 1;
547                if (!(proto & 0x1)) {  // lowest bit set for lowest byte of protocol
548                    proto = (proto << 8) + p[1];
549                    hdrlen = 2;
550                }
551                mbuf_pkthdr_setheader(m, p);// header point to the protocol header (0x21 or 0x0021)
552                mbuf_adj(m, hdrlen);	// the packet points to the real data (0x45)
553                p = mbuf_data(m);
554                break;
555            default:
556                ppp_comp_incompress(wan, m);
557        }
558    }
559
560    switch (proto) {
561        case PPP_VJC_COMP:
562        case PPP_VJC_UNCOMP:
563            if (!(wan->sc_flags & SC_COMP_TCP))
564                goto reject;
565
566            if (!wan->vjcomp) {
567                LOGDBG(ifp, ("ppp%d: VJ structure not allocated\n", ifnet_unit(ifp)));
568                goto free;
569            }
570
571            inlen = mbuf_pkthdr_len(m);
572
573            /*
574             * We should make sure the header is contiguous in the mbuf of the compress/decompress routines
575             * Do not ask more than the mbuf contains
576             */
577            if (mbuf_len(m) < MIN(inlen, sizeof(struct ip) + sizeof(struct tcphdr))) {
578                mbuf_t      new_m = NULL;
579                size_t      offset = 0;
580                size_t      len = MIN(inlen, sizeof(struct ip) + sizeof(struct tcphdr));
581
582#ifdef LOGDATA
583                log_mbuf(ifp, m, proto == PPP_VJC_COMP ? "PPP_VJC_COMP" : "PPP_VJC_UNCOMP");
584#endif
585                if (mbuf_pulldown(m, &offset, len, &new_m) != 0) {
586                    LOGDBG(ifp, ("ppp%d: mbuf_pulldown failed\n", ifnet_unit(ifp)));
587                    goto end;
588                }
589                if (new_m != m) {
590                    m = new_m;
591#ifdef LOGDATA
592                    log_mbuf(ifp, m, "pulled-down");
593#endif
594                }
595            }
596            if (proto == PPP_VJC_COMP) {
597
598                vjlen = sl_uncompress_tcp_core(p, mbuf_len(m), inlen, TYPE_COMPRESSED_TCP,
599                    wan->vjcomp, &iphdr, &hlen);
600
601                if (vjlen <= 0) {
602                    LOGDBG(ifp, ("ppp%d: VJ uncompress failed on type PPP_VJC_COMP\n", ifnet_unit(ifp)));
603                    goto free;
604                }
605
606                // we must move data in the buffer, to add the uncompressed TCP/IP header...
607                if (mbuf_trailingspace(m) < (hlen - vjlen)) {
608                    LOGDBG(ifp, ("ppp%d: VJ uncompress failed: trailingspace (%d) < hlen (%d) - vjlen (%d)\n", ifnet_unit(ifp),
609                        mbuf_trailingspace(m), hlen, vjlen));
610                    goto free;
611                }
612                bcopy(p + vjlen, p + hlen, inlen - vjlen);
613                bcopy(iphdr, p, hlen);
614				mbuf_setlen(m, mbuf_len(m) + hlen - vjlen);
615                mbuf_pkthdr_setlen(m, mbuf_pkthdr_len(m) + hlen - vjlen);
616            }
617            else {
618                vjlen = sl_uncompress_tcp_core(p, mbuf_len(m), inlen, TYPE_UNCOMPRESSED_TCP,
619                    wan->vjcomp, &iphdr, &hlen);
620
621                if (vjlen < 0) {
622                    LOGDBG(ifp, ("ppp%d: VJ uncompress failed on type TYPE_UNCOMPRESSED_TCP\n", ifnet_unit(ifp)));
623                    goto free;
624                }
625            }
626            *(u_char *)mbuf_pkthdr_header(m) = PPP_IP; // change the protocol, use 1 byte
627            proto = PPP_IP;
628            //no break;
629        case PPP_IP:
630            if (wan->npmode[NP_IP] != NPMODE_PASS)
631                goto reject;
632            if (wan->npafmode[NP_IP] & NPAFMODE_SRC_IN) {
633                if (ppp_ip_af_src_in(ifp, mbuf_data(m))) {
634                    error = 0;
635                    goto free;
636                }
637            }
638            if (wan->npafmode[NP_IP] & NPAFMODE_DHCP_INTERCEPT_SERVER) {
639				if (ppp_ip_bootp_server_in(ifp, mbuf_data(m)))
640					goto reject;
641            }
642            if (wan->npafmode[NP_IP] & NPAFMODE_DHCP_INTERCEPT_CLIENT) {
643                if (ppp_ip_bootp_client_in(ifp, mbuf_data(m)))
644					goto reject;
645            }
646            break;
647        case PPP_IPV6:
648            if (wan->npmode[NP_IPV6] != NPMODE_PASS)
649                goto reject;
650            break;
651        case PPP_CCP:
652            ppp_comp_ccp(wan, m, 1);
653            goto reject;
654        default:
655            goto reject;
656    }
657
658    // See if bpf wants to look at the packet.
659    if (wan->bpf_input) {
660        if (mbuf_prepend(&m, 4, MBUF_WAITOK) != 0) {
661			bzero(&statsinc, sizeof(statsinc));
662			statsinc.errors_in = 1;
663			ifnet_stat_increment(ifp, &statsinc);
664            return ENOMEM;
665        }
666        p = mbuf_data(m);
667        // Wcast-align fix for unaligned move
668        aligned_short = htons(0xFF03);
669        *p++ = *((u_int8_t *)&aligned_short);
670        *p++ = *(((u_int8_t *)&aligned_short) + 1);
671        aligned_short = htons(proto);
672        *p++ = *((u_int8_t *)&aligned_short);
673        *p++ = *(((u_int8_t *)&aligned_short) + 1);
674        (*wan->bpf_input)(ifp, m);
675        mbuf_adj(m, 4);
676    }
677
678	bzero(&statsinc, sizeof(statsinc));
679	statsinc.packets_in = 1;
680	statsinc.bytes_in = mbuf_pkthdr_len(m);
681	mbuf_pkthdr_setrcvif(m, ifp);
682    nanouptime(&tv);
683    wan->last_recv = tv.tv_sec;
684
685	lck_mtx_unlock(ppp_domain_mutex);
686    ifnet_input(ifp, m, &statsinc);
687	lck_mtx_lock(ppp_domain_mutex);
688    return 0;
689
690reject:
691
692    // unexpected network protocol, prepend the 2 bytes protocol header expected by pppd
693	if (mbuf_prepend(&m, 2, MBUF_WAITOK) != 0) {
694		bzero(&statsinc, sizeof(statsinc));
695		statsinc.errors_in = 1;
696		ifnet_stat_increment(ifp, &statsinc);
697		return ENOMEM;
698	}
699	p = mbuf_data(m);
700    // Wcast-align fix for unaligned move
701    aligned_short = htons(proto);
702    *p++ = *((u_int8_t *)&aligned_short);
703    *p++ = *(((u_int8_t *)&aligned_short) + 1);
704    ppp_proto_input(wan->host, m);
705    return 0;
706
707free:
708    mbuf_freem(m);
709end:
710	bzero(&statsinc, sizeof(statsinc));
711	statsinc.errors_in = 1;
712	ifnet_stat_increment(ifp, &statsinc);
713    return error;
714}
715
716/* -----------------------------------------------------------------------------
717This gets called when the interface is freed
718(if dlil_if_detach has returned DLIL_WAIT_FOR_FREE)
719----------------------------------------------------------------------------- */
720void ppp_if_if_free(ifnet_t ifp)
721{
722    struct ppp_if  	*wan = ifnet_softc(ifp);
723
724	lck_mtx_lock(wan->mtx);
725	wan->state &= ~PPP_IF_STATE_DETACHING;
726	lck_mtx_unlock(wan->mtx);
727    wakeup(ifp);
728}
729
730/* -----------------------------------------------------------------------------
731Process an ioctl request to the ppp interface
732----------------------------------------------------------------------------- */
733int ppp_if_control(ifnet_t ifp, u_long cmd, void *data)
734{
735    struct ppp_if 	*wan = ifnet_softc(ifp);
736    int 		error = 0, npx;
737    u_int16_t		mru, flags16;
738    u_int32_t		flags;
739    u_int32_t		t;
740    struct npioctl 	*npi;
741    struct npafioctl 	*npafi;
742	struct timespec tv;
743    struct ifpppdelegate    *ifdelegate;
744    ifnet_t                 del_ifp = NULL;
745
746    //LOGDBG(ifp, ("ppp_if_control, (ifnet = %s%d), cmd = 0x%x\n", ifp->if_name, ifp->if_unit, cmd));
747
748	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
749
750    switch (cmd) {
751	case PPPIOCSDEBUG:
752            flags = *(int *)data;
753            LOGDBG(ifp, ("ppp_if_control: PPPIOCSDEBUG (level = 0x%x)\n", flags));
754            flags16 = 0;
755            if (flags & 1) flags16 |= IFF_DEBUG;	// general purpose debugging
756            if (flags & 2) flags16 |= PPP_LOG_INPKT;	// trace all packets in
757            if (flags & 4) flags16 |= PPP_LOG_OUTPKT;	// trace all packets out
758			ifnet_set_flags(ifp, flags16, IFF_DEBUG + PPP_LOG_INPKT + PPP_LOG_OUTPKT);
759            break;
760
761	case PPPIOCGDEBUG:
762			flags16 = ifnet_flags(ifp);
763            flags = 0;
764            if (flags16 & IFF_DEBUG) flags |= 1;
765            if (flags16 & PPP_LOG_INPKT) flags |= 2;
766            if (flags16 & PPP_LOG_OUTPKT) flags |= 4;
767            *(int *)data = flags;
768            LOGDBG(ifp, ("ppp_if_control: PPPIOCGDEBUG (level = 0x%x)\n", flags));
769            break;
770
771	case PPPIOCSMRU:
772            LOGDBG(ifp, ("ppp_if_control: PPPIOCSMRU\n"));
773            mru = *(int *)data;
774            wan->mru = mru;
775            break;
776
777	case PPPIOCSFLAGS:
778            flags = *(int *)data & SC_MASK;
779            LOGDBG(ifp, ("ppp_if_control: PPPIOCSFLAGS, old flags = 0x%x new flags = 0x%x, \n", wan->sc_flags, (wan->sc_flags & ~SC_MASK) | flags));
780            wan->sc_flags = (wan->sc_flags & ~SC_MASK) | flags;
781            break;
782
783	case PPPIOCGFLAGS:
784            LOGDBG(ifp, ("ppp_if_control: PPPIOCGFLAGS\n"));
785            *(int *)data = wan->sc_flags;
786            break;
787
788	case PPPIOCSCOMPRESS32:
789	case PPPIOCSCOMPRESS64:
790            error = ppp_comp_setcompressor(wan, data);
791            break;
792
793	case PPPIOCGUNIT:
794            LOGDBG(ifp, ("ppp_if_control: PPPIOCGUNIT\n"));
795            *(int *)data = ifnet_unit(ifp);
796            break;
797
798	case PPPIOCGIDLE:
799            LOGDBG(ifp, ("ppp_if_control: PPPIOCGIDLE\n"));
800			nanouptime(&tv);
801			t = tv.tv_sec;
802            ((struct ppp_idle *)data)->xmit_idle = t - wan->last_xmit;
803            ((struct ppp_idle *)data)->recv_idle = t - wan->last_recv;
804            break;
805
806        case PPPIOCSMAXCID:
807            LOGDBG(ifp, ("ppp_if_control: PPPIOCSMAXCID\n"));
808            // allocate the vj structure first
809            if (!wan->vjcomp) {
810                MALLOC(wan->vjcomp, struct slcompress *, sizeof(struct slcompress),
811                    M_TEMP, M_WAITOK);
812                if (!wan->vjcomp)
813                    return ENOMEM;
814                sl_compress_init(wan->vjcomp, -1);
815            }
816            // reeinit the compressor
817            sl_compress_init(wan->vjcomp, *(int *)data);
818            break;
819
820	case PPPIOCSNPMODE:
821	case PPPIOCGNPMODE:
822            LOGDBG(ifp, ("ppp_if_control: PPPIOCSNPMODE/PPPIOCGNPMODE\n"));
823            npi = (struct npioctl *) data;
824            switch (npi->protocol) {
825                case PPP_IP:
826                    npx = NP_IP;
827                    break;
828                case PPP_IPV6:
829                    npx = NP_IPV6;
830                   break;
831                default:
832                    return EINVAL;
833            }
834            if (cmd == PPPIOCGNPMODE) {
835                npi->mode = wan->npmode[npx];
836            } else {
837                if (npi->mode != wan->npmode[npx]) {
838                    wan->npmode[npx] = npi->mode;
839                    if (npi->mode != NPMODE_QUEUE) {
840                        //ppp_requeue(sc);
841                        //(*sc->sc_start)(sc);
842                    }
843                }
844            }
845            break;
846
847	case PPPIOCSNPAFMODE:
848	case PPPIOCGNPAFMODE:
849            LOGDBG(ifp, ("ppp_if_control: PPPIOCSNPAFMODE/PPPIOCGNPAFMODE\n"));
850            npafi = (struct npafioctl *) data;
851            switch (npafi->protocol) {
852                case PPP_IP:
853                    npx = NP_IP;
854                    break;
855                case PPP_IPV6:
856                    npx = NP_IPV6;
857                    break;
858                default:
859                    return EINVAL;
860            }
861            if (cmd == PPPIOCGNPMODE) {
862                npafi->mode = wan->npafmode[npx];
863            } else {
864                wan->npafmode[npx] = npafi->mode;
865            }
866            break;
867
868    case PPPIOCSDELEGATE:
869        LOGDBG(ifp, ("ppp_if_control: PPPIOCSDELEGATE\n"));
870        ifdelegate = (struct ifpppdelegate*)data;
871        if (strlen(ifdelegate->ifr_delegate_name) != 0)
872            error = ifnet_find_by_name(ifdelegate->ifr_delegate_name, &del_ifp);
873        if (error == 0) {
874            error = ifnet_set_delegate(ifp, del_ifp);
875            if (del_ifp)
876                ifnet_release(del_ifp);
877        }
878        break;
879
880	default:
881            LOGDBG(ifp, ("ppp_if_control: unknown ioctl\n"));
882            error = EINVAL;
883	}
884
885    return error;
886}
887
888/* -----------------------------------------------------------------------------
889Process an ioctl request to the ppp interface
890----------------------------------------------------------------------------- */
891errno_t ppp_if_ioctl(ifnet_t ifp, u_long cmd, void *data)
892{
893    //struct ppp_if 	*wan = ifp->if_softc;
894    struct ifreq 	*ifr = (struct ifreq *)data;
895    int 		error = 0;
896    struct ppp_stats 	*psp;
897	struct ifnet_stats_param statspar;
898
899    //LOGDBG(ifp, ("ppp_if_ioctl, cmd = 0x%x\n", cmd));
900
901	lck_mtx_lock(ppp_domain_mutex);
902
903    switch (cmd) {
904
905        case SIOCSIFFLAGS:
906            LOGDBG(ifp, ("ppp_if_ioctl: cmd = SIOCSIFFLAGS\n"));
907            // even if this case does nothing, it must be there to return 0
908            //if ((ifp->if_flags & IFF_RUNNING) == 0)
909            //    ifp->if_flags &= ~IFF_UP;
910            break;
911
912        case SIOCSIFADDR:
913        case SIOCAIFADDR:
914            LOGDBG(ifp, ("ppp_if_ioctl: cmd = SIOCSIFADDR/SIOCAIFADDR\n"));
915            // dlil protocol module already took care of the ioctl
916            break;
917
918        case SIOCADDMULTI:
919        case SIOCDELMULTI:
920            LOGDBG(ifp, ("ppp_if_ioctl: cmd = SIOCADDMULTI/SIOCDELMULTI\n"));
921            break;
922
923        case SIOCDIFADDR:
924            LOGDBG(ifp, ("ppp_if_ioctl: cmd = SIOCDIFADDR\n"));
925            break;
926
927        case SIOCSIFDSTADDR:
928            LOGDBG(ifp, ("ppp_if_ioctl: cmd = SIOCSIFDSTADDR\n"));
929            break;
930
931	case SIOCGPPPSTATS:
932            LOGDBG(ifp, ("ppp_if_ioctl, SIOCGPPPSTATS\n"));
933            psp = &((struct ifpppstatsreq *) data)->stats;
934            bzero(psp, sizeof(*psp));
935			ifnet_stat(ifp, &statspar);
936			/*
937				XXX ppp pcounters are only 32 bits.
938				need to implement a second ioctl
939				for 64 bits conters
940			*/
941            psp->p.ppp_ibytes = statspar.bytes_in;
942            psp->p.ppp_obytes = statspar.bytes_out;
943            psp->p.ppp_ipackets = statspar.packets_in;
944            psp->p.ppp_opackets = statspar.packets_out;
945            psp->p.ppp_ierrors = statspar.errors_in;
946            psp->p.ppp_oerrors = statspar.errors_out;
947
948#if 0
949            if (sc->sc_comp) {
950                psp->vj.vjs_packets = sc->sc_comp->sls_packets;
951                psp->vj.vjs_compressed = sc->sc_comp->sls_compressed;
952                psp->vj.vjs_searches = sc->sc_comp->sls_searches;
953                psp->vj.vjs_misses = sc->sc_comp->sls_misses;
954                psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin;
955                psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin;
956                psp->vj.vjs_errorin = sc->sc_comp->sls_errorin;
957                psp->vj.vjs_tossed = sc->sc_comp->sls_tossed;
958            }
959#endif
960            break;
961
962        case SIOCSIFMTU:
963            LOGDBG(ifp, ("ppp_if_ioctl, SIOCSIFMTU\n"));
964            // should we check the minimum MTU for all channels attached to that interface ?
965            if (ifr->ifr_mtu > PPP_MTU)
966                error = EINVAL;
967            else
968                ifnet_set_mtu(ifp, ifr->ifr_mtu);
969            break;
970
971	default:
972            LOGDBG(ifp, ("ppp_if_ioctl, unknown ioctl, cmd = 0x%x\n", cmd));
973            error = EOPNOTSUPP;
974	}
975	lck_mtx_unlock(ppp_domain_mutex);
976    return error;
977}
978
979/* -----------------------------------------------------------------------------
980This gets called at splnet from if_ppp.c at various times
981when there is data ready to be sent
982----------------------------------------------------------------------------- */
983static void ppp_if_start(ifnet_t interface)
984{
985	mbuf_t data;
986
987	for (;;) {
988		if (ifnet_dequeue(interface, &data) != 0)
989			break;
990		if (ppp_if_output(interface, data) != 0)
991			break;
992	}
993}
994
995errno_t ppp_if_output(ifnet_t ifp, mbuf_t m)
996{
997    struct ppp_if 	*wan = ifnet_softc(ifp);
998    int 		error = 0;
999    u_int16_t		proto;
1000    enum NPmode		mode;
1001    enum NPAFmode	afmode;
1002    char		*p;
1003	struct timespec tv;
1004	struct		ifnet_stat_increment_param statsinc;
1005
1006	lck_mtx_lock(ppp_domain_mutex);
1007
1008	// clear any flag that can confuse the underlying driver
1009	mbuf_setflags(m, mbuf_flags(m) & ~(MBUF_BCAST + MBUF_MCAST));
1010
1011    memcpy(&proto, mbuf_data(m), sizeof(u_int16_t));
1012    proto = ntohs(proto);
1013
1014    switch (proto) {
1015        case PPP_IP:
1016            mode = wan->npmode[NP_IP];
1017            afmode = wan->npafmode[NP_IP];
1018            break;
1019        case PPP_IPV6:
1020            mode = wan->npmode[NP_IPV6];
1021            afmode = wan->npafmode[NP_IPV6];
1022            break;
1023        default:
1024            // should never happen, since we attached the protocol ourself
1025            error = EAFNOSUPPORT;
1026            goto bad;
1027    }
1028
1029    switch (mode) {
1030        case NPMODE_ERROR:
1031            error = ENETDOWN;
1032            goto bad;
1033        case NPMODE_QUEUE:
1034        case NPMODE_DROP:
1035            error = 0;
1036            goto bad;
1037        case NPMODE_PASS:
1038            break;
1039    }
1040
1041    if (afmode & NPAFMODE_SRC_OUT) {
1042		if (mbuf_len(m) < (sizeof(struct ip) + 2) &&
1043			mbuf_pullup(&m, sizeof(struct ip) + 2)) {
1044			if (m) {
1045				mbuf_free(m);
1046				m = NULL;
1047			}
1048			bzero(&statsinc, sizeof(statsinc));
1049			statsinc.errors_out = 1;
1050			ifnet_stat_increment(ifp, &statsinc);
1051			lck_mtx_unlock(ppp_domain_mutex);
1052            return ENOBUFS;
1053		}
1054        p = mbuf_data(m);
1055        p += 2;
1056        switch (proto) {
1057            case PPP_IP:
1058                error = ppp_ip_af_src_out(ifp, p);
1059                break;
1060        }
1061        if (error) {
1062            error = 0;
1063            goto bad;
1064        }
1065    }
1066
1067    // See if bpf wants to look at the packet.
1068	lck_mtx_unlock(ppp_domain_mutex);
1069    if (wan->bpf_output) {
1070        if (mbuf_prepend(&m, 2, MBUF_WAITOK) != 0) {
1071			bzero(&statsinc, sizeof(statsinc));
1072			statsinc.errors_out = 1;
1073			ifnet_stat_increment(ifp, &statsinc);
1074            return ENOBUFS;
1075        }
1076        proto = htons(0xFF03);
1077        memcpy(mbuf_data(m), &proto, sizeof(u_int16_t));
1078	(*wan->bpf_output)(ifp, m);
1079        mbuf_adj(m, 2);
1080    }
1081	lck_mtx_lock(ppp_domain_mutex);
1082
1083    // Update interface statistics.
1084	ifnet_touch_lastchange(ifp);
1085	nanouptime(&tv);
1086	wan->last_xmit = tv.tv_sec;
1087	bzero(&statsinc, sizeof(statsinc));
1088	statsinc.bytes_out = mbuf_pkthdr_len(m) - 2; // don't count protocol header;
1089	statsinc.packets_out = 1;
1090	ifnet_stat_increment(ifp, &statsinc);
1091
1092    if (wan->sc_flags & SC_LOOP_TRAFFIC) {
1093        ppp_proto_input(wan->host, m);
1094        lck_mtx_unlock(ppp_domain_mutex);
1095        return 0;
1096    }
1097
1098    error = ppp_if_send(ifp, m);
1099	lck_mtx_unlock(ppp_domain_mutex);
1100    return error;
1101
1102bad:
1103    mbuf_freem(m);
1104	bzero(&statsinc, sizeof(statsinc));
1105	statsinc.errors_out = 1;
1106	ifnet_stat_increment(ifp, &statsinc);
1107	lck_mtx_unlock(ppp_domain_mutex);
1108    return error;
1109}
1110
1111/* -----------------------------------------------------------------------------
1112add protocol function
1113called from dlil when a network protocol is attached for an
1114interface from that family (i.e ip is attached through ppp_attach_ip)
1115----------------------------------------------------------------------------- */
1116int  ppp_if_add_proto(ifnet_t ifp, protocol_family_t protocol_family,
1117			const struct ifnet_demux_desc *demux_list, u_int32_t demux_count)
1118{
1119    LOGDBG(ifp, ("ppp_if_add_proto = %d, ifp = %p\n", protocol_family, ifp));
1120
1121    switch (protocol_family) {
1122        case PF_INET:
1123        case PF_INET6:
1124            break;
1125        default:
1126            return EINVAL;	// happen for unknown protocol, or for empty descriptor
1127    }
1128
1129    return 0;
1130}
1131
1132/* -----------------------------------------------------------------------------
1133delete protocol function
1134called from dlil when a network protocol is detached for an
1135interface from that family (i.e ip is attached through ppp_detach_ip)
1136----------------------------------------------------------------------------- */
1137int  ppp_if_del_proto(ifnet_t ifp, protocol_family_t protocol_family)
1138{
1139
1140    LOGDBG(ifp, ("ppp_if_del_proto, ifp = %p\n", ifp));
1141
1142    return 0;
1143}
1144
1145/* -----------------------------------------------------------------------------
1146demux function
1147----------------------------------------------------------------------------- */
1148int ppp_if_demux(ifnet_t ifp, mbuf_t m, char *frame_header,
1149                  protocol_family_t *protocol_family)
1150{
1151    u_int16_t 		proto;
1152
1153    proto = frame_header[0];
1154    if (!proto & 0x1) {  // lowest bit set for lowest byte of protocol
1155        proto = (proto << 8) + frame_header[1];
1156    }
1157
1158    switch (proto) {
1159        case PPP_IP:
1160			// We could check pppfam->ip_attached, but dlil will handle case where it isn't
1161			*protocol_family = PF_INET;
1162            break;
1163        case PPP_IPV6:
1164			// We could check pppfam->ipv6_attached, but dlil will handle case where it isn't
1165			*protocol_family = PF_INET6;
1166            break;
1167        default :
1168            LOGDBG(ifp, ("ppp_fam_demux, ifp = %p, bad proto = 0x%x\n", ifp, proto));
1169            return ENOENT;	// should never happen
1170    }
1171
1172    return 0;
1173}
1174
1175/* -----------------------------------------------------------------------------
1176a network packet needs to be send through the interface.
1177add the ppp header to the packet (as a network interface, we only worry
1178about adding our protocol number)
1179----------------------------------------------------------------------------- */
1180errno_t ppp_if_frameout(ifnet_t ifp, mbuf_t *m0,
1181						const struct sockaddr *ndest, const char *edst, const char *ppp_type
1182#if KPI_INTERFACE_EMBEDDED
1183						, u_int32_t *pre, u_int32_t *post
1184#endif /* KPI_INTERFACE_EMBEDDED */
1185						)
1186
1187{
1188    u_int16_t aligned_type;
1189
1190	struct		ifnet_stat_increment_param statsinc;
1191
1192    if (mbuf_prepend(m0, 2, MBUF_DONTWAIT) != 0) {
1193        LOGDBG(ifp, ("ppp_fam_ifoutput : no memory for transmit header\n"));
1194		bzero(&statsinc, sizeof(statsinc));
1195		statsinc.errors_out = 1;
1196		ifnet_stat_increment(ifp, &statsinc);
1197        return EJUSTRETURN;	// just return, because the buffer was freed in m_prepend
1198    }
1199
1200#if KPI_INTERFACE_EMBEDDED
1201	*pre = 2;
1202	*post = 0;
1203#endif /* KPI_INTERFACE_EMBEDDED */
1204
1205    // place protocol number at the beginning of the mbuf
1206    // Wcast-align fix - memcpy for unaligned moves
1207    memcpy(&aligned_type, ppp_type, sizeof(aligned_type));
1208    aligned_type = htons(aligned_type);
1209    memcpy(mbuf_data(*m0), &aligned_type, sizeof(aligned_type));
1210
1211
1212    return 0;
1213}
1214
1215/* -----------------------------------------------------------------------------
1216 * Connect a PPP channel to a PPP interface unit.
1217----------------------------------------------------------------------------- */
1218int ppp_if_attachlink(struct ppp_link *link, int unit)
1219{
1220    struct ppp_if 	*wan;
1221
1222	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
1223
1224    if (link->lk_ifnet)	// already attached
1225        return EINVAL;
1226
1227    wan = ppp_if_findunit(unit);
1228    if (!wan)
1229	return EINVAL;
1230
1231	ifnet_set_flags(wan->net, IFF_RUNNING, IFF_RUNNING);
1232    ifnet_set_baudrate(wan->net, ifnet_baudrate(wan->net) + link->lk_baudrate);
1233
1234    TAILQ_INSERT_TAIL(&wan->link_head, link, lk_bdl_next);
1235    wan->nblinks++;
1236    link->lk_ifnet = wan->net;
1237
1238    return 0;
1239}
1240
1241/* -----------------------------------------------------------------------------
1242 * Disconnect a channel from its ppp unit.
1243----------------------------------------------------------------------------- */
1244int ppp_if_detachlink(struct ppp_link *link)
1245{
1246    ifnet_t			 ifp = (__typeof__(ifp))link->lk_ifnet;
1247    struct ppp_if 	*wan;
1248
1249	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
1250
1251    if (!ifp)
1252        return EINVAL; // link already detached
1253
1254    wan = ifnet_softc(ifp);
1255
1256    // check if this is the last link, when multilink is coded
1257    ifnet_set_flags(ifp, 0, IFF_RUNNING);
1258    ifnet_set_baudrate(ifp, ifnet_baudrate(ifp) - link->lk_baudrate);
1259
1260    TAILQ_REMOVE(&wan->link_head, link, lk_bdl_next);
1261    wan->nblinks--;
1262    link->lk_ifnet = 0;
1263    return 0;
1264}
1265
1266/* -----------------------------------------------------------------------------
1267----------------------------------------------------------------------------- */
1268int ppp_if_send(ifnet_t ifp, mbuf_t m)
1269{
1270    struct ppp_if 	*wan = ifnet_softc(ifp);
1271    u_int16_t		proto;
1272	struct			ifnet_stat_increment_param statsinc;
1273	int				error = 0;
1274
1275	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
1276
1277    memcpy(&proto, mbuf_data(m), sizeof(u_int16_t));	// always the 2 first bytes
1278    proto = ntohs(proto);
1279
1280    if (ppp_qfull(&wan->sndq)) {
1281        ppp_drop(&wan->sndq);
1282		bzero(&statsinc, sizeof(statsinc));
1283		statsinc.errors_out = 1;
1284		ifnet_stat_increment(ifp, &statsinc);
1285        mbuf_freem(m);
1286        return ENOBUFS;
1287    }
1288
1289    switch (proto) {
1290        case PPP_IP:
1291            // see if we can compress it
1292            if ((wan->sc_flags & SC_COMP_TCP) && wan->vjcomp) {
1293                mbuf_t		mp = m;
1294                struct ip 	ip_data, *ip = mbuf_data(m) + 2;
1295                int 		vjtype, len;
1296
1297                // skip mbuf, in case the ppp header and ip header are not in the same mbuf
1298                if (mbuf_len(mp) <= 2) {
1299                    mp = mbuf_next(mp);
1300                    if (!mp)
1301                        break;
1302                    ip = mbuf_data(mp);
1303                }
1304
1305		memcpy(&ip_data, ip, sizeof(ip_data));
1306
1307                // this code assumes the IP/TCP header is in one non-shared mbuf
1308                if (ip_data.ip_p == IPPROTO_TCP) {
1309                    vjtype = sl_compress_tcp(mp, &ip_data, wan->vjcomp, !(wan->sc_flags & SC_NO_TCP_CCID));
1310		    memcpy(ip, &ip_data, sizeof(ip_data));
1311                    switch (vjtype) {
1312                        case TYPE_UNCOMPRESSED_TCP:
1313                            proto = htons(PPP_VJC_UNCOMP); // update protocol
1314                            break;
1315                        case TYPE_COMPRESSED_TCP:
1316                            proto = htons(PPP_VJC_COMP); // header has moved, update protocol
1317			memcpy(mbuf_data(m), &proto, sizeof(u_int16_t));
1318                        break;
1319                    }
1320                    // adjust packet len
1321                    len = 0;
1322                    for (mp = m; mp != 0; mp = mbuf_next(mp))
1323                        len += mbuf_len(mp);
1324                    mbuf_pkthdr_setlen(m, len);
1325                }
1326            }
1327            break;
1328        case PPP_CCP:
1329            mbuf_adj(m, 2);
1330            ppp_comp_ccp(wan, m, 0);
1331            if (mbuf_prepend(&m, 2, MBUF_DONTWAIT) != 0) {
1332                bzero(&statsinc, sizeof(statsinc));
1333                statsinc.errors_out = 1;
1334                ifnet_stat_increment(ifp, &statsinc);
1335                return ENOBUFS;
1336            }
1337            break;
1338    }
1339
1340    if (wan->sc_flags & SC_COMP_RUN) {
1341
1342        if (ppp_comp_compress(wan, &m) == COMP_OK) {
1343            if (mbuf_prepend(&m, 2, MBUF_DONTWAIT) != 0) {
1344				bzero(&statsinc, sizeof(statsinc));
1345				statsinc.errors_out = 1;
1346				ifnet_stat_increment(ifp, &statsinc);
1347                return ENOBUFS;
1348            }
1349            proto = htons(PPP_COMP); // update protocol
1350	    memcpy(mbuf_data(m), &proto, sizeof(u_int16_t));
1351        }
1352    }
1353
1354    if (wan->sndq.len) {
1355        ppp_enqueue(&wan->sndq, m);
1356    }
1357    else
1358		error = ppp_if_xmit(ifp, m);
1359
1360    return error;
1361}
1362
1363/* -----------------------------------------------------------------------------
1364----------------------------------------------------------------------------- */
1365int ppp_if_xmit(ifnet_t ifp, mbuf_t m)
1366{
1367    struct ppp_if 	*wan = ifnet_softc(ifp);
1368    struct ppp_link	*link;
1369    int 		error = 0, len;
1370	struct		ifnet_stat_increment_param statsinc;
1371
1372	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
1373
1374    if (m == 0)
1375        m = ppp_dequeue(&wan->sndq);
1376
1377    while (m) {
1378
1379        link = TAILQ_FIRST(&wan->link_head);
1380        if (link == 0) {
1381            LOGDBG(ifp, ("ppp%d: Trying to send data with link detached\n", ifnet_unit(ifp)));
1382            // just flush everything
1383            error = ENXIO;
1384			goto flush;
1385        }
1386
1387        if (link->lk_flags & SC_HOLD) {
1388            // should try next link
1389            mbuf_freem(m);
1390            m = ppp_dequeue(&wan->sndq);
1391            continue;
1392        }
1393
1394        if (link->lk_flags & (SC_XMIT_BUSY | SC_XMIT_FULL)) {
1395            // should try next link
1396            ppp_prepend(&wan->sndq, m);
1397            return 0;
1398        }
1399
1400        // get the len before we send the packet,
1401        // we can not assume the state of the mbuf when we return
1402        len = mbuf_len(m);
1403
1404        // since we tested the lk_flags, ppp_link_send should not failed
1405        // except if there is a dramatic error
1406        link->lk_flags |= SC_XMIT_BUSY;
1407        error = ppp_link_send(link, m);
1408        link->lk_flags &= ~SC_XMIT_BUSY;
1409        if (error) {
1410            // packet has been freed by link lower layer
1411			m = 0;
1412			goto flush;
1413        }
1414
1415         m = ppp_dequeue(&wan->sndq);
1416    }
1417
1418    return 0;
1419
1420flush:
1421
1422	ifnet_touch_lastchange(ifp);
1423	do {
1424		bzero(&statsinc, sizeof(statsinc));
1425		statsinc.errors_out = 1;
1426		ifnet_stat_increment(ifp, &statsinc);
1427		if (m)
1428			mbuf_freem(m);
1429		m = ppp_dequeue(&wan->sndq);
1430	}
1431	while (m);
1432	return error;
1433}
1434
1435/* -----------------------------------------------------------------------------
1436----------------------------------------------------------------------------- */
1437void ppp_if_error(ifnet_t ifp)
1438{
1439    struct ppp_if 	*wan = ifnet_softc(ifp);
1440
1441	lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED);
1442
1443    // reset vj compression
1444    if (wan->vjcomp) {
1445	sl_uncompress_tcp(NULL, 0, TYPE_ERROR, wan->vjcomp);
1446    }
1447}
1448