moved here from sunos4 directory
[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.1 1996/07/01 01:01:30 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                 ifs = newifs;
263                 states = newstates;
264                 ppp_nalloc = newn;
265             }
266
267             /* Allocate a new ifnet struct if necessary. */
268             ifp = ifs[unit];
269             if (ifp == 0) {
270                 ifp = (struct ifnet *) ALLOC_NOSLEEP(sizeof (struct ifnet));
271                 if (ifp == 0)
272                     break;
273                 bzero(ifp, sizeof (struct ifnet));
274                 ifs[unit] = ifp;
275                 ifp->if_name = "ppp";
276                 ifp->if_unit = unit;
277                 ifp->if_mtu = PPP_MRU;
278                 ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
279 #ifdef IFF_MULTICAST
280                 ifp->if_flags |= IFF_MULTICAST;
281 #endif
282                 ifp->if_output = if_ppp_output;
283 #ifdef __osf__
284                 ifp->if_version = "Point-to-Point Protocol, version 2.3";
285                 ifp->if_mediamtu = 1500;
286                 ifp->if_type = IFT_PPP;
287                 ifp->if_hdrlen = PPP_HDRLEN;
288                 ifp->if_addrlen = 0;
289 #ifdef NETMASTERCPU
290                 ifp->if_affinity = NETMASTERCPU;
291 #endif
292 #endif
293                 ifp->if_ioctl = if_ppp_ioctl;
294                 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
295                 if_attach(ifp);
296                 if (sp->flags & DBGLOG)
297                     printf("if_ppp: created unit %d\n", unit);
298             } else {
299                 ifp->if_mtu = PPP_MRU;
300                 ifp->if_flags |= IFF_RUNNING;
301             }
302
303             states[unit] = sp;
304             sp->unit = unit;
305
306             error = 0;
307             iop->ioc_count = 0;
308             if (sp->flags & DBGLOG)
309                 printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
310                        sp, sp->q);
311             break;
312
313         case PPPIO_DEBUG:
314             error = -1;
315             if (iop->ioc_count == sizeof(int)) {
316                 if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
317                     printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
318                     sp->flags |= DBGLOG;
319                     error = 0;
320                     iop->ioc_count = 0;
321                 }
322             }
323             break;
324
325         default:
326             error = -1;
327             break;
328         }
329
330         if (sp->flags & DBGLOG)
331             printf("if_ppp: ioctl result %d\n", error);
332         if (error < 0)
333             putnext(q, mp);
334         else if (error == 0) {
335             mp->b_datap->db_type = M_IOCACK;
336             qreply(q, mp);
337         } else {
338             mp->b_datap->db_type = M_IOCNAK;
339             iop->ioc_count = 0;
340             iop->ioc_error = error;
341             qreply(q, mp);
342         }
343         break;
344
345     default:
346         putnext(q, mp);
347     }
348     return 0;
349 }
350
351 static int
352 if_ppp_rput(q, mp)
353     queue_t *q;
354     mblk_t *mp;
355 {
356     if_ppp_t *sp;
357     int proto, s;
358     struct mbuf *mb;
359     struct ifqueue *inq;
360     struct ifnet *ifp;
361     int len;
362
363     sp = (if_ppp_t *) q->q_ptr;
364     switch (mp->b_datap->db_type) {
365     case M_DATA:
366         /*
367          * Convert the message into an mbuf chain
368          * and inject it into the network code.
369          */
370         if (sp->flags & DBGLOG)
371             printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
372                    msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
373                    mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
374                    mp->b_rptr[7]);
375
376         if (sp->unit < 0) {
377             freemsg(mp);
378             break;
379         }
380         if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
381 #ifdef DEBUG
382             printf("if_ppp: no unit %d!\n", sp->unit);
383 #endif
384             freemsg(mp);
385             break;
386         }
387
388         if ((ifp->if_flags & IFF_UP) == 0) {
389             freemsg(mp);
390             break;
391         }
392         ++ifp->if_ipackets;
393
394         proto = PPP_PROTOCOL(mp->b_rptr);
395         adjmsg(mp, PPP_HDRLEN);
396         len = msgdsize(mp);
397         mb = make_mbufs(mp, sizeof(struct ifnet *));
398         freemsg(mp);
399         if (mb == NULL) {
400             if (sp->flags & DBGLOG)
401                 printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
402             ++ifp->if_ierrors;
403             break;
404         }
405
406 /* For Digital UNIX, there's space set aside in the header mbuf
407  * for the interface info.
408  *
409  * For Sun it's smuggled around via a pointer at the front of the mbuf
410  */
411 #ifdef __osf__
412         mb->m_pkthdr.rcvif = ifp;
413         mb->m_pkthdr.len = len;
414 #else
415         mb->m_off -= sizeof(struct ifnet *);
416         mb->m_len += sizeof(struct ifnet *);
417         *mtod(mb, struct ifnet **) = ifp;
418 #endif
419
420         inq = 0;
421         switch (proto) {
422         case PPP_IP:
423             inq = &ipintrq;
424             schednetisr(NETISR_IP);
425         }
426
427         if (inq != 0) {
428             s = splhigh();
429             if (IF_QFULL(inq)) {
430                 IF_DROP(inq);
431                 ++ifp->if_ierrors;
432                 if (sp->flags & DBGLOG)
433                     printf("if_ppp: inq full, proto=%x\n", proto);
434                 m_freem(mb);
435             } else {
436                 IF_ENQUEUE(inq, mb);
437             }
438             splx(s);
439         } else {
440             if (sp->flags & DBGLOG)
441                 printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
442             ++ifp->if_ierrors;
443             m_freem(mb);
444         }
445         break;
446
447     default:
448         putnext(q, mp);
449     }
450     return 0;
451 }
452
453 /*
454  * Network code wants to output a packet.
455  * Turn it into a STREAMS message and send it down.
456  */
457 static int
458 if_ppp_output(ifp, m0, dst)
459     struct ifnet *ifp;
460     struct mbuf *m0;
461     struct sockaddr *dst;
462 {
463     mblk_t *mp;
464     int proto, s;
465     if_ppp_t *sp;
466     u_char *p;
467
468     if ((ifp->if_flags & IFF_UP) == 0) {
469         m_freem(m0);
470         return ENETDOWN;
471     }
472
473     if ((unsigned)ifp->if_unit >= ppp_nalloc) {
474 #ifdef DEBUG
475         printf("if_ppp_output: unit %d?\n", ifp->if_unit);
476 #endif
477         m_freem(m0);
478         return EINVAL;
479     }
480     sp = states[ifp->if_unit];
481     if (sp == 0) {
482 #ifdef DEBUG
483         printf("if_ppp_output: no queue?\n");
484 #endif
485         m_freem(m0);
486         return ENETDOWN;
487     }
488
489     if (sp->flags & DBGLOG) {
490         p = mtod(m0, u_char *);
491         printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
492                ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
493                p[5], p[6], p[7], sp->q);
494     }
495
496     switch (dst->sa_family) {
497     case AF_INET:
498         proto = PPP_IP;
499         break;
500     default:
501         m_freem(m0);
502         return EAFNOSUPPORT;
503     }
504
505     ++ifp->if_opackets;
506     mp = make_message(m0, PPP_HDRLEN);
507     m_freem(m0);
508     if (mp == 0) {
509         ++ifp->if_oerrors;
510         return ENOBUFS;
511     }
512     mp->b_rptr -= PPP_HDRLEN;
513     mp->b_rptr[0] = PPP_ALLSTATIONS;
514     mp->b_rptr[1] = PPP_UI;
515     mp->b_rptr[2] = proto >> 8;
516     mp->b_rptr[3] = proto;
517
518     s = splstr();
519     if (sp->flags & DBGLOG)
520         printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
521                sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
522     putnext(sp->q, mp);
523     splx(s);
524
525     return 0;
526 }
527
528 /*
529  * Socket ioctl routine for ppp interfaces.
530  */
531 static int
532 if_ppp_ioctl(ifp, cmd, data)
533     struct ifnet *ifp;
534     u_int cmd;
535     caddr_t data;
536 {
537     int s, error;
538     struct ifreq *ifr = (struct ifreq *) data;
539     struct ifaddr *ifa = (struct ifaddr *) data;
540
541     error = 0;
542     s = splimp();
543     switch (cmd) {
544     case SIOCSIFFLAGS:
545         if ((ifp->if_flags & IFF_RUNNING) == 0)
546             ifp->if_flags &= ~IFF_UP;
547         break;
548
549     case SIOCSIFADDR:
550         if (IFA_ADDR(ifa).sa_family != AF_INET)
551             error = EAFNOSUPPORT;
552         break;
553
554     case SIOCSIFDSTADDR:
555         if (IFA_ADDR(ifa).sa_family != AF_INET)
556             error = EAFNOSUPPORT;
557         break;
558
559     case SIOCSIFMTU:
560         if ((error = NOTSUSER()) != 0)
561             break;
562         if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
563             error = EINVAL;
564             break;
565         }
566         ifp->if_mtu = ifr->ifr_mtu;
567         break;
568
569     case SIOCGIFMTU:
570         ifr->ifr_mtu = ifp->if_mtu;
571         break;
572
573     case SIOCADDMULTI:
574     case SIOCDELMULTI:
575         switch(ifr->ifr_addr.sa_family) {
576         case AF_INET:
577             break;
578         default:
579             error = EAFNOSUPPORT;
580             break;
581         }
582         break;
583
584     default:
585         error = EINVAL;
586     }
587     splx(s);
588     return (error);
589 }
590
591 /*
592  * Turn a STREAMS message into an mbuf chain.
593  */
594 static struct mbuf *
595 make_mbufs(mp, off)
596     mblk_t *mp;
597     int off;
598 {
599     struct mbuf *head, **prevp, *m;
600     int len, space, n;
601     unsigned char *cp, *dp;
602
603     len = msgdsize(mp);
604     if (len == 0)
605         return 0;
606     prevp = &head;
607     space = 0;
608     cp = mp->b_rptr;
609 #ifdef __osf__
610     MGETHDR(m, M_DONTWAIT, MT_DATA);
611     m->m_len = 0;
612     space = MHLEN;
613     *prevp = m;
614     prevp = &m->m_next;
615     dp = mtod(m, unsigned char *);
616     len -= space;
617     off = 0;
618 #endif
619     for (;;) {
620         while (cp >= mp->b_wptr) {
621             mp = mp->b_cont;
622             if (mp == 0) {
623                 *prevp = 0;
624                 return head;
625             }
626             cp = mp->b_rptr;
627         }
628         n = mp->b_wptr - cp;
629         if (space == 0) {
630             MGET(m, M_DONTWAIT, MT_DATA);
631             *prevp = m;
632             if (m == 0) {
633                 if (head != 0)
634                     m_freem(head);
635                 return 0;
636             }
637             if (len + off > 2 * MLEN) {
638 #ifdef __osf__
639                 MCLGET(m, M_DONTWAIT);
640 #else
641                 MCLGET(m);
642 #endif
643             }
644 #ifdef __osf__
645             space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);
646 #else
647             space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
648             m->m_off += off;
649 #endif
650             m->m_len = 0;
651             len -= space;
652             dp = mtod(m, unsigned char *);
653             off = 0;
654             prevp = &m->m_next;
655         }
656         if (n > space)
657             n = space;
658         bcopy(cp, dp, n);
659         cp += n;
660         dp += n;
661         space -= n;
662         m->m_len += n;
663     }
664 }
665
666 /*
667  * Turn an mbuf chain into a STREAMS message.
668  */
669 #define ALLOCB_MAX      4096
670
671 static mblk_t *
672 make_message(m, off)
673     struct mbuf *m;
674     int off;
675 {
676     mblk_t *head, **prevp, *mp;
677     int len, space, n, nb;
678     unsigned char *cp, *dp;
679     struct mbuf *nm;
680
681     len = 0;
682     for (nm = m; nm != 0; nm = nm->m_next)
683         len += nm->m_len;
684     prevp = &head;
685     space = 0;
686     cp = mtod(m, unsigned char *);
687     nb = m->m_len;
688     for (;;) {
689         while (nb <= 0) {
690             m = m->m_next;
691             if (m == 0) {
692                 *prevp = 0;
693                 return head;
694             }
695             cp = mtod(m, unsigned char *);
696             nb = m->m_len;
697         }
698         if (space == 0) {
699             space = len + off;
700             if (space > ALLOCB_MAX)
701                 space = ALLOCB_MAX;
702             mp = allocb(space, BPRI_LO);
703             *prevp = mp;
704             if (mp == 0) {
705                 if (head != 0)
706                     freemsg(head);
707                 return 0;
708             }
709             dp = mp->b_rptr += off;
710             space -= off;
711             len -= space;
712             off = 0;
713             prevp = &mp->b_cont;
714         }
715         n = nb < space? nb: space;
716         bcopy(cp, dp, n);
717         cp += n;
718         dp += n;
719         nb -= n;
720         space -= n;
721         mp->b_wptr = dp;
722     }
723 }
724
725 /* Digital UNIX doesn't allow for removing ifnet structures
726  * from the list.  Taking the i/f down from pppd will take
727  * care of most of the stuff that this code intends to do
728  * anyhow
729  */
730 #ifndef __osf__
731
732 /*
733  * Remove an interface from the system.
734  * This routine contains magic.
735  */
736 #include <net/route.h>
737 #include <netinet/in_pcb.h>
738 #include <netinet/ip_var.h>
739 #include <netinet/tcp.h>
740 #include <netinet/tcp_timer.h>
741 #include <netinet/tcp_var.h>
742 #include <netinet/udp.h>
743 #include <netinet/udp_var.h>
744
745 static void
746 ppp_if_detach(ifp)
747     struct ifnet *ifp;
748 {
749     int s;
750     struct inpcb *pcb;
751     struct ifaddr *ifa;
752     struct in_ifaddr **inap;
753     struct ifnet **ifpp;
754
755     s = splhigh();
756
757     /*
758      * Clear the interface from any routes currently cached in
759      * TCP or UDP protocol control blocks.
760      */
761     for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next)
762         if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
763             in_losing(pcb);
764     for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
765         if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
766             in_losing(pcb);
767
768     /*
769      * Delete routes through all addresses of the interface.
770      */
771     for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) {
772         rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
773         rtinit(ifa, ifa, SIOCDELRT, 0);
774     }
775
776     /*
777      * Unlink the interface's address(es) from the in_ifaddr list.
778      */
779     for (inap = &in_ifaddr; *inap != 0; ) {
780         if ((*inap)->ia_ifa.ifa_ifp == ifp)
781             *inap = (*inap)->ia_next;
782         else
783             inap = &(*inap)->ia_next;
784     }
785
786     /*
787      * Delete the interface from the ifnet list.
788      */
789     for (ifpp = &ifnet; (*ifpp) != 0; ) {
790         if (*ifpp == ifp)
791             break;
792         ifpp = &(*ifpp)->if_next;
793     }
794     if (*ifpp == 0)
795         printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
796     else
797         *ifpp = ifp->if_next;
798
799     splx(s);
800 }
801
802 #endif /* __osf__ */