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