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