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