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