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