]> git.ozlabs.org Git - ppp.git/blob - modules/if_ppp.c
pppd: Fix spelling errors in man page
[ppp.git] / modules / if_ppp.c
1 /*
2  * if_ppp.c - a network interface connected to a STREAMS module.
3  *
4  * Copyright (c) 1994 Paul Mackerras. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. The name(s) of the authors of this software must not be used to
19  *    endorse or promote products derived from this software without
20  *    prior written permission.
21  *
22  * 4. Redistributions of any form whatsoever must retain the following
23  *    acknowledgment:
24  *    "This product includes software developed by Paul Mackerras
25  *     <paulus@samba.org>".
26  *
27  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
28  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
30  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
32  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
33  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34  *
35  * $Id: if_ppp.c,v 1.18 2002/12/06 09:49:15 paulus Exp $
36  */
37
38 /*
39  * This file is used under SunOS 4 and Digital UNIX.
40  *
41  * This file provides the glue between PPP and IP.
42  */
43
44 #define INET    1
45
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/errno.h>
49 #include <sys/mbuf.h>
50 #include <sys/socket.h>
51 #include <net/if.h>
52 #include <net/netisr.h>
53 #include <net/ppp_defs.h>
54 #include <net/pppio.h>
55 #include <netinet/in.h>
56 #include <netinet/in_var.h>
57 #ifdef __osf__
58 #include <sys/ioctl.h>
59 #include <net/if_types.h>
60 #else
61 #include <sys/sockio.h>
62 #endif
63 #include "ppp_mod.h"
64
65 #include <sys/stream.h>
66
67 #ifdef SNIT_SUPPORT
68 #include <sys/time.h>
69 #include <net/nit_if.h>
70 #include <netinet/if_ether.h>
71 #endif
72
73 #ifdef __osf__
74 #define SIOCSIFMTU SIOCSIPMTU
75 #define SIOCGIFMTU SIOCRIPMTU
76 #define IFA_ADDR(ifa)   (*(ifa)->ifa_addr)
77 #else
78 #define IFA_ADDR(ifa)   ((ifa)->ifa_addr)
79 #endif
80
81 #define ifr_mtu         ifr_metric
82
83 static int if_ppp_open __P((queue_t *, int, int, int));
84 static int if_ppp_close __P((queue_t *, int));
85 static int if_ppp_wput __P((queue_t *, mblk_t *));
86 static int if_ppp_rput __P((queue_t *, mblk_t *));
87
88 #define PPP_IF_ID 0x8021
89 static struct module_info minfo = {
90     PPP_IF_ID, "if_ppp", 0, INFPSZ, 4096, 128
91 };
92
93 static struct qinit rinit = {
94     if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL
95 };
96
97 static struct qinit winit = {
98     if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
99 };
100
101 struct streamtab if_pppinfo = {
102     &rinit, &winit, NULL, NULL
103 };
104
105 typedef struct if_ppp_state {
106     int unit;
107     queue_t *q;
108     int flags;
109 } if_ppp_t;
110
111 /* Values for flags */
112 #define DBGLOG          1
113
114 static int if_ppp_count;        /* Number of currently-active streams */
115
116 static int ppp_nalloc;          /* Number of elements of ifs and states */
117 static struct ifnet **ifs;      /* Array of pointers to interface structs */
118 static if_ppp_t **states;       /* Array of pointers to state structs */
119
120 static int if_ppp_output __P((struct ifnet *, struct mbuf *,
121                               struct sockaddr *));
122 static int if_ppp_ioctl __P((struct ifnet *, u_int, caddr_t));
123 static struct mbuf *make_mbufs __P((mblk_t *, int));
124 static mblk_t *make_message __P((struct mbuf *, int));
125
126 #ifdef SNIT_SUPPORT
127 /* Fake ether header for SNIT */
128 static struct ether_header snit_ehdr = {{0}, {0}, ETHERTYPE_IP};
129 #endif
130
131 #ifndef __osf__
132 static void ppp_if_detach __P((struct ifnet *));
133
134 /*
135  * Detach all the interfaces before unloading.
136  * Not sure this works.
137  */
138 int
139 if_ppp_unload()
140 {
141     int i;
142
143     if (if_ppp_count > 0)
144         return EBUSY;
145     for (i = 0; i < ppp_nalloc; ++i)
146         if (ifs[i] != 0)
147             ppp_if_detach(ifs[i]);
148     if (ifs) {
149         FREE(ifs, ppp_nalloc * sizeof (struct ifnet *));
150         FREE(states, ppp_nalloc * sizeof (struct if_ppp_t *));
151     }
152     ppp_nalloc = 0;
153     return 0;
154 }
155 #endif /* __osf__ */
156
157 /*
158  * STREAMS module entry points.
159  */
160 static int
161 if_ppp_open(q, dev, flag, sflag)
162     queue_t *q;
163     int dev;
164     int flag, sflag;
165 {
166     if_ppp_t *sp;
167
168     if (q->q_ptr == 0) {
169         sp = (if_ppp_t *) ALLOC_SLEEP(sizeof (if_ppp_t));
170         if (sp == 0)
171             return OPENFAIL;
172         bzero(sp, sizeof (if_ppp_t));
173         q->q_ptr = (caddr_t) sp;
174         WR(q)->q_ptr = (caddr_t) sp;
175         sp->unit = -1;          /* no interface unit attached at present */
176         sp->q = WR(q);
177         sp->flags = 0;
178         ++if_ppp_count;
179     }
180     return 0;
181 }
182
183 static int
184 if_ppp_close(q, flag)
185     queue_t *q;
186     int flag;
187 {
188     if_ppp_t *sp;
189     struct ifnet *ifp;
190
191     sp = (if_ppp_t *) q->q_ptr;
192     if (sp != 0) {
193         if (sp->flags & DBGLOG)
194             printf("if_ppp closed, q=%x sp=%x\n", q, sp);
195         if (sp->unit >= 0) {
196             if (sp->unit < ppp_nalloc) {
197                 states[sp->unit] = 0;
198                 ifp = ifs[sp->unit];
199                 if (ifp != 0)
200                     ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
201 #ifdef DEBUG
202             } else {
203                 printf("if_ppp: unit %d nonexistent!\n", sp->unit);
204 #endif
205             }
206         }
207         FREE(sp, sizeof (if_ppp_t));
208         --if_ppp_count;
209     }
210     return 0;
211 }
212
213 static int
214 if_ppp_wput(q, mp)
215     queue_t *q;
216     mblk_t *mp;
217 {
218     if_ppp_t *sp;
219     struct iocblk *iop;
220     int error, unit;
221     struct ifnet *ifp;
222
223     sp = (if_ppp_t *) q->q_ptr;
224     switch (mp->b_datap->db_type) {
225     case M_DATA:
226         /*
227          * Now why would we be getting data coming in here??
228          */
229         if (sp->flags & DBGLOG)
230             printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp));
231         freemsg(mp);
232         break;
233
234     case M_IOCTL:
235         iop = (struct iocblk *) mp->b_rptr;
236         error = EINVAL;
237
238         if (sp->flags & DBGLOG)
239             printf("if_ppp: got ioctl cmd=%x count=%d\n",
240                    iop->ioc_cmd, iop->ioc_count);
241
242         switch (iop->ioc_cmd) {
243         case PPPIO_NEWPPA:              /* well almost */
244             if (iop->ioc_count != sizeof(int) || sp->unit >= 0)
245                 break;
246             if ((error = NOTSUSER()) != 0)
247                 break;
248             unit = *(int *)mp->b_cont->b_rptr;
249
250             /* Check that this unit isn't already in use */
251             if (unit < ppp_nalloc && states[unit] != 0) {
252                 error = EADDRINUSE;
253                 break;
254             }
255
256             /* Extend ifs and states arrays if necessary. */
257             error = ENOSR;
258             if (unit >= ppp_nalloc) {
259                 int newn;
260                 struct ifnet **newifs;
261                 if_ppp_t **newstates;
262
263                 newn = unit + 4;
264                 if (sp->flags & DBGLOG)
265                     printf("if_ppp: extending ifs to %d\n", newn);
266                 newifs = (struct ifnet **)
267                     ALLOC_NOSLEEP(newn * sizeof (struct ifnet *));
268                 if (newifs == 0)
269                     break;
270                 bzero(newifs, newn * sizeof (struct ifnet *));
271                 newstates = (if_ppp_t **)
272                     ALLOC_NOSLEEP(newn * sizeof (struct if_ppp_t *));
273                 if (newstates == 0) {
274                     FREE(newifs, newn * sizeof (struct ifnet *));
275                     break;
276                 }
277                 bzero(newstates, newn * sizeof (struct if_ppp_t *));
278                 bcopy(ifs, newifs, ppp_nalloc * sizeof(struct ifnet *));
279                 bcopy(states, newstates, ppp_nalloc * sizeof(if_ppp_t *));
280                 if (ifs) {
281                     FREE(ifs, ppp_nalloc * sizeof(struct ifnet *));
282                     FREE(states, ppp_nalloc * sizeof(if_ppp_t *));
283                 }
284                 ifs = newifs;
285                 states = newstates;
286                 ppp_nalloc = newn;
287             }
288
289             /* Allocate a new ifnet struct if necessary. */
290             ifp = ifs[unit];
291             if (ifp == 0) {
292                 ifp = (struct ifnet *) ALLOC_NOSLEEP(sizeof (struct ifnet));
293                 if (ifp == 0)
294                     break;
295                 bzero(ifp, sizeof (struct ifnet));
296                 ifs[unit] = ifp;
297                 ifp->if_name = "ppp";
298                 ifp->if_unit = unit;
299                 ifp->if_mtu = PPP_MTU;
300                 ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
301 #ifndef __osf__
302 #ifdef IFF_MULTICAST
303                 ifp->if_flags |= IFF_MULTICAST;
304 #endif
305 #endif /* __osf__ */
306                 ifp->if_output = if_ppp_output;
307 #ifdef __osf__
308                 ifp->if_version = "Point-to-Point Protocol, version 2.3.11";
309                 ifp->if_mediamtu = PPP_MTU;
310                 ifp->if_type = IFT_PPP;
311                 ifp->if_hdrlen = PPP_HDRLEN;
312                 ifp->if_addrlen = 0;
313                 ifp->if_flags |= IFF_NOARP | IFF_SIMPLEX | IFF_NOTRAILERS;
314 #ifdef IFF_VAR_MTU
315                 ifp->if_flags |= IFF_VAR_MTU;
316 #endif
317 #ifdef NETMASTERCPU
318                 ifp->if_affinity = NETMASTERCPU;
319 #endif
320 #endif
321                 ifp->if_ioctl = if_ppp_ioctl;
322                 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
323                 if_attach(ifp);
324                 if (sp->flags & DBGLOG)
325                     printf("if_ppp: created unit %d\n", unit);
326             } else {
327                 ifp->if_mtu = PPP_MTU;
328                 ifp->if_flags |= IFF_RUNNING;
329             }
330
331             states[unit] = sp;
332             sp->unit = unit;
333
334             error = 0;
335             iop->ioc_count = 0;
336             if (sp->flags & DBGLOG)
337                 printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
338                        sp, sp->q);
339             break;
340
341         case PPPIO_DEBUG:
342             error = -1;
343             if (iop->ioc_count == sizeof(int)) {
344                 if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
345                     printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
346                     sp->flags |= DBGLOG;
347                     error = 0;
348                     iop->ioc_count = 0;
349                 }
350             }
351             break;
352
353         default:
354             error = -1;
355             break;
356         }
357
358         if (sp->flags & DBGLOG)
359             printf("if_ppp: ioctl result %d\n", error);
360         if (error < 0)
361             putnext(q, mp);
362         else if (error == 0) {
363             mp->b_datap->db_type = M_IOCACK;
364             qreply(q, mp);
365         } else {
366             mp->b_datap->db_type = M_IOCNAK;
367             iop->ioc_count = 0;
368             iop->ioc_error = error;
369             qreply(q, mp);
370         }
371         break;
372
373     default:
374         putnext(q, mp);
375     }
376     return 0;
377 }
378
379 static int
380 if_ppp_rput(q, mp)
381     queue_t *q;
382     mblk_t *mp;
383 {
384     if_ppp_t *sp;
385     int proto, s;
386     struct mbuf *mb;
387     struct ifqueue *inq;
388     struct ifnet *ifp;
389     int len;
390
391     sp = (if_ppp_t *) q->q_ptr;
392     switch (mp->b_datap->db_type) {
393     case M_DATA:
394         /*
395          * Convert the message into an mbuf chain
396          * and inject it into the network code.
397          */
398         if (sp->flags & DBGLOG)
399             printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
400                    msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
401                    mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
402                    mp->b_rptr[7]);
403
404         if (sp->unit < 0) {
405             freemsg(mp);
406             break;
407         }
408         if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
409 #ifdef DEBUG
410             printf("if_ppp: no unit %d!\n", sp->unit);
411 #endif
412             freemsg(mp);
413             break;
414         }
415
416         if ((ifp->if_flags & IFF_UP) == 0) {
417             freemsg(mp);
418             break;
419         }
420         ++ifp->if_ipackets;
421
422         proto = PPP_PROTOCOL(mp->b_rptr);
423         adjmsg(mp, PPP_HDRLEN);
424         len = msgdsize(mp);
425         mb = make_mbufs(mp, sizeof(struct ifnet *));
426         freemsg(mp);
427         if (mb == NULL) {
428             if (sp->flags & DBGLOG)
429                 printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
430             ++ifp->if_ierrors;
431             break;
432         }
433
434 #ifdef SNIT_SUPPORT
435         if (proto == PPP_IP && (ifp->if_flags & IFF_PROMISC)) {
436             struct nit_if nif;
437
438             nif.nif_header = (caddr_t) &snit_ehdr;
439             nif.nif_hdrlen = sizeof(snit_ehdr);
440             nif.nif_bodylen = len;
441             nif.nif_promisc = 0;
442             snit_intr(ifp, mb, &nif);
443         }
444 #endif
445
446 /*
447  * For Digital UNIX, there's space set aside in the header mbuf
448  * for the interface info.
449  *
450  * For Sun it's smuggled around via a pointer at the front of the mbuf.
451  */
452 #ifdef __osf__
453         mb->m_pkthdr.rcvif = ifp;
454         mb->m_pkthdr.len = len;
455 #else
456         mb->m_off -= sizeof(struct ifnet *);
457         mb->m_len += sizeof(struct ifnet *);
458         *mtod(mb, struct ifnet **) = ifp;
459 #endif
460
461         inq = 0;
462         switch (proto) {
463         case PPP_IP:
464             inq = &ipintrq;
465             schednetisr(NETISR_IP);
466         }
467
468         if (inq != 0) {
469             s = splhigh();
470             if (IF_QFULL(inq)) {
471                 IF_DROP(inq);
472                 ++ifp->if_ierrors;
473                 if (sp->flags & DBGLOG)
474                     printf("if_ppp: inq full, proto=%x\n", proto);
475                 m_freem(mb);
476             } else {
477                 IF_ENQUEUE(inq, mb);
478             }
479             splx(s);
480         } else {
481             if (sp->flags & DBGLOG)
482                 printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
483             ++ifp->if_ierrors;
484             m_freem(mb);
485         }
486         break;
487
488     default:
489         putnext(q, mp);
490     }
491     return 0;
492 }
493
494 /*
495  * Network code wants to output a packet.
496  * Turn it into a STREAMS message and send it down.
497  */
498 static int
499 if_ppp_output(ifp, m0, dst)
500     struct ifnet *ifp;
501     struct mbuf *m0;
502     struct sockaddr *dst;
503 {
504     mblk_t *mp;
505     int proto, s;
506     if_ppp_t *sp;
507     u_char *p;
508
509     if ((ifp->if_flags & IFF_UP) == 0) {
510         m_freem(m0);
511         return ENETDOWN;
512     }
513
514     if ((unsigned)ifp->if_unit >= ppp_nalloc) {
515 #ifdef DEBUG
516         printf("if_ppp_output: unit %d?\n", ifp->if_unit);
517 #endif
518         m_freem(m0);
519         return EINVAL;
520     }
521     sp = states[ifp->if_unit];
522     if (sp == 0) {
523 #ifdef DEBUG
524         printf("if_ppp_output: no queue?\n");
525 #endif
526         m_freem(m0);
527         return ENETDOWN;
528     }
529
530     if (sp->flags & DBGLOG) {
531         p = mtod(m0, u_char *);
532         printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
533                ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
534                p[5], p[6], p[7], sp->q);
535     }
536
537     switch (dst->sa_family) {
538     case AF_INET:
539         proto = PPP_IP;
540 #ifdef SNIT_SUPPORT
541         if (ifp->if_flags & IFF_PROMISC) {
542             struct nit_if nif;
543             struct mbuf *m;
544             int len;
545
546             for (len = 0, m = m0; m != NULL; m = m->m_next)
547                 len += m->m_len;
548             nif.nif_header = (caddr_t) &snit_ehdr;
549             nif.nif_hdrlen = sizeof(snit_ehdr);
550             nif.nif_bodylen = len;
551             nif.nif_promisc = 0;
552             snit_intr(ifp, m0, &nif);
553         }
554 #endif
555         break;
556
557     default:
558         m_freem(m0);
559         return EAFNOSUPPORT;
560     }
561
562     ++ifp->if_opackets;
563     mp = make_message(m0, PPP_HDRLEN);
564     m_freem(m0);
565     if (mp == 0) {
566         ++ifp->if_oerrors;
567         return ENOBUFS;
568     }
569     mp->b_rptr -= PPP_HDRLEN;
570     mp->b_rptr[0] = PPP_ALLSTATIONS;
571     mp->b_rptr[1] = PPP_UI;
572     mp->b_rptr[2] = proto >> 8;
573     mp->b_rptr[3] = proto;
574
575     s = splstr();
576     if (sp->flags & DBGLOG)
577         printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
578                sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
579     putnext(sp->q, mp);
580     splx(s);
581
582     return 0;
583 }
584
585 /*
586  * Socket ioctl routine for ppp interfaces.
587  */
588 static int
589 if_ppp_ioctl(ifp, cmd, data)
590     struct ifnet *ifp;
591     u_int cmd;
592     caddr_t data;
593 {
594     int s, error;
595     struct ifreq *ifr = (struct ifreq *) data;
596     struct ifaddr *ifa = (struct ifaddr *) data;
597     u_short mtu;
598
599     error = 0;
600     s = splimp();
601     switch (cmd) {
602     case SIOCSIFFLAGS:
603         if ((ifp->if_flags & IFF_RUNNING) == 0)
604             ifp->if_flags &= ~IFF_UP;
605         break;
606
607     case SIOCSIFADDR:
608         if (IFA_ADDR(ifa).sa_family != AF_INET)
609             error = EAFNOSUPPORT;
610         break;
611
612     case SIOCSIFDSTADDR:
613         if (IFA_ADDR(ifa).sa_family != AF_INET)
614             error = EAFNOSUPPORT;
615         break;
616
617     case SIOCSIFMTU:
618         if ((error = NOTSUSER()) != 0)
619             break;
620 #ifdef __osf__
621         /* this hack is necessary because ifioctl checks ifr_data
622          * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each 
623          * other in the definition of struct ifreq so pppd can't set both.
624          */
625         bcopy(ifr->ifr_data, &mtu, sizeof (u_short));
626         ifr->ifr_mtu = mtu;
627 #endif
628
629         if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
630             error = EINVAL;
631             break;
632         }
633         ifp->if_mtu = ifr->ifr_mtu;
634         break;
635
636     case SIOCGIFMTU:
637         ifr->ifr_mtu = ifp->if_mtu;
638         break;
639
640     case SIOCADDMULTI:
641     case SIOCDELMULTI:
642         switch(ifr->ifr_addr.sa_family) {
643         case AF_INET:
644             break;
645         default:
646             error = EAFNOSUPPORT;
647             break;
648         }
649         break;
650
651     default:
652         error = EINVAL;
653     }
654     splx(s);
655     return (error);
656 }
657
658 /*
659  * Turn a STREAMS message into an mbuf chain.
660  */
661 static struct mbuf *
662 make_mbufs(mp, off)
663     mblk_t *mp;
664     int off;
665 {
666     struct mbuf *head, **prevp, *m;
667     int len, space, n;
668     unsigned char *cp, *dp;
669
670     len = msgdsize(mp);
671     if (len == 0)
672         return 0;
673     prevp = &head;
674     space = 0;
675     cp = mp->b_rptr;
676 #ifdef __osf__
677     MGETHDR(m, M_DONTWAIT, MT_DATA);
678     m->m_len = 0;
679     space = MHLEN;
680     *prevp = m;
681     prevp = &m->m_next;
682     dp = mtod(m, unsigned char *);
683     len -= space;
684     off = 0;
685 #endif
686     for (;;) {
687         while (cp >= mp->b_wptr) {
688             mp = mp->b_cont;
689             if (mp == 0) {
690                 *prevp = 0;
691                 return head;
692             }
693             cp = mp->b_rptr;
694         }
695         n = mp->b_wptr - cp;
696         if (space == 0) {
697             MGET(m, M_DONTWAIT, MT_DATA);
698             *prevp = m;
699             if (m == 0) {
700                 if (head != 0)
701                     m_freem(head);
702                 return 0;
703             }
704             if (len + off > 2 * MLEN) {
705 #ifdef __osf__
706                 MCLGET(m, M_DONTWAIT);
707 #else
708                 MCLGET(m);
709 #endif
710             }
711 #ifdef __osf__
712             space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);
713 #else
714             space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
715             m->m_off += off;
716 #endif
717             m->m_len = 0;
718             len -= space;
719             dp = mtod(m, unsigned char *);
720             off = 0;
721             prevp = &m->m_next;
722         }
723         if (n > space)
724             n = space;
725         bcopy(cp, dp, n);
726         cp += n;
727         dp += n;
728         space -= n;
729         m->m_len += n;
730     }
731 }
732
733 /*
734  * Turn an mbuf chain into a STREAMS message.
735  */
736 #define ALLOCB_MAX      4096
737
738 static mblk_t *
739 make_message(m, off)
740     struct mbuf *m;
741     int off;
742 {
743     mblk_t *head, **prevp, *mp;
744     int len, space, n, nb;
745     unsigned char *cp, *dp;
746     struct mbuf *nm;
747
748     len = 0;
749     for (nm = m; nm != 0; nm = nm->m_next)
750         len += nm->m_len;
751     prevp = &head;
752     space = 0;
753     cp = mtod(m, unsigned char *);
754     nb = m->m_len;
755     for (;;) {
756         while (nb <= 0) {
757             m = m->m_next;
758             if (m == 0) {
759                 *prevp = 0;
760                 return head;
761             }
762             cp = mtod(m, unsigned char *);
763             nb = m->m_len;
764         }
765         if (space == 0) {
766             space = len + off;
767             if (space > ALLOCB_MAX)
768                 space = ALLOCB_MAX;
769             mp = allocb(space, BPRI_LO);
770             *prevp = mp;
771             if (mp == 0) {
772                 if (head != 0)
773                     freemsg(head);
774                 return 0;
775             }
776             dp = mp->b_rptr += off;
777             space -= off;
778             len -= space;
779             off = 0;
780             prevp = &mp->b_cont;
781         }
782         n = nb < space? nb: space;
783         bcopy(cp, dp, n);
784         cp += n;
785         dp += n;
786         nb -= n;
787         space -= n;
788         mp->b_wptr = dp;
789     }
790 }
791
792 /*
793  * Digital UNIX doesn't allow for removing ifnet structures
794  * from the list.  But then we're not using this as a loadable
795  * module anyway, so that's OK.
796  *
797  * Under SunOS, this should allow the module to be unloaded.
798  * Unfortunately, it doesn't seem to detach all the references,
799  * so your system may well crash after you unload this module :-(
800  */
801 #ifndef __osf__
802
803 /*
804  * Remove an interface from the system.
805  * This routine contains magic.
806  */
807 #include <net/route.h>
808 #include <netinet/in_pcb.h>
809 #include <netinet/ip_var.h>
810 #include <netinet/tcp.h>
811 #include <netinet/tcp_timer.h>
812 #include <netinet/tcp_var.h>
813 #include <netinet/udp.h>
814 #include <netinet/udp_var.h>
815
816 static void
817 ppp_if_detach(ifp)
818     struct ifnet *ifp;
819 {
820     int s;
821     struct inpcb *pcb;
822     struct ifaddr *ifa;
823     struct in_ifaddr **inap;
824     struct ifnet **ifpp;
825
826     s = splhigh();
827
828     /*
829      * Clear the interface from any routes currently cached in
830      * TCP or UDP protocol control blocks.
831      */
832     for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next)
833         if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
834             in_losing(pcb);
835     for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
836         if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
837             in_losing(pcb);
838
839     /*
840      * Delete routes through all addresses of the interface.
841      */
842     for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) {
843         rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
844         rtinit(ifa, ifa, SIOCDELRT, 0);
845     }
846
847     /*
848      * Unlink the interface's address(es) from the in_ifaddr list.
849      */
850     for (inap = &in_ifaddr; *inap != 0; ) {
851         if ((*inap)->ia_ifa.ifa_ifp == ifp)
852             *inap = (*inap)->ia_next;
853         else
854             inap = &(*inap)->ia_next;
855     }
856
857     /*
858      * Delete the interface from the ifnet list.
859      */
860     for (ifpp = &ifnet; (*ifpp) != 0; ) {
861         if (*ifpp == ifp)
862             break;
863         ifpp = &(*ifpp)->if_next;
864     }
865     if (*ifpp == 0)
866         printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
867     else
868         *ifpp = ifp->if_next;
869
870     splx(s);
871 }
872
873 #endif /* __osf__ */