if_ppp.c revision 1.2
1/* 2 * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. 3 * 4 * Copyright (c) 1989 Carnegie Mellon University. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms are permitted 8 * provided that the above copyright notice and this paragraph are 9 * duplicated in all such forms and that any documentation, 10 * advertising materials, and other materials related to such 11 * distribution and use acknowledge that the software was developed 12 * by Carnegie Mellon University. The name of the 13 * University may not be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 18 * 19 * Drew D. Perkins 20 * Carnegie Mellon University 21 * 4910 Forbes Ave. 22 * Pittsburgh, PA 15213 23 * (412) 268-8576 24 * ddp@andrew.cmu.edu 25 * 26 * Based on: 27 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 28 * 29 * Copyright (c) 1987 Regents of the University of California. 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms are permitted 33 * provided that the above copyright notice and this paragraph are 34 * duplicated in all such forms and that any documentation, 35 * advertising materials, and other materials related to such 36 * distribution and use acknowledge that the software was developed 37 * by the University of California, Berkeley. The name of the 38 * University may not be used to endorse or promote products derived 39 * from this software without specific prior written permission. 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 41 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 42 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 43 * 44 * Serial Line interface 45 * 46 * Rick Adams 47 * Center for Seismic Studies 48 * 1300 N 17th Street, Suite 1450 49 * Arlington, Virginia 22209 50 * (703)276-7900 51 * rick@seismo.ARPA 52 * seismo!rick 53 * 54 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 55 * Converted to 4.3BSD Beta by Chris Torek. 56 * Other changes made at Berkeley, based in part on code by Kirk Smith. 57 * 58 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) 59 * Added VJ tcp header compression; more unified ioctls 60 * 61 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). 62 * Cleaned up a lot of the mbuf-related code to fix bugs that 63 * caused system crashes and packet corruption. Changed pppstart 64 * so that it doesn't just give up with a collision if the whole 65 * packet doesn't fit in the output ring buffer. 66 * 67 * Added priority queueing for interactive IP packets, following 68 * the model of if_sl.c, plus hooks for bpf. 69 * Paul Mackerras (paulus@cs.anu.edu.au). 70 */ 71 72/* $Id: if_ppp.c,v 1.2 1993/08/31 00:05:27 paulus Exp $ */ 73/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 74 75#include "ppp.h" 76#if NPPP > 0 77 78#define VJC 79 80#include "param.h" 81#include "proc.h" 82#include "mbuf.h" 83#include "buf.h" 84#include "dkstat.h" 85#include "socket.h" 86#include "ioctl.h" 87#include "file.h" 88#include "tty.h" 89#include "kernel.h" 90#include "conf.h" 91 92#include "if.h" 93#include "if_types.h" 94#include "netisr.h" 95#include "route.h" 96#if INET 97#include "../netinet/in.h" 98#include "../netinet/in_systm.h" 99#include "../netinet/in_var.h" 100#include "../netinet/ip.h" 101#endif 102 103#include "bpfilter.h" 104#if NBPFILTER > 0 105#include "time.h" 106#include "bpf.h" 107#endif 108 109/* 110 * Here we try to tell whether we are in a 386BSD kernel, or 111 * in a NetBSD/Net-2/4.3-Reno kernel. 112 */ 113#ifndef RB_LEN 114/* NetBSD, 4.3-Reno or similar */ 115#define CCOUNT(q) ((q)->c_cc) 116 117#else 118/* 386BSD, Jolitz-style ring buffers */ 119#define t_outq t_out 120#define t_rawq t_raw 121#define t_canq t_can 122#define CCOUNT(q) (RB_LEN(q)) 123#endif 124 125#ifdef VJC 126#include "slcompress.h" 127#define HDROFF MAX_HDR 128/* HDROFF should really be 128, but other parts of the system will 129 panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */ 130 131#else 132#define HDROFF (0) 133#endif 134 135#include "if_ppp.h" 136#include "machine/mtpr.h" 137 138struct ppp_softc ppp_softc[NPPP]; 139int ppp_async_out_debug = 0; 140int ppp_async_in_debug = 0; 141int ppp_debug = 0; 142int ppp_raw_in_debug = -1; 143char ppp_rawin[32]; 144int ppp_rawin_count; 145 146void pppattach __P((void)); 147int pppopen __P((dev_t dev, struct tty *tp)); 148void pppclose __P((struct tty *tp, int flag)); 149int pppread __P((struct tty *tp, struct uio *uio, int flag)); 150int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); 151int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag)); 152int pppoutput __P((struct ifnet *ifp, struct mbuf *m0, 153 struct sockaddr *dst)); 154void pppstart __P((struct tty *tp)); 155void pppinput __P((int c, struct tty *tp)); 156int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data)); 157 158static u_short pppfcs __P((u_short fcs, u_char *cp, int len)); 159static int pppinit __P((struct ppp_softc *sc)); 160static struct mbuf *ppp_btom __P((struct ppp_softc *sc)); 161static void pppdumpm __P((struct mbuf *m0, int pktlen)); 162static void pppdumpb __P((u_char *b, int l)); 163 164/* 165 * Some useful mbuf macros not in mbuf.h. 166 */ 167#define M_DATASTART(m) \ 168 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \ 169 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) 170 171#define M_DATASIZE(m) \ 172 ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \ 173 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) 174 175/* 176 * The following disgusting hack gets around the problem that IP TOS 177 * can't be set yet. We want to put "interactive" traffic on a high 178 * priority queue. To decide if traffic is interactive, we check that 179 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 180 */ 181static u_short interactive_ports[8] = { 182 0, 513, 0, 0, 183 0, 21, 0, 23, 184}; 185#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 186 187/* 188 * Does c need to be escaped? 189 */ 190#define ESCAPE_P(c) (((c) == PPP_FLAG) || ((c) == PPP_ESCAPE) || \ 191 (c) < 0x20 && (sc->sc_asyncmap & (1 << (c)))) 192 193/* 194 * Called from boot code to establish ppp interfaces. 195 */ 196void 197pppattach() 198{ 199 register struct ppp_softc *sc; 200 register int i = 0; 201 202 for (sc = ppp_softc; i < NPPP; sc++) { 203 sc->sc_if.if_name = "ppp"; 204 sc->sc_if.if_unit = i++; 205 sc->sc_if.if_mtu = PPP_MTU; 206 sc->sc_if.if_flags = IFF_POINTOPOINT; 207 sc->sc_if.if_type = IFT_PPP; 208 sc->sc_if.if_hdrlen = PPP_HEADER_LEN; 209 sc->sc_if.if_ioctl = pppioctl; 210 sc->sc_if.if_output = pppoutput; 211 sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; 212 sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; 213 sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; 214 if_attach(&sc->sc_if); 215#if NBPFILTER > 0 216 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HEADER_LEN); 217#endif 218 } 219} 220 221/* 222 * Line specific open routine. 223 * Attach the given tty to the first available ppp unit. 224 */ 225/* ARGSUSED */ 226int 227pppopen(dev, tp) 228 dev_t dev; 229 register struct tty *tp; 230{ 231 struct proc *p = curproc; /* XXX */ 232 register struct ppp_softc *sc; 233 register int nppp; 234 int error, s; 235 236 if (error = suser(p->p_ucred, &p->p_acflag)) 237 return (error); 238 239 if (tp->t_line == PPPDISC) 240 return (0); 241 242 for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) 243 if (sc->sc_ttyp == NULL) 244 break; 245 if (nppp >= NPPP) 246 return ENXIO; 247 248 sc->sc_flags = 0; 249 sc->sc_ilen = 0; 250 sc->sc_asyncmap = 0xffffffff; 251 sc->sc_rasyncmap = 0; 252 sc->sc_mru = PPP_MRU; 253#ifdef VJC 254 sl_compress_init(&sc->sc_comp); 255#endif 256 if (pppinit(sc) == 0) { 257 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 258 return (ENOBUFS); 259 } 260 tp->t_sc = (caddr_t)sc; 261 sc->sc_ttyp = tp; 262 sc->sc_outm = NULL; 263 ttyflush(tp, FREAD | FWRITE); 264 sc->sc_if.if_flags |= IFF_RUNNING; 265 266#ifdef PPP_OUTQ_SIZE 267 /* N.B. this code is designed *only* for use in NetBSD */ 268 s = spltty(); 269 /* get rid of the default outq clist buffer */ 270 clfree(&tp->t_outq); 271 /* and get a new one, without quoting support, much larger */ 272 clalloc(&tp->t_outq, PPP_OUTQ_SIZE, 0); 273 splx (s); 274#endif /* PPP_OUTQ_SIZE */ 275 276 return (0); 277} 278 279/* 280 * Line specific close routine. 281 * Detach the tty from the ppp unit. 282 * Mimics part of ttyclose(). 283 */ 284void 285pppclose(tp, flag) 286 struct tty *tp; 287 int flag; 288{ 289 register struct ppp_softc *sc; 290 struct mbuf *m; 291 int s; 292 293 ttywflush(tp); 294 s = splimp(); /* paranoid; splnet probably ok */ 295 tp->t_line = 0; 296 sc = (struct ppp_softc *)tp->t_sc; 297 if (sc != NULL) { 298 if_down(&sc->sc_if); 299 sc->sc_ttyp = NULL; 300 tp->t_sc = NULL; 301 m_freem(sc->sc_outm); 302 sc->sc_outm = NULL; 303 m_freem(sc->sc_m); 304 sc->sc_m = NULL; 305 for (;;) { 306 IF_DEQUEUE(&sc->sc_inq, m); 307 if (m == NULL) 308 break; 309 m_freem(m); 310 } 311 for (;;) { 312 IF_DEQUEUE(&sc->sc_fastq, m); 313 if (m == NULL) 314 break; 315 m_freem(m); 316 } 317 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 318 319#ifdef PPP_OUTQ_SIZE 320 /* reinstall default clist-buffer for outq 321 XXXX should really remember old value and restore that!! */ 322 clfree(&tp->t_outq); 323 clalloc(&tp->t_outq, 1024, 0); 324#endif /* PPP_OUTQ_SIZE */ 325 326 } 327 splx(s); 328} 329 330/* 331 * Line specific (tty) read routine. 332 */ 333int 334pppread(tp, uio, flag) 335 register struct tty *tp; 336 struct uio *uio; 337 int flag; 338{ 339 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 340 struct mbuf *m, *m0; 341 register int s; 342 int error; 343 344 if ((tp->t_state & TS_CARR_ON)==0) 345 return (EIO); 346 s = splimp(); 347 while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) { 348 if (tp->t_state & TS_ASYNC) { 349 splx(s); 350 return (EWOULDBLOCK); 351 } 352 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0); 353 if (error) 354 return error; 355 } 356 if (tp->t_line != PPPDISC) { 357 splx(s); 358 return (-1); 359 } 360 361 /* Pull place-holder byte out of canonical queue */ 362 getc(&tp->t_canq); 363 364 /* Get the packet from the input queue */ 365 IF_DEQUEUE(&sc->sc_inq, m0); 366 splx(s); 367 368 for (m = m0; m && uio->uio_resid; m = m->m_next) 369 if (error = uiomove(mtod(m, u_char *), m->m_len, uio)) 370 break; 371 m_freem(m0); 372 return (error); 373} 374 375/* 376 * Line specific (tty) write routine. 377 */ 378int 379pppwrite(tp, uio, flag) 380 register struct tty *tp; 381 struct uio *uio; 382 int flag; 383{ 384 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 385 struct mbuf *m, *m0, **mp; 386 struct sockaddr dst; 387 struct ppp_header *ph1, *ph2; 388 int len, error; 389 390 if ((tp->t_state & TS_CARR_ON)==0) 391 return (EIO); 392 if (tp->t_line != PPPDISC) 393 return (EINVAL); 394 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HEADER_LEN || 395 uio->uio_resid < PPP_HEADER_LEN) 396 return (EMSGSIZE); 397 for (mp = &m0; uio->uio_resid; mp = &m->m_next) { 398 MGET(m, M_WAIT, MT_DATA); 399 if ((*mp = m) == NULL) { 400 m_freem(m0); 401 return (ENOBUFS); 402 } 403 if (uio->uio_resid >= MCLBYTES / 2) 404 MCLGET(m, M_DONTWAIT); 405 len = MIN(M_TRAILINGSPACE(m), uio->uio_resid); 406 if (error = uiomove(mtod(m, u_char *), len, uio)) { 407 m_freem(m0); 408 return (error); 409 } 410 m->m_len = len; 411 } 412 dst.sa_family = AF_UNSPEC; 413 ph1 = (struct ppp_header *) &dst.sa_data; 414 ph2 = mtod(m0, struct ppp_header *); 415 *ph1 = *ph2; 416 m0->m_data += PPP_HEADER_LEN; 417 m0->m_len -= PPP_HEADER_LEN; 418 return (pppoutput(&sc->sc_if, m0, &dst)); 419} 420 421/* 422 * Line specific (tty) ioctl routine. 423 * Provide a way to get the ppp unit number. 424 * This discipline requires that tty device drivers call 425 * the line specific l_ioctl routine from their ioctl routines. 426 */ 427/* ARGSUSED */ 428int 429ppptioctl(tp, cmd, data, flag) 430 struct tty *tp; 431 caddr_t data; 432 int cmd, flag; 433{ 434 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 435 struct proc *p = curproc; /* XXX */ 436 int s, error, flags, mru; 437 438 switch (cmd) { 439#if 0 /* this is handled (properly) by ttioctl */ 440 case TIOCGETD: 441 *(int *)data = sc->sc_if.if_unit; 442 break; 443#endif 444 case FIONREAD: 445 *(int *)data = sc->sc_inq.ifq_len; 446 break; 447 448 case PPPIOCGUNIT: 449 *(int *)data = sc->sc_if.if_unit; 450 break; 451 452 case PPPIOCGFLAGS: 453 *(u_int *)data = sc->sc_flags; 454 break; 455 456 case PPPIOCSFLAGS: 457 if (error = suser(p->p_ucred, &p->p_acflag)) 458 return (error); 459 flags = *(int *)data & SC_MASK; 460 s = splimp(); 461 sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; 462 splx(s); 463 break; 464 465 case PPPIOCSASYNCMAP: 466 if (error = suser(p->p_ucred, &p->p_acflag)) 467 return (error); 468 sc->sc_asyncmap = *(u_int *)data; 469 break; 470 471 case PPPIOCGASYNCMAP: 472 *(u_int *)data = sc->sc_asyncmap; 473 break; 474 475 case PPPIOCSRASYNCMAP: 476 if (error = suser(p->p_ucred, &p->p_acflag)) 477 return (error); 478 sc->sc_rasyncmap = *(u_int *)data; 479 break; 480 481 case PPPIOCGRASYNCMAP: 482 *(u_int *)data = sc->sc_rasyncmap; 483 break; 484 485 case PPPIOCSMRU: 486 if (error = suser(p->p_ucred, &p->p_acflag)) 487 return (error); 488 mru = *(int *)data; 489 if (mru >= PPP_MRU && mru <= PPP_MAXMRU) { 490 sc->sc_mru = mru; 491 if (pppinit(sc) == 0) { 492 error = ENOBUFS; 493 sc->sc_mru = PPP_MRU; 494 if (pppinit(sc) == 0) 495 sc->sc_if.if_flags &= ~IFF_UP; 496 } 497 } 498 break; 499 500 case PPPIOCGMRU: 501 *(int *)data = sc->sc_mru; 502 break; 503 504 default: 505 return (-1); 506 } 507 return (0); 508} 509 510/* 511 * FCS lookup table as calculated by genfcstab. 512 */ 513static u_short fcstab[256] = { 514 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 515 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 516 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 517 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 518 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 519 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 520 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 521 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 522 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 523 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 524 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 525 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 526 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 527 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 528 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 529 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 530 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 531 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 532 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 533 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 534 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 535 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 536 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 537 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 538 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 539 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 540 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 541 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 542 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 543 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 544 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 545 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 546}; 547 548/* 549 * Calculate a new FCS given the current FCS and the new data. 550 */ 551static u_short 552pppfcs(fcs, cp, len) 553 register u_short fcs; 554 register u_char *cp; 555 register int len; 556{ 557 while (len--) 558 fcs = PPP_FCS(fcs, *cp++); 559 return (fcs); 560} 561 562/* 563 * Queue a packet. Start transmission if not active. 564 * Packet is placed in Information field of PPP frame. 565 */ 566int 567pppoutput(ifp, m0, dst) 568 struct ifnet *ifp; 569 struct mbuf *m0; 570 struct sockaddr *dst; 571{ 572 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; 573 struct ppp_header *ph; 574 int protocol, address, control; 575 u_char *cp; 576 int s, error; 577 struct ip *ip; 578 struct ifqueue *ifq; 579 580 if (sc->sc_ttyp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 581 || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) { 582 error = ENETDOWN; /* sort of */ 583 goto bad; 584 } 585 if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 586 error = EHOSTUNREACH; 587 goto bad; 588 } 589 590 /* 591 * Compute PPP header. 592 */ 593 address = PPP_ALLSTATIONS; 594 control = PPP_UI; 595 ifq = &ifp->if_snd; 596 switch (dst->sa_family) { 597#ifdef INET 598 case AF_INET: 599 protocol = PPP_IP; 600 /* 601 * If this is a TCP packet to or from an "interactive" port, 602 * put the packet on the fastq instead. 603 */ 604 if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) { 605 register int p = ((int *)ip)[ip->ip_hl]; 606 if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) 607 ifq = &sc->sc_fastq; 608 } 609 break; 610#endif 611#ifdef NS 612 case AF_NS: 613 protocol = PPP_XNS; 614 break; 615#endif 616 case AF_UNSPEC: 617 ph = (struct ppp_header *) dst->sa_data; 618 address = ph->ph_address; 619 control = ph->ph_control; 620 protocol = ntohs(ph->ph_protocol); 621 break; 622 default: 623 printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family); 624 error = EAFNOSUPPORT; 625 goto bad; 626 } 627 628 /* 629 * Add PPP header. If no space in first mbuf, allocate another. 630 * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) 631 */ 632 if (M_LEADINGSPACE(m0) < PPP_HEADER_LEN) { 633 m0 = m_prepend(m0, PPP_HEADER_LEN, M_DONTWAIT); 634 if (m0 == 0) { 635 error = ENOBUFS; 636 goto bad; 637 } 638 m0->m_len = 0; 639 } else 640 m0->m_data -= PPP_HEADER_LEN; 641 642 cp = mtod(m0, u_char *); 643 *cp++ = address; 644 *cp++ = control; 645 *cp++ = protocol >> 8; 646 *cp++ = protocol & 0xff; 647 m0->m_len += PPP_HEADER_LEN; 648 649 if (ppp_async_out_debug) { 650 printf("ppp%d output: ", ifp->if_unit); 651 pppdumpm(m0, -1); 652 } 653 654#if NBPFILTER > 0 655 /* See if bpf wants to look at the packet. */ 656 if (sc->sc_bpf) 657 bpf_mtap(sc->sc_bpf, m0); 658#endif 659 660 /* 661 * Put the packet on the appropriate queue. 662 */ 663 s = splimp(); 664 if (IF_QFULL(ifq)) { 665 IF_DROP(ifq); 666 splx(s); 667 sc->sc_if.if_oerrors++; 668 error = ENOBUFS; 669 goto bad; 670 } 671 IF_ENQUEUE(ifq, m0); 672 if (CCOUNT(&sc->sc_ttyp->t_outq) == 0) 673 pppstart(sc->sc_ttyp); 674 splx(s); 675 return (0); 676 677bad: 678 m_freem(m0); 679 return (error); 680} 681 682/* 683 * Start output on interface. Get another datagram 684 * to send from the interface queue and map it to 685 * the interface before starting output. 686 */ 687void 688pppstart(tp) 689 register struct tty *tp; 690{ 691 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 692 register struct mbuf *m; 693 register int len; 694 register u_char *start, *stop, *cp; 695 int n, s, ndone, done; 696 struct mbuf *m2; 697 int address, control, protocol; 698 int compac, compprot, nb; 699 700 for (;;) { 701 /* 702 * If there is more in the output queue, just send it now. 703 * We are being called in lieu of ttstart and must do what 704 * it would. 705 */ 706 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) { 707 (*tp->t_oproc)(tp); 708 if (CCOUNT(&tp->t_outq) > PPP_HIWAT) 709 return; 710 } 711 /* 712 * This happens briefly when the line shuts down. 713 */ 714 if (sc == NULL) 715 return; 716 717 /* 718 * See if we have an existing packet partly sent. 719 * If not, get a new packet and start sending it. 720 * We take packets on the priority queue ahead of those 721 * on the normal queue. 722 */ 723 m = sc->sc_outm; 724 if (m == NULL) { 725 s = splimp(); 726 IF_DEQUEUE(&sc->sc_fastq, m); 727 if (m == NULL) 728 IF_DEQUEUE(&sc->sc_if.if_snd, m); 729 splx(s); 730 if (m == NULL) 731 return; 732 733 /* 734 * Extract the ppp header of the new packet. 735 * The ppp header will be in one mbuf. 736 */ 737 cp = mtod(m, u_char *); 738 address = *cp++; 739 control = *cp++; 740 protocol = *cp++; 741 protocol = (protocol << 8) + *cp++; 742 m->m_data += PPP_HEADER_LEN; 743 m->m_len -= PPP_HEADER_LEN; 744 745#ifdef VJC 746 /* 747 * If the packet is a TCP/IP packet, see if we can compress it. 748 */ 749 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) { 750 struct ip *ip; 751 int type; 752 struct mbuf *mp; 753 754 mp = m; 755 if (mp->m_len <= 0) { 756 mp = mp->m_next; 757 cp = mtod(mp, u_char *); 758 } 759 ip = (struct ip *) cp; 760 if (ip->ip_p == IPPROTO_TCP) { 761 type = sl_compress_tcp(mp, ip, &sc->sc_comp, 762 !(sc->sc_flags & SC_NO_TCP_CCID)); 763 switch (type) { 764 case TYPE_UNCOMPRESSED_TCP: 765 protocol = PPP_VJC_UNCOMP; 766 break; 767 case TYPE_COMPRESSED_TCP: 768 protocol = PPP_VJC_COMP; 769 break; 770 } 771 } 772 } 773#endif 774 775 /* 776 * Compress the address/control and protocol, if possible. 777 */ 778 compac = sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && 779 control == PPP_UI && protocol != PPP_ALLSTATIONS && 780 protocol != PPP_LCP; 781 compprot = sc->sc_flags & SC_COMP_PROT && protocol < 0x100; 782 nb = (compac ? 0 : 2) + (compprot ? 1 : 2); 783 m->m_data -= nb; 784 m->m_len += nb; 785 786 cp = mtod(m, u_char *); 787 if (!compac) { 788 *cp++ = address; 789 *cp++ = control; 790 } 791 if (!compprot) 792 *cp++ = protocol >> 8; 793 *cp++ = protocol; 794 795 /* 796 * The extra PPP_FLAG will start up a new packet, and thus 797 * will flush any accumulated garbage. We do this whenever 798 * the line may have been idle for some time. 799 */ 800 if (CCOUNT(&tp->t_outq) == 0) { 801 ++sc->sc_bytessent; 802 (void) putc(PPP_FLAG, &tp->t_outq); 803 } 804 805 /* Calculate the FCS for the first mbuf's worth. */ 806 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); 807 } 808 809 for (;;) { 810 start = mtod(m, u_char *); 811 len = m->m_len; 812 stop = start + len; 813 while (len > 0) { 814 /* 815 * Find out how many bytes in the string we can 816 * handle without doing something special. 817 */ 818 for (cp = start; cp < stop; cp++) 819 if (ESCAPE_P(*cp)) 820 break; 821 n = cp - start; 822 if (n) { 823#ifndef RB_LEN 824 /* NetBSD (0.9 or later), 4.3-Reno or similar. */ 825 ndone = n - b_to_q(start, n, &tp->t_outq); 826#else 827#ifdef NetBSD 828 /* NetBSD, 0.8 or earlier */ 829 ndone = rb_cwrite(&tp->t_out, start, n); 830#else 831 /* 386BSD */ 832 int cc, nleft; 833 for (nleft = n; nleft > 0; nleft -= cc) { 834 if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0) 835 break; 836 cc = min (cc, nleft); 837 bcopy((char *)start, tp->t_out.rb_tl, cc); 838 tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out, 839 tp->t_out.rb_tl + cc); 840 } 841 ndone = n - nleft; 842#endif /* NetBSD */ 843#endif /* RB_LEN */ 844 len -= ndone; 845 start += ndone; 846 sc->sc_bytessent += ndone; 847 848 if (ndone < n) 849 break; /* packet doesn't fit */ 850 } 851 /* 852 * If there are characters left in the mbuf, 853 * the first one must be special.. 854 * Put it out in a different form. 855 */ 856 if (len) { 857 if (putc(PPP_ESCAPE, &tp->t_outq)) 858 break; 859 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { 860 (void) unputc(&tp->t_outq); 861 break; 862 } 863 sc->sc_bytessent += 2; 864 start++; 865 len--; 866 } 867 } 868 /* 869 * If we didn't empty this mbuf, remember where we're up to. 870 * If we emptied the last mbuf, try to add the FCS and closing 871 * flag, and if we can't, leave sc_outm pointing to m, but with 872 * m->m_len == 0, to remind us to output the FCS and flag later. 873 */ 874 done = len == 0; 875 if (done && m->m_next == NULL) { 876 u_char *p, *q; 877 int c; 878 u_char endseq[8]; 879 880 /* 881 * We may have to escape the bytes in the FCS. 882 */ 883 p = endseq; 884 c = ~sc->sc_outfcs & 0xFF; 885 if (ESCAPE_P(c)) { 886 *p++ = PPP_ESCAPE; 887 *p++ = c ^ PPP_TRANS; 888 } else 889 *p++ = c; 890 c = (~sc->sc_outfcs >> 8) & 0xFF; 891 if (ESCAPE_P(c)) { 892 *p++ = PPP_ESCAPE; 893 *p++ = c ^ PPP_TRANS; 894 } else 895 *p++ = c; 896 *p++ = PPP_FLAG; 897 898 /* 899 * Try to output the FCS and flag. If the bytes 900 * don't all fit, back out. 901 */ 902 for (q = endseq; q < p; ++q) 903 if (putc(*q, &tp->t_outq)) { 904 done = 0; 905 for (; q > endseq; --q) 906 unputc(&tp->t_outq); 907 break; 908 } 909 } 910 911 if (!done) { 912 m->m_data = start; 913 m->m_len = len; 914 sc->sc_outm = m; 915 if (tp->t_oproc != NULL) 916 (*tp->t_oproc)(tp); 917 return; /* can't do any more at the moment */ 918 } 919 920 /* Finished with this mbuf; free it and move on. */ 921 MFREE(m, m2); 922 if (m2 == NULL) 923 break; 924 925 m = m2; 926 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); 927 } 928 929 /* Finished a packet */ 930 sc->sc_outm = NULL; 931 sc->sc_bytessent++; /* account for closing flag */ 932 sc->sc_if.if_opackets++; 933 sc->sc_if.if_obytes = sc->sc_bytessent; 934 } 935} 936 937/* 938 * Allocate enough mbuf to handle current MRU. 939 */ 940static int 941pppinit(sc) 942 register struct ppp_softc *sc; 943{ 944 struct mbuf *m, **mp; 945 int len = HDROFF + sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN; 946 int s; 947 948 s = splimp(); 949 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next) 950 if ((len -= M_DATASIZE(m)) <= 0) { 951 splx(s); 952 return (1); 953 } 954 955 for (;; mp = &m->m_next) { 956 MGETHDR(m, M_DONTWAIT, MT_DATA); 957 if (m == 0) { 958 m_freem(sc->sc_m); 959 sc->sc_m = NULL; 960 splx(s); 961 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit); 962 return (0); 963 } 964 *mp = m; 965 MCLGET(m, M_DONTWAIT); 966 if ((len -= M_DATASIZE(m)) <= 0) { 967 splx(s); 968 return (1); 969 } 970 } 971} 972 973/* 974 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy 975 * of the data, not just copies of pointers to the data. 976 */ 977static struct mbuf * 978ppp_btom(sc) 979 struct ppp_softc *sc; 980{ 981 register struct mbuf *m, **mp; 982 struct mbuf *top = sc->sc_m; 983 984 /* 985 * First check current mbuf. If we have more than a small mbuf, 986 * return the whole cluster and set beginning of buffer to the 987 * next mbuf. 988 * Else, copy the current bytes into a small mbuf, attach the new 989 * mbuf to the end of the chain and set beginning of buffer to the 990 * current mbuf. 991 */ 992 993 if (sc->sc_mc->m_len > MHLEN) { 994 sc->sc_m = sc->sc_mc->m_next; 995 sc->sc_mc->m_next = NULL; 996 } 997 else { 998 /* rather than waste a whole cluster on <= MHLEN bytes, 999 alloc a small mbuf and copy to it */ 1000 MGETHDR(m, M_DONTWAIT, MT_DATA); 1001 if (m == NULL) 1002 return (NULL); 1003 1004 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len); 1005 m->m_len = sc->sc_mc->m_len; 1006 for (mp = ⊤ *mp != sc->sc_mc; mp = &(*mp)->m_next) 1007 ; 1008 *mp = m; 1009 sc->sc_m = sc->sc_mc; 1010 } 1011 1012 /* 1013 * Try to allocate enough extra mbufs to handle the next packet. 1014 */ 1015 if (pppinit(sc) == 0) { 1016 m_freem(top); 1017 if (pppinit(sc) == 0) 1018 sc->sc_if.if_flags &= ~IFF_UP; 1019 return (NULL); 1020 } 1021 1022 return (top); 1023} 1024 1025/* 1026 * tty interface receiver interrupt. 1027 */ 1028#define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ 1029 TYPE_UNCOMPRESSED_TCP) 1030 1031void 1032pppinput(c, tp) 1033 int c; 1034 register struct tty *tp; 1035{ 1036 register struct ppp_softc *sc; 1037 struct mbuf *m; 1038 struct ifqueue *inq; 1039 int s, ilen, xlen, proto; 1040 char *pkttype; 1041 1042 tk_nin++; 1043 sc = (struct ppp_softc *)tp->t_sc; 1044 if (sc == NULL) 1045 return; 1046 1047 ++sc->sc_if.if_ibytes; 1048 1049 if (c & TTY_FE) { 1050 /* framing error or overrun on this char - abort packet */ 1051 if (ppp_debug) 1052 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c); 1053 goto flush; 1054 } 1055 1056 c &= 0xff; 1057 1058 if (sc->sc_if.if_unit == ppp_raw_in_debug) { 1059 ppp_rawin[ppp_rawin_count++] = c; 1060 if (ppp_rawin_count >= sizeof(ppp_rawin)) { 1061 printf("raw ppp%d: ", ppp_raw_in_debug); 1062 pppdumpb(ppp_rawin, ppp_rawin_count); 1063 ppp_rawin_count = 0; 1064 } 1065 } 1066 1067 if (c == PPP_FLAG) { 1068 ilen = sc->sc_ilen; 1069 sc->sc_ilen = 0; 1070 1071 if (sc->sc_flags & SC_FLUSH 1072 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) { 1073#ifdef VJC 1074 /* 1075 * If we've missed a packet, we must toss subsequent compressed 1076 * packets which don't have an explicit connection ID. 1077 */ 1078 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp); 1079#endif 1080 if ((sc->sc_flags & SC_FLUSH) == 0){ 1081 if (ppp_debug) 1082 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit); 1083 sc->sc_if.if_ierrors++; 1084 } else 1085 sc->sc_flags &= ~SC_FLUSH; 1086 return; 1087 } 1088 1089 if (ilen < PPP_HEADER_LEN + PPP_FCS_LEN) { 1090 if (ilen) { 1091 if (ppp_debug) 1092 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); 1093 sc->sc_if.if_ierrors++; 1094 } 1095 return; 1096 } 1097 1098 /* 1099 * Remove FCS trailer. Somewhat painful... 1100 */ 1101 ilen -= 2; 1102 if (--sc->sc_mc->m_len == 0) { 1103 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 1104 ; 1105 sc->sc_mc = m; 1106 } 1107 sc->sc_mc->m_len--; 1108 1109 sc->sc_if.if_ipackets++; 1110 m = sc->sc_m; 1111 1112 if (ppp_async_in_debug) { 1113 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen); 1114 pppdumpm(m, ilen); 1115 } 1116 1117 proto = ntohs(mtod(m, struct ppp_header *)->ph_protocol); 1118 switch (proto) { 1119#ifdef INET 1120 case PPP_IP: 1121 ilen -= PPP_HEADER_LEN; 1122 m->m_data += PPP_HEADER_LEN; 1123 m->m_len -= PPP_HEADER_LEN; 1124 break; 1125 1126#ifdef VJC 1127 case PPP_VJC_COMP: 1128 case PPP_VJC_UNCOMP: 1129 pkttype = proto == PPP_VJC_COMP? "": "un"; 1130 if (!(sc->sc_flags & SC_REJ_COMP_TCP)) { 1131 1132 m->m_data += PPP_HEADER_LEN; 1133 m->m_len -= PPP_HEADER_LEN; 1134 ilen -= PPP_HEADER_LEN; 1135 1136 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data), 1137 m->m_len, ilen, 1138 COMPTYPE(proto), &sc->sc_comp); 1139 1140 if (xlen) { 1141 /* adjust the first mbuf by the decompressed amt */ 1142 m->m_len += xlen - ilen; 1143 ilen = xlen; 1144 proto = PPP_IP; 1145 break; 1146 } 1147 1148 if (ppp_debug) 1149 printf("ppp%d: sl_uncompress failed on type %scomp\n", 1150 sc->sc_if.if_unit, pkttype); 1151 1152 } else { 1153 if (ppp_debug) 1154 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n", 1155 sc->sc_if.if_unit, pkttype, sc->sc_flags); 1156 } 1157 if (ppp_debug) 1158 printf("ppp%d: packet rejected, protocol 0x%x\n", 1159 sc->sc_if.if_unit, proto); 1160 sc->sc_if.if_ierrors++; 1161 return; 1162#endif 1163#endif 1164 } 1165 1166 /* get this packet as an mbuf chain */ 1167 if ((m = ppp_btom(sc)) == NULL) { 1168 sc->sc_if.if_ierrors++; 1169 return; 1170 } 1171 m->m_pkthdr.len = ilen; 1172 m->m_pkthdr.rcvif = &sc->sc_if; 1173 1174 if (proto == PPP_IP) { 1175 /* IP packet - pass it up to IP */ 1176 if ((sc->sc_if.if_flags & IFF_UP) == 0) { 1177 /* interface is down - drop the packet. */ 1178 m_freem(m); 1179 sc->sc_if.if_ierrors++; 1180 return; 1181 } 1182 schednetisr(NETISR_IP); 1183 inq = &ipintrq; 1184 1185 } else { 1186 /* some other protocol - place on input queue for read() */ 1187 /* Put a placeholder byte in canq for ttselect()/ttnread() */ 1188 putc(0, &tp->t_canq); 1189 ttwakeup(tp); 1190 inq = &sc->sc_inq; 1191 } 1192 1193#if NBPFILTER > 0 1194 /* See if bpf wants to look at the packet. */ 1195 if (sc->sc_bpf) 1196 bpf_mtap(sc->sc_bpf, m); 1197#endif 1198 1199 /* Put the packet on the appropriate input queue. */ 1200 s = splimp(); 1201 if (IF_QFULL(inq)) { 1202 IF_DROP(inq); 1203 if (ppp_debug) 1204 printf("ppp%d: queue full\n", sc->sc_if.if_unit); 1205 sc->sc_if.if_ierrors++; 1206 sc->sc_if.if_iqdrops++; 1207 m_freem(m); 1208 } else 1209 IF_ENQUEUE(inq, m); 1210 1211 splx(s); 1212 return; 1213 } 1214 1215 if (sc->sc_flags & SC_FLUSH) 1216 return; 1217 if (c == PPP_ESCAPE) { 1218 sc->sc_flags |= SC_ESCAPED; 1219 return; 1220 } 1221 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 1222 return; 1223 1224 if (sc->sc_flags & SC_ESCAPED) { 1225 sc->sc_flags &= ~SC_ESCAPED; 1226 c ^= PPP_TRANS; 1227 } 1228 1229 /* 1230 * Initialize buffer on first octet received. 1231 * First octet could be address or protocol (when compressing 1232 * address/control). 1233 * Second octet is control. 1234 * Third octet is first or second (when compressing protocol) 1235 * octet of protocol. 1236 * Fourth octet is second octet of protocol. 1237 */ 1238 if (sc->sc_ilen == 0) { 1239 /* reset the first input mbuf */ 1240 m = sc->sc_m; 1241 m->m_len = 0; 1242 m->m_data = M_DATASTART(sc->sc_m) + HDROFF; 1243 sc->sc_mc = m; 1244 sc->sc_mp = mtod(m, char *); 1245 sc->sc_fcs = PPP_INITFCS; 1246 if (c != PPP_ALLSTATIONS) { 1247 if (sc->sc_flags & SC_REJ_COMP_AC) { 1248 if (ppp_debug) 1249 printf("ppp%d: missing ALLSTATIONS, got 0x%x; flags %x\n", 1250 sc->sc_if.if_unit, c, sc->sc_flags); 1251 goto flush; 1252 } 1253 *sc->sc_mp++ = PPP_ALLSTATIONS; 1254 *sc->sc_mp++ = PPP_UI; 1255 sc->sc_ilen += 2; 1256 m->m_len += 2; 1257 } 1258 } 1259 if (sc->sc_ilen == 1 && c != PPP_UI) { 1260 if (ppp_debug) 1261 printf("ppp%d: missing UI, got 0x%x\n", sc->sc_if.if_unit, c); 1262 goto flush; 1263 } 1264 if (sc->sc_ilen == 2 && (c & 1) == 1) { 1265 /* RFC1331 says we have to accept a compressed protocol */ 1266 *sc->sc_mp++ = 0; 1267 sc->sc_ilen++; 1268 sc->sc_mc->m_len++; 1269 } 1270 if (sc->sc_ilen == 3 && (c & 1) == 0) { 1271 if (ppp_debug) 1272 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, 1273 (sc->sc_mp[-1] << 8) + c); 1274 goto flush; 1275 } 1276 1277 /* packet beyond configured mru? */ 1278 if (++sc->sc_ilen > sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN) { 1279 if (ppp_debug) 1280 printf("ppp%d: packet too big\n", sc->sc_if.if_unit); 1281 goto flush; 1282 } 1283 1284 /* is this mbuf full? */ 1285 m = sc->sc_mc; 1286 if (M_TRAILINGSPACE(m) <= 0) { 1287 sc->sc_mc = m = m->m_next; 1288 if (m == NULL) { 1289 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); 1290 goto flush; 1291 } 1292 m->m_len = 0; 1293 m->m_data = M_DATASTART(m); 1294 sc->sc_mp = mtod(m, char *); 1295 } 1296 1297 ++m->m_len; 1298 *sc->sc_mp++ = c; 1299 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1300 return; 1301 1302 flush: 1303 sc->sc_if.if_ierrors++; 1304 sc->sc_flags |= SC_FLUSH; 1305} 1306 1307/* 1308 * Process an ioctl request to interface. 1309 */ 1310pppioctl(ifp, cmd, data) 1311 register struct ifnet *ifp; 1312 int cmd; 1313 caddr_t data; 1314{ 1315 struct proc *p = curproc; /* XXX */ 1316 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; 1317 register struct ifaddr *ifa = (struct ifaddr *)data; 1318 register struct ifreq *ifr = (struct ifreq *)data; 1319 int s = splimp(), error = 0; 1320 1321 1322 switch (cmd) { 1323 case SIOCSIFFLAGS: 1324 if ((ifp->if_flags & IFF_RUNNING) == 0) 1325 ifp->if_flags &= ~IFF_UP; 1326 break; 1327 1328 case SIOCSIFADDR: 1329 if (ifa->ifa_addr->sa_family != AF_INET) 1330 error = EAFNOSUPPORT; 1331 break; 1332 1333 case SIOCSIFDSTADDR: 1334 if (ifa->ifa_addr->sa_family != AF_INET) 1335 error = EAFNOSUPPORT; 1336 break; 1337 1338 case SIOCSIFMTU: 1339 if (error = suser(p->p_ucred, &p->p_acflag)) 1340 return (error); 1341 sc->sc_if.if_mtu = ifr->ifr_mtu; 1342 break; 1343 1344 case SIOCGIFMTU: 1345 ifr->ifr_mtu = sc->sc_if.if_mtu; 1346 break; 1347 1348 default: 1349 error = EINVAL; 1350 } 1351 splx(s); 1352 return (error); 1353} 1354 1355#define MAX_DUMP_BYTES 128 1356 1357static void 1358pppdumpm(m0, pktlen) 1359 struct mbuf *m0; 1360 int pktlen; 1361{ 1362 char buf[2*MAX_DUMP_BYTES+4]; 1363 char *bp = buf; 1364 struct mbuf *m; 1365 static char digits[] = "0123456789abcdef"; 1366 1367 for (m = m0; m && pktlen; m = m->m_next) { 1368 int l = m->m_len; 1369 u_char *rptr = (u_char *)m->m_data; 1370 1371 if (pktlen > 0) { 1372 l = min(l, pktlen); 1373 pktlen -= l; 1374 } 1375 while (l--) { 1376 if (bp > buf + sizeof(buf) - 4) 1377 goto done; 1378 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ 1379 *bp++ = digits[*rptr++ & 0xf]; 1380 } 1381 1382 if (m->m_next) { 1383 if (bp > buf + sizeof(buf) - 3) 1384 goto done; 1385 *bp++ = '|'; 1386 } 1387 } 1388done: 1389 if (m && pktlen) 1390 *bp++ = '>'; 1391 *bp = 0; 1392 printf("%s\n", buf); 1393} 1394 1395static void 1396pppdumpb(b, l) 1397 u_char *b; 1398 int l; 1399{ 1400 char buf[2*MAX_DUMP_BYTES+4]; 1401 char *bp = buf; 1402 static char digits[] = "0123456789abcdef"; 1403 1404 while (l--) { 1405 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1406 *bp++ = digits[*b++ & 0xf]; 1407 if (bp >= buf + sizeof(buf) - 2) { 1408 *bp++ = '>'; 1409 break; 1410 } 1411 } 1412 1413 *bp = 0; 1414 printf("%s\n", buf); 1415} 1416 1417 1418#endif /* NPPP > 0 */ 1419