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.4 1993/11/04 03:45:23 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 138 struct ppp_softc ppp_softc[NPPP]; 139 int ppp_async_out_debug = 0; 140 int ppp_async_in_debug = 0; 141 int ppp_debug = 0; 142 int ppp_raw_in_debug = -1; 143 char ppp_rawin[32]; 144 int ppp_rawin_count; 145 146 void pppattach __P((void)); 147 int pppopen __P((dev_t dev, struct tty *tp)); 148 void pppclose __P((struct tty *tp, int flag)); 149 int pppread __P((struct tty *tp, struct uio *uio, int flag)); 150 int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); 151 int ppptioctl __P((struct tty *tp, int cmd, caddr_t data, int flag)); 152 int pppoutput __P((struct ifnet *ifp, struct mbuf *m0, 153 struct sockaddr *dst)); 154 void pppstart __P((struct tty *tp)); 155 void pppinput __P((int c, struct tty *tp)); 156 int pppioctl __P((struct ifnet *ifp, int cmd, caddr_t data)); 157 158 static u_short pppfcs __P((u_short fcs, u_char *cp, int len)); 159 static int pppinit __P((struct ppp_softc *sc)); 160 static struct mbuf *ppp_btom __P((struct ppp_softc *sc)); 161 static void pppdumpm __P((struct mbuf *m0, int pktlen)); 162 static 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 */ 181 static 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 */ 196 void 197 pppattach() 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 */ 226 int 227 pppopen(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 */ 284 void 285 pppclose(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 */ 333 int 334 pppread(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 */ 378 int 379 pppwrite(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 */ 428 int 429 ppptioctl(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 */ 513 static 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 */ 551 static u_short 552 pppfcs(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 */ 566 int 567 pppoutput(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 /* 673 * The next statement used to be subject to: 674 * if (CCOUNT(&sc->sc_ttyp->t_outq) == 0) 675 * which was removed so that we don't hang up completely 676 * if the serial transmitter loses an interrupt. 677 */ 678 pppstart(sc->sc_ttyp); 679 splx(s); 680 return (0); 681 682 bad: 683 m_freem(m0); 684 return (error); 685 } 686 687 /* 688 * Start output on interface. Get another datagram 689 * to send from the interface queue and map it to 690 * the interface before starting output. 691 */ 692 void 693 pppstart(tp) 694 register struct tty *tp; 695 { 696 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 697 register struct mbuf *m; 698 register int len; 699 register u_char *start, *stop, *cp; 700 int n, s, ndone, done; 701 struct mbuf *m2; 702 int address, control, protocol; 703 int compac, compprot, nb; 704 705 for (;;) { 706 /* 707 * If there is more in the output queue, just send it now. 708 * We are being called in lieu of ttstart and must do what 709 * it would. 710 */ 711 if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) { 712 (*tp->t_oproc)(tp); 713 if (CCOUNT(&tp->t_outq) > PPP_HIWAT) 714 return; 715 } 716 /* 717 * This happens briefly when the line shuts down. 718 */ 719 if (sc == NULL) 720 return; 721 722 /* 723 * See if we have an existing packet partly sent. 724 * If not, get a new packet and start sending it. 725 * We take packets on the priority queue ahead of those 726 * on the normal queue. 727 */ 728 m = sc->sc_outm; 729 if (m == NULL) { 730 s = splimp(); 731 IF_DEQUEUE(&sc->sc_fastq, m); 732 if (m == NULL) 733 IF_DEQUEUE(&sc->sc_if.if_snd, m); 734 splx(s); 735 if (m == NULL) 736 return; 737 738 /* 739 * Extract the ppp header of the new packet. 740 * The ppp header will be in one mbuf. 741 */ 742 cp = mtod(m, u_char *); 743 address = *cp++; 744 control = *cp++; 745 protocol = *cp++; 746 protocol = (protocol << 8) + *cp++; 747 m->m_data += PPP_HEADER_LEN; 748 m->m_len -= PPP_HEADER_LEN; 749 750 #ifdef VJC 751 /* 752 * If the packet is a TCP/IP packet, see if we can compress it. 753 */ 754 if (protocol == PPP_IP && sc->sc_flags & SC_COMP_TCP) { 755 struct ip *ip; 756 int type; 757 struct mbuf *mp; 758 759 mp = m; 760 if (mp->m_len <= 0) { 761 mp = mp->m_next; 762 cp = mtod(mp, u_char *); 763 } 764 ip = (struct ip *) cp; 765 if (ip->ip_p == IPPROTO_TCP) { 766 type = sl_compress_tcp(mp, ip, &sc->sc_comp, 767 !(sc->sc_flags & SC_NO_TCP_CCID)); 768 switch (type) { 769 case TYPE_UNCOMPRESSED_TCP: 770 protocol = PPP_VJC_UNCOMP; 771 break; 772 case TYPE_COMPRESSED_TCP: 773 protocol = PPP_VJC_COMP; 774 break; 775 } 776 } 777 } 778 #endif 779 780 /* 781 * Compress the address/control and protocol, if possible. 782 */ 783 compac = sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && 784 control == PPP_UI && protocol != PPP_ALLSTATIONS && 785 protocol != PPP_LCP; 786 compprot = sc->sc_flags & SC_COMP_PROT && protocol < 0x100; 787 nb = (compac ? 0 : 2) + (compprot ? 1 : 2); 788 m->m_data -= nb; 789 m->m_len += nb; 790 791 cp = mtod(m, u_char *); 792 if (!compac) { 793 *cp++ = address; 794 *cp++ = control; 795 } 796 if (!compprot) 797 *cp++ = protocol >> 8; 798 *cp++ = protocol; 799 800 /* 801 * The extra PPP_FLAG will start up a new packet, and thus 802 * will flush any accumulated garbage. We do this whenever 803 * the line may have been idle for some time. 804 */ 805 if (CCOUNT(&tp->t_outq) == 0) { 806 ++sc->sc_bytessent; 807 (void) putc(PPP_FLAG, &tp->t_outq); 808 } 809 810 /* Calculate the FCS for the first mbuf's worth. */ 811 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); 812 } 813 814 for (;;) { 815 start = mtod(m, u_char *); 816 len = m->m_len; 817 stop = start + len; 818 while (len > 0) { 819 /* 820 * Find out how many bytes in the string we can 821 * handle without doing something special. 822 */ 823 for (cp = start; cp < stop; cp++) 824 if (ESCAPE_P(*cp)) 825 break; 826 n = cp - start; 827 if (n) { 828 #ifndef RB_LEN 829 /* NetBSD (0.9 or later), 4.3-Reno or similar. */ 830 ndone = n - b_to_q(start, n, &tp->t_outq); 831 #else 832 #ifdef NetBSD 833 /* NetBSD with 2-byte ring buffer entries */ 834 ndone = rb_cwrite(&tp->t_out, start, n); 835 #else 836 /* 386BSD, FreeBSD */ 837 int cc, nleft; 838 for (nleft = n; nleft > 0; nleft -= cc) { 839 if ((cc = RB_CONTIGPUT(&tp->t_out)) == 0) 840 break; 841 cc = min (cc, nleft); 842 bcopy((char *)start + n - nleft, tp->t_out.rb_tl, cc); 843 tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out, 844 tp->t_out.rb_tl + cc); 845 } 846 ndone = n - nleft; 847 #endif /* NetBSD */ 848 #endif /* RB_LEN */ 849 len -= ndone; 850 start += ndone; 851 sc->sc_bytessent += ndone; 852 853 if (ndone < n) 854 break; /* packet doesn't fit */ 855 } 856 /* 857 * If there are characters left in the mbuf, 858 * the first one must be special.. 859 * Put it out in a different form. 860 */ 861 if (len) { 862 if (putc(PPP_ESCAPE, &tp->t_outq)) 863 break; 864 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { 865 (void) unputc(&tp->t_outq); 866 break; 867 } 868 sc->sc_bytessent += 2; 869 start++; 870 len--; 871 } 872 } 873 /* 874 * If we didn't empty this mbuf, remember where we're up to. 875 * If we emptied the last mbuf, try to add the FCS and closing 876 * flag, and if we can't, leave sc_outm pointing to m, but with 877 * m->m_len == 0, to remind us to output the FCS and flag later. 878 */ 879 done = len == 0; 880 if (done && m->m_next == NULL) { 881 u_char *p, *q; 882 int c; 883 u_char endseq[8]; 884 885 /* 886 * We may have to escape the bytes in the FCS. 887 */ 888 p = endseq; 889 c = ~sc->sc_outfcs & 0xFF; 890 if (ESCAPE_P(c)) { 891 *p++ = PPP_ESCAPE; 892 *p++ = c ^ PPP_TRANS; 893 } else 894 *p++ = c; 895 c = (~sc->sc_outfcs >> 8) & 0xFF; 896 if (ESCAPE_P(c)) { 897 *p++ = PPP_ESCAPE; 898 *p++ = c ^ PPP_TRANS; 899 } else 900 *p++ = c; 901 *p++ = PPP_FLAG; 902 903 /* 904 * Try to output the FCS and flag. If the bytes 905 * don't all fit, back out. 906 */ 907 for (q = endseq; q < p; ++q) 908 if (putc(*q, &tp->t_outq)) { 909 done = 0; 910 for (; q > endseq; --q) 911 unputc(&tp->t_outq); 912 break; 913 } 914 } 915 916 if (!done) { 917 m->m_data = start; 918 m->m_len = len; 919 sc->sc_outm = m; 920 if (tp->t_oproc != NULL) 921 (*tp->t_oproc)(tp); 922 return; /* can't do any more at the moment */ 923 } 924 925 /* Finished with this mbuf; free it and move on. */ 926 MFREE(m, m2); 927 if (m2 == NULL) 928 break; 929 930 m = m2; 931 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); 932 } 933 934 /* Finished a packet */ 935 sc->sc_outm = NULL; 936 sc->sc_bytessent++; /* account for closing flag */ 937 sc->sc_if.if_opackets++; 938 sc->sc_if.if_obytes = sc->sc_bytessent; 939 } 940 } 941 942 /* 943 * Allocate enough mbuf to handle current MRU. 944 */ 945 static int 946 pppinit(sc) 947 register struct ppp_softc *sc; 948 { 949 struct mbuf *m, **mp; 950 int len = HDROFF + sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN; 951 int s; 952 953 s = splimp(); 954 for (mp = &sc->sc_m; (m = *mp) != NULL; mp = &m->m_next) 955 if ((len -= M_DATASIZE(m)) <= 0) { 956 splx(s); 957 return (1); 958 } 959 960 for (;; mp = &m->m_next) { 961 MGETHDR(m, M_DONTWAIT, MT_DATA); 962 if (m == 0) { 963 m_freem(sc->sc_m); 964 sc->sc_m = NULL; 965 splx(s); 966 printf("ppp%d: can't allocate mbuf\n", sc->sc_if.if_unit); 967 return (0); 968 } 969 *mp = m; 970 MCLGET(m, M_DONTWAIT); 971 if ((len -= M_DATASIZE(m)) <= 0) { 972 splx(s); 973 return (1); 974 } 975 } 976 } 977 978 /* 979 * Copy mbuf chain. Would like to use m_copy(), but we need a real copy 980 * of the data, not just copies of pointers to the data. 981 */ 982 static struct mbuf * 983 ppp_btom(sc) 984 struct ppp_softc *sc; 985 { 986 register struct mbuf *m, **mp; 987 struct mbuf *top = sc->sc_m; 988 989 /* 990 * First check current mbuf. If we have more than a small mbuf, 991 * return the whole cluster and set beginning of buffer to the 992 * next mbuf. 993 * Else, copy the current bytes into a small mbuf, attach the new 994 * mbuf to the end of the chain and set beginning of buffer to the 995 * current mbuf. 996 */ 997 998 if (sc->sc_mc->m_len > MHLEN) { 999 sc->sc_m = sc->sc_mc->m_next; 1000 sc->sc_mc->m_next = NULL; 1001 } 1002 else { 1003 /* rather than waste a whole cluster on <= MHLEN bytes, 1004 alloc a small mbuf and copy to it */ 1005 MGETHDR(m, M_DONTWAIT, MT_DATA); 1006 if (m == NULL) 1007 return (NULL); 1008 1009 bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t), sc->sc_mc->m_len); 1010 m->m_len = sc->sc_mc->m_len; 1011 for (mp = ⊤ *mp != sc->sc_mc; mp = &(*mp)->m_next) 1012 ; 1013 *mp = m; 1014 sc->sc_m = sc->sc_mc; 1015 } 1016 1017 /* 1018 * Try to allocate enough extra mbufs to handle the next packet. 1019 */ 1020 if (pppinit(sc) == 0) { 1021 m_freem(top); 1022 if (pppinit(sc) == 0) 1023 sc->sc_if.if_flags &= ~IFF_UP; 1024 return (NULL); 1025 } 1026 1027 return (top); 1028 } 1029 1030 /* 1031 * tty interface receiver interrupt. 1032 */ 1033 #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ 1034 TYPE_UNCOMPRESSED_TCP) 1035 1036 void 1037 pppinput(c, tp) 1038 int c; 1039 register struct tty *tp; 1040 { 1041 register struct ppp_softc *sc; 1042 struct mbuf *m; 1043 struct ifqueue *inq; 1044 int s, ilen, xlen, proto; 1045 struct ppp_header hdr; 1046 1047 tk_nin++; 1048 sc = (struct ppp_softc *)tp->t_sc; 1049 if (sc == NULL) 1050 return; 1051 1052 ++sc->sc_if.if_ibytes; 1053 1054 if (c & TTY_FE) { 1055 /* framing error or overrun on this char - abort packet */ 1056 if (ppp_debug) 1057 printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c); 1058 goto flush; 1059 } 1060 1061 c &= 0xff; 1062 1063 if (sc->sc_if.if_unit == ppp_raw_in_debug) { 1064 ppp_rawin[ppp_rawin_count++] = c; 1065 if (ppp_rawin_count >= sizeof(ppp_rawin)) { 1066 printf("raw ppp%d: ", ppp_raw_in_debug); 1067 pppdumpb(ppp_rawin, ppp_rawin_count); 1068 ppp_rawin_count = 0; 1069 } 1070 } 1071 1072 if (c == PPP_FLAG) { 1073 ilen = sc->sc_ilen; 1074 sc->sc_ilen = 0; 1075 1076 if (sc->sc_flags & SC_FLUSH 1077 || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) { 1078 #ifdef VJC 1079 /* 1080 * If we've missed a packet, we must toss subsequent compressed 1081 * packets which don't have an explicit connection ID. 1082 */ 1083 sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp); 1084 #endif 1085 if ((sc->sc_flags & SC_FLUSH) == 0){ 1086 if (ppp_debug) 1087 printf("ppp%d: bad fcs\n", sc->sc_if.if_unit); 1088 sc->sc_if.if_ierrors++; 1089 } else 1090 sc->sc_flags &= ~SC_FLUSH; 1091 return; 1092 } 1093 1094 if (ilen < PPP_HEADER_LEN + PPP_FCS_LEN) { 1095 if (ilen) { 1096 if (ppp_debug) 1097 printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); 1098 sc->sc_if.if_ierrors++; 1099 } 1100 return; 1101 } 1102 1103 /* 1104 * Remove FCS trailer. Somewhat painful... 1105 */ 1106 ilen -= 2; 1107 if (--sc->sc_mc->m_len == 0) { 1108 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 1109 ; 1110 sc->sc_mc = m; 1111 } 1112 sc->sc_mc->m_len--; 1113 1114 sc->sc_if.if_ipackets++; 1115 m = sc->sc_m; 1116 1117 if (ppp_async_in_debug) { 1118 printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen); 1119 pppdumpm(m, ilen); 1120 } 1121 1122 hdr = *mtod(m, struct ppp_header *); 1123 proto = ntohs(hdr.ph_protocol); 1124 1125 #ifdef VJC 1126 /* 1127 * See if we have a VJ-compressed packet to uncompress. 1128 */ 1129 if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) { 1130 char *pkttype = proto == PPP_VJC_COMP? "": "un"; 1131 1132 if (sc->sc_flags & SC_REJ_COMP_TCP) { 1133 if (ppp_debug) 1134 printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n", 1135 sc->sc_if.if_unit, pkttype, sc->sc_flags); 1136 sc->sc_if.if_ierrors++; 1137 return; 1138 } 1139 1140 m->m_data += PPP_HEADER_LEN; 1141 m->m_len -= PPP_HEADER_LEN; 1142 ilen -= PPP_HEADER_LEN; 1143 xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data), 1144 m->m_len, ilen, 1145 COMPTYPE(proto), &sc->sc_comp); 1146 1147 if (xlen == 0) { 1148 if (ppp_debug) 1149 printf("ppp%d: sl_uncompress failed on type %scomp\n", 1150 sc->sc_if.if_unit, pkttype); 1151 sc->sc_if.if_ierrors++; 1152 return; 1153 } 1154 1155 /* adjust the first mbuf by the decompressed amt */ 1156 xlen += PPP_HEADER_LEN; 1157 m->m_len += xlen - ilen; 1158 ilen = xlen; 1159 m->m_data -= PPP_HEADER_LEN; 1160 proto = PPP_IP; 1161 1162 #if NBPFILTER > 0 1163 /* put the ppp header back in place */ 1164 hdr.ph_protocol = htons(PPP_IP); 1165 *mtod(m, struct ppp_header *) = hdr; 1166 #endif /* NBPFILTER */ 1167 } 1168 #endif /* VJC */ 1169 1170 /* get this packet as an mbuf chain */ 1171 if ((m = ppp_btom(sc)) == NULL) { 1172 sc->sc_if.if_ierrors++; 1173 return; 1174 } 1175 m->m_pkthdr.len = ilen; 1176 m->m_pkthdr.rcvif = &sc->sc_if; 1177 1178 #if NBPFILTER > 0 1179 /* See if bpf wants to look at the packet. */ 1180 if (sc->sc_bpf) 1181 bpf_mtap(sc->sc_bpf, m); 1182 #endif 1183 1184 switch (proto) { 1185 #ifdef INET 1186 case PPP_IP: 1187 /* 1188 * IP packet - take off the ppp header and pass it up to IP. 1189 */ 1190 if ((sc->sc_if.if_flags & IFF_UP) == 0) { 1191 /* interface is down - drop the packet. */ 1192 m_freem(m); 1193 sc->sc_if.if_ierrors++; 1194 return; 1195 } 1196 m->m_pkthdr.len -= PPP_HEADER_LEN; 1197 m->m_data += PPP_HEADER_LEN; 1198 m->m_len -= PPP_HEADER_LEN; 1199 schednetisr(NETISR_IP); 1200 inq = &ipintrq; 1201 break; 1202 #endif 1203 1204 default: 1205 /* 1206 * Some other protocol - place on input queue for read(). 1207 * Put a placeholder byte in canq for ttselect()/ttnread(). 1208 */ 1209 putc(0, &tp->t_canq); 1210 ttwakeup(tp); 1211 inq = &sc->sc_inq; 1212 break; 1213 } 1214 1215 /* 1216 * Put the packet on the appropriate input queue. 1217 */ 1218 s = splimp(); 1219 if (IF_QFULL(inq)) { 1220 IF_DROP(inq); 1221 if (ppp_debug) 1222 printf("ppp%d: queue full\n", sc->sc_if.if_unit); 1223 sc->sc_if.if_ierrors++; 1224 sc->sc_if.if_iqdrops++; 1225 m_freem(m); 1226 } else 1227 IF_ENQUEUE(inq, m); 1228 1229 splx(s); 1230 return; 1231 } 1232 1233 if (sc->sc_flags & SC_FLUSH) 1234 return; 1235 if (c == PPP_ESCAPE) { 1236 sc->sc_flags |= SC_ESCAPED; 1237 return; 1238 } 1239 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 1240 return; 1241 1242 if (sc->sc_flags & SC_ESCAPED) { 1243 sc->sc_flags &= ~SC_ESCAPED; 1244 c ^= PPP_TRANS; 1245 } 1246 1247 /* 1248 * Initialize buffer on first octet received. 1249 * First octet could be address or protocol (when compressing 1250 * address/control). 1251 * Second octet is control. 1252 * Third octet is first or second (when compressing protocol) 1253 * octet of protocol. 1254 * Fourth octet is second octet of protocol. 1255 */ 1256 if (sc->sc_ilen == 0) { 1257 /* reset the first input mbuf */ 1258 m = sc->sc_m; 1259 m->m_len = 0; 1260 m->m_data = M_DATASTART(sc->sc_m) + HDROFF; 1261 sc->sc_mc = m; 1262 sc->sc_mp = mtod(m, char *); 1263 sc->sc_fcs = PPP_INITFCS; 1264 if (c != PPP_ALLSTATIONS) { 1265 if (sc->sc_flags & SC_REJ_COMP_AC) { 1266 if (ppp_debug) 1267 printf("ppp%d: missing ALLSTATIONS, got 0x%x; flags %x\n", 1268 sc->sc_if.if_unit, c, sc->sc_flags); 1269 goto flush; 1270 } 1271 *sc->sc_mp++ = PPP_ALLSTATIONS; 1272 *sc->sc_mp++ = PPP_UI; 1273 sc->sc_ilen += 2; 1274 m->m_len += 2; 1275 } 1276 } 1277 if (sc->sc_ilen == 1 && c != PPP_UI) { 1278 if (ppp_debug) 1279 printf("ppp%d: missing UI, got 0x%x\n", sc->sc_if.if_unit, c); 1280 goto flush; 1281 } 1282 if (sc->sc_ilen == 2 && (c & 1) == 1) { 1283 /* RFC1331 says we have to accept a compressed protocol */ 1284 *sc->sc_mp++ = 0; 1285 sc->sc_ilen++; 1286 sc->sc_mc->m_len++; 1287 } 1288 if (sc->sc_ilen == 3 && (c & 1) == 0) { 1289 if (ppp_debug) 1290 printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, 1291 (sc->sc_mp[-1] << 8) + c); 1292 goto flush; 1293 } 1294 1295 /* packet beyond configured mru? */ 1296 if (++sc->sc_ilen > sc->sc_mru + PPP_HEADER_LEN + PPP_FCS_LEN) { 1297 if (ppp_debug) 1298 printf("ppp%d: packet too big\n", sc->sc_if.if_unit); 1299 goto flush; 1300 } 1301 1302 /* is this mbuf full? */ 1303 m = sc->sc_mc; 1304 if (M_TRAILINGSPACE(m) <= 0) { 1305 sc->sc_mc = m = m->m_next; 1306 if (m == NULL) { 1307 printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); 1308 goto flush; 1309 } 1310 m->m_len = 0; 1311 m->m_data = M_DATASTART(m); 1312 sc->sc_mp = mtod(m, char *); 1313 } 1314 1315 ++m->m_len; 1316 *sc->sc_mp++ = c; 1317 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1318 return; 1319 1320 flush: 1321 sc->sc_if.if_ierrors++; 1322 sc->sc_flags |= SC_FLUSH; 1323 } 1324 1325 /* 1326 * Process an ioctl request to interface. 1327 */ 1328 pppioctl(ifp, cmd, data) 1329 register struct ifnet *ifp; 1330 int cmd; 1331 caddr_t data; 1332 { 1333 struct proc *p = curproc; /* XXX */ 1334 register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; 1335 register struct ifaddr *ifa = (struct ifaddr *)data; 1336 register struct ifreq *ifr = (struct ifreq *)data; 1337 int s = splimp(), error = 0; 1338 1339 1340 switch (cmd) { 1341 case SIOCSIFFLAGS: 1342 if ((ifp->if_flags & IFF_RUNNING) == 0) 1343 ifp->if_flags &= ~IFF_UP; 1344 break; 1345 1346 case SIOCSIFADDR: 1347 if (ifa->ifa_addr->sa_family != AF_INET) 1348 error = EAFNOSUPPORT; 1349 break; 1350 1351 case SIOCSIFDSTADDR: 1352 if (ifa->ifa_addr->sa_family != AF_INET) 1353 error = EAFNOSUPPORT; 1354 break; 1355 1356 case SIOCSIFMTU: 1357 if (error = suser(p->p_ucred, &p->p_acflag)) 1358 return (error); 1359 sc->sc_if.if_mtu = ifr->ifr_mtu; 1360 break; 1361 1362 case SIOCGIFMTU: 1363 ifr->ifr_mtu = sc->sc_if.if_mtu; 1364 break; 1365 1366 default: 1367 error = EINVAL; 1368 } 1369 splx(s); 1370 return (error); 1371 } 1372 1373 #define MAX_DUMP_BYTES 128 1374 1375 static void 1376 pppdumpm(m0, pktlen) 1377 struct mbuf *m0; 1378 int pktlen; 1379 { 1380 char buf[2*MAX_DUMP_BYTES+4]; 1381 char *bp = buf; 1382 struct mbuf *m; 1383 static char digits[] = "0123456789abcdef"; 1384 1385 for (m = m0; m && pktlen; m = m->m_next) { 1386 int l = m->m_len; 1387 u_char *rptr = (u_char *)m->m_data; 1388 1389 if (pktlen > 0) { 1390 l = min(l, pktlen); 1391 pktlen -= l; 1392 } 1393 while (l--) { 1394 if (bp > buf + sizeof(buf) - 4) 1395 goto done; 1396 *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ 1397 *bp++ = digits[*rptr++ & 0xf]; 1398 } 1399 1400 if (m->m_next) { 1401 if (bp > buf + sizeof(buf) - 3) 1402 goto done; 1403 *bp++ = '|'; 1404 } 1405 } 1406 done: 1407 if (m && pktlen) 1408 *bp++ = '>'; 1409 *bp = 0; 1410 printf("%s\n", buf); 1411 } 1412 1413 static void 1414 pppdumpb(b, l) 1415 u_char *b; 1416 int l; 1417 { 1418 char buf[2*MAX_DUMP_BYTES+4]; 1419 char *bp = buf; 1420 static char digits[] = "0123456789abcdef"; 1421 1422 while (l--) { 1423 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1424 *bp++ = digits[*b++ & 0xf]; 1425 if (bp >= buf + sizeof(buf) - 2) { 1426 *bp++ = '>'; 1427 break; 1428 } 1429 } 1430 1431 *bp = 0; 1432 printf("%s\n", buf); 1433 } 1434 1435 1436 #endif /* NPPP > 0 */ 1437