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