1/* 2 * if_ppp.c - a network interface connected to a STREAMS module. 3 * 4 * Copyright (c) 1994 Paul Mackerras. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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. 17 * 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. 21 * 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>". 26 * 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. 34 * 35 * $Id: if_ppp.c,v 1.18 2002/12/06 09:49:15 paulus Exp $ 36 */ 37 38/* 39 * This file is used under SunOS 4 and Digital UNIX. 40 * 41 * This file provides the glue between PPP and IP. 42 */ 43 44#define INET 1 45 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" 64 65#include <sys/stream.h> 66 67#ifdef SNIT_SUPPORT 68#include <sys/time.h> 69#include <net/nit_if.h> 70#include <netinet/if_ether.h> 71#endif 72 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 80 81#define ifr_mtu ifr_metric 82 83static int if_ppp_open __P((queue_t *, int, int, int)); 84static int if_ppp_close __P((queue_t *, int)); 85static int if_ppp_wput __P((queue_t *, mblk_t *)); 86static int if_ppp_rput __P((queue_t *, mblk_t *)); 87 88#define PPP_IF_ID 0x8021 89static struct module_info minfo = { 90 PPP_IF_ID, "if_ppp", 0, INFPSZ, 4096, 128 91}; 92 93static struct qinit rinit = { 94 if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL 95}; 96 97static struct qinit winit = { 98 if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL 99}; 100 101struct streamtab if_pppinfo = { 102 &rinit, &winit, NULL, NULL 103}; 104 105typedef struct if_ppp_state { 106 int unit; 107 queue_t *q; 108 int flags; 109} if_ppp_t; 110 111/* Values for flags */ 112#define DBGLOG 1 113 114static int if_ppp_count; /* Number of currently-active streams */ 115 116static int ppp_nalloc; /* Number of elements of ifs and states */ 117static struct ifnet **ifs; /* Array of pointers to interface structs */ 118static if_ppp_t **states; /* Array of pointers to state structs */ 119 120static int if_ppp_output __P((struct ifnet *, struct mbuf *, 121 struct sockaddr *)); 122static int if_ppp_ioctl __P((struct ifnet *, u_int, caddr_t)); 123static struct mbuf *make_mbufs __P((mblk_t *, int)); 124static mblk_t *make_message __P((struct mbuf *, int)); 125 126#ifdef SNIT_SUPPORT 127/* Fake ether header for SNIT */ 128static struct ether_header snit_ehdr = {{0}, {0}, ETHERTYPE_IP}; 129#endif 130 131#ifndef __osf__ 132static void ppp_if_detach __P((struct ifnet *)); 133 134/* 135 * Detach all the interfaces before unloading. 136 * Not sure this works. 137 */ 138int 139if_ppp_unload() 140{ 141 int i; 142 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 *)); 151 } 152 ppp_nalloc = 0; 153 return 0; 154} 155#endif /* __osf__ */ 156 157/* 158 * STREAMS module entry points. 159 */ 160static int 161if_ppp_open(q, dev, flag, sflag) 162 queue_t *q; 163 int dev; 164 int flag, sflag; 165{ 166 if_ppp_t *sp; 167 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; 179 } 180 return 0; 181} 182 183static int 184if_ppp_close(q, flag) 185 queue_t *q; 186 int flag; 187{ 188 if_ppp_t *sp; 189 struct ifnet *ifp; 190 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 205 } 206 } 207 FREE(sp, sizeof (if_ppp_t)); 208 --if_ppp_count; 209 } 210 return 0; 211} 212 213static int 214if_ppp_wput(q, mp) 215 queue_t *q; 216 mblk_t *mp; 217{ 218 if_ppp_t *sp; 219 struct iocblk *iop; 220 int error, unit; 221 struct ifnet *ifp; 222 223 sp = (if_ppp_t *) q->q_ptr; 224 switch (mp->b_datap->db_type) { 225 case M_DATA: 226 /* 227 * Now why would we be getting data coming in here?? 228 */ 229 if (sp->flags & DBGLOG) 230 printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp)); 231 freemsg(mp); 232 break; 233 234 case M_IOCTL: 235 iop = (struct iocblk *) mp->b_rptr; 236 error = EINVAL; 237 238 if (sp->flags & DBGLOG) 239 printf("if_ppp: got ioctl cmd=%x count=%d\n", 240 iop->ioc_cmd, iop->ioc_count); 241 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; 249 250 /* Check that this unit isn't already in use */ 251 if (unit < ppp_nalloc && states[unit] != 0) { 252 error = EADDRINUSE; 253 break; 254 } 255 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; 262 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; 276 } 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 *)); 283 } 284 ifs = newifs; 285 states = newstates; 286 ppp_nalloc = newn; 287 } 288 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; 329 } 330 331 states[unit] = sp; 332 sp->unit = unit; 333 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; 340 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; 349 } 350 } 351 break; 352 353 default: 354 error = -1; 355 break; 356 } 357 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); 370 } 371 break; 372 373 default: 374 putnext(q, mp); 375 } 376 return 0; 377} 378 379static int 380if_ppp_rput(q, mp) 381 queue_t *q; 382 mblk_t *mp; 383{ 384 if_ppp_t *sp; 385 int proto, s; 386 struct mbuf *mb; 387 struct ifqueue *inq; 388 struct ifnet *ifp; 389 int len; 390 391 sp = (if_ppp_t *) q->q_ptr; 392 switch (mp->b_datap->db_type) { 393 case M_DATA: 394 /* 395 * Convert the message into an mbuf chain 396 * and inject it into the network code. 397 */ 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]); 403 404 if (sp->unit < 0) { 405 freemsg(mp); 406 break; 407 } 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; 414 } 415 416 if ((ifp->if_flags & IFF_UP) == 0) { 417 freemsg(mp); 418 break; 419 } 420 ++ifp->if_ipackets; 421 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; 432 } 433 434#ifdef SNIT_SUPPORT 435 if (proto == PPP_IP && (ifp->if_flags & IFF_PROMISC)) { 436 struct nit_if nif; 437 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); 443 } 444#endif 445 446/* 447 * For Digital UNIX, there's space set aside in the header mbuf 448 * for the interface info. 449 * 450 * For Sun it's smuggled around via a pointer at the front of the mbuf. 451 */ 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 460 461 inq = 0; 462 switch (proto) { 463 case PPP_IP: 464 inq = &ipintrq; 465 schednetisr(NETISR_IP); 466 } 467 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); 478 } 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); 485 } 486 break; 487 488 default: 489 putnext(q, mp); 490 } 491 return 0; 492} 493 494/* 495 * Network code wants to output a packet. 496 * Turn it into a STREAMS message and send it down. 497 */ 498static int 499if_ppp_output(ifp, m0, dst) 500 struct ifnet *ifp; 501 struct mbuf *m0; 502 struct sockaddr *dst; 503{ 504 mblk_t *mp; 505 int proto, s; 506 if_ppp_t *sp; 507 u_char *p; 508 509 if ((ifp->if_flags & IFF_UP) == 0) { 510 m_freem(m0); 511 return ENETDOWN; 512 } 513 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; 520 } 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; 528 } 529 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); 535 } 536 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; 545 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); 553 } 554#endif 555 break; 556 557 default: 558 m_freem(m0); 559 return EAFNOSUPPORT; 560 } 561 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; 568 } 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; 574 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); 581 582 return 0; 583} 584 585/* 586 * Socket ioctl routine for ppp interfaces. 587 */ 588static int 589if_ppp_ioctl(ifp, cmd, data) 590 struct ifnet *ifp; 591 u_int cmd; 592 caddr_t data; 593{ 594 int s, error; 595 struct ifreq *ifr = (struct ifreq *) data; 596 struct ifaddr *ifa = (struct ifaddr *) data; 597 u_short mtu; 598 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; 606 607 case SIOCSIFADDR: 608 if (IFA_ADDR(ifa).sa_family != AF_INET) 609 error = EAFNOSUPPORT; 610 break; 611 612 case SIOCSIFDSTADDR: 613 if (IFA_ADDR(ifa).sa_family != AF_INET) 614 error = EAFNOSUPPORT; 615 break; 616 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. 624 */ 625 bcopy(ifr->ifr_data, &mtu, sizeof (u_short)); 626 ifr->ifr_mtu = mtu; 627#endif 628 629 if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) { 630 error = EINVAL; 631 break; 632 } 633 ifp->if_mtu = ifr->ifr_mtu; 634 break; 635 636 case SIOCGIFMTU: 637 ifr->ifr_mtu = ifp->if_mtu; 638 break; 639 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; 648 } 649 break; 650 651 default: 652 error = EINVAL; 653 } 654 splx(s); 655 return (error); 656} 657 658/* 659 * Turn a STREAMS message into an mbuf chain. 660 */ 661static struct mbuf * 662make_mbufs(mp, off) 663 mblk_t *mp; 664 int off; 665{ 666 struct mbuf *head, **prevp, *m; 667 int len, space, n; 668 unsigned char *cp, *dp; 669 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; 692 } 693 cp = mp->b_rptr; 694 } 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; 703 } 704 if (len + off > 2 * MLEN) { 705#ifdef __osf__ 706 MCLGET(m, M_DONTWAIT); 707#else 708 MCLGET(m); 709#endif 710 } 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; 722 } 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; 730 } 731} 732 733/* 734 * Turn an mbuf chain into a STREAMS message. 735 */ 736#define ALLOCB_MAX 4096 737 738static mblk_t * 739make_message(m, off) 740 struct mbuf *m; 741 int off; 742{ 743 mblk_t *head, **prevp, *mp; 744 int len, space, n, nb; 745 unsigned char *cp, *dp; 746 struct mbuf *nm; 747 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; 761 } 762 cp = mtod(m, unsigned char *); 763 nb = m->m_len; 764 } 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; 775 } 776 dp = mp->b_rptr += off; 777 space -= off; 778 len -= space; 779 off = 0; 780 prevp = &mp->b_cont; 781 } 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; 789 } 790} 791 792/* 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. 796 * 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 :-( 800 */ 801#ifndef __osf__ 802 803/* 804 * Remove an interface from the system. 805 * This routine contains magic. 806 */ 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> 815 816static void 817ppp_if_detach(ifp) 818 struct ifnet *ifp; 819{ 820 int s; 821 struct inpcb *pcb; 822 struct ifaddr *ifa; 823 struct in_ifaddr **inap; 824 struct ifnet **ifpp; 825 826 s = splhigh(); 827 828 /* 829 * Clear the interface from any routes currently cached in 830 * TCP or UDP protocol control blocks. 831 */ 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); 838 839 /* 840 * Delete routes through all addresses of the interface. 841 */ 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); 845 } 846 847 /* 848 * Unlink the interface's address(es) from the in_ifaddr list. 849 */ 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; 855 } 856 857 /* 858 * Delete the interface from the ifnet list. 859 */ 860 for (ifpp = &ifnet; (*ifpp) != 0; ) { 861 if (*ifpp == ifp) 862 break; 863 ifpp = &(*ifpp)->if_next; 864 } 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; 869 870 splx(s); 871} 872 873#endif /* __osf__ */ 874