1 /* $OpenBSD: ppp_tty.c,v 1.12 2001/06/15 03:38:34 itojun Exp $ */ 2 /* $NetBSD: ppp_tty.c,v 1.12 1997/03/24 21:23:10 christos Exp $ */ 3 4 /* 5 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous 6 * tty devices. 7 * 8 * Copyright (c) 1989 Carnegie Mellon University. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms are permitted 12 * provided that the above copyright notice and this paragraph are 13 * duplicated in all such forms and that any documentation, 14 * advertising materials, and other materials related to such 15 * distribution and use acknowledge that the software was developed 16 * by Carnegie Mellon University. The name of the 17 * University may not be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 21 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 * 23 * Drew D. Perkins 24 * Carnegie Mellon University 25 * 4910 Forbes Ave. 26 * Pittsburgh, PA 15213 27 * (412) 268-8576 28 * ddp@andrew.cmu.edu 29 * 30 * Based on: 31 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 32 * 33 * Copyright (c) 1987 Regents of the University of California. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms are permitted 37 * provided that the above copyright notice and this paragraph are 38 * duplicated in all such forms and that any documentation, 39 * advertising materials, and other materials related to such 40 * distribution and use acknowledge that the software was developed 41 * by the University of California, Berkeley. The name of the 42 * University may not be used to endorse or promote products derived 43 * from this software without specific prior written permission. 44 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 45 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 46 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 47 * 48 * Serial Line interface 49 * 50 * Rick Adams 51 * Center for Seismic Studies 52 * 1300 N 17th Street, Suite 1450 53 * Arlington, Virginia 22209 54 * (703)276-7900 55 * rick@seismo.ARPA 56 * seismo!rick 57 * 58 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 59 * Converted to 4.3BSD Beta by Chris Torek. 60 * Other changes made at Berkeley, based in part on code by Kirk Smith. 61 * 62 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com) 63 * Added VJ tcp header compression; more unified ioctls 64 * 65 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au). 66 * Cleaned up a lot of the mbuf-related code to fix bugs that 67 * caused system crashes and packet corruption. Changed pppstart 68 * so that it doesn't just give up with a collision if the whole 69 * packet doesn't fit in the output ring buffer. 70 * 71 * Added priority queueing for interactive IP packets, following 72 * the model of if_sl.c, plus hooks for bpf. 73 * Paul Mackerras (paulus@cs.anu.edu.au). 74 */ 75 76 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 77 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ 78 79 #include "ppp.h" 80 #if NPPP > 0 81 82 #define VJC 83 #define PPP_COMPRESS 84 85 #include <sys/param.h> 86 #include <sys/proc.h> 87 #include <sys/mbuf.h> 88 #include <sys/dkstat.h> 89 #include <sys/socket.h> 90 #include <sys/ioctl.h> 91 #include <sys/file.h> 92 #include <sys/tty.h> 93 #include <sys/kernel.h> 94 #include <sys/conf.h> 95 #include <sys/vnode.h> 96 #include <sys/systm.h> 97 98 #include <net/if.h> 99 #include <net/if_types.h> 100 101 #ifdef VJC 102 #include <netinet/in.h> 103 #include <netinet/in_systm.h> 104 #include <netinet/ip.h> 105 #include <net/slcompress.h> 106 #endif 107 108 #include <net/bpf.h> 109 #include <net/ppp_defs.h> 110 #include <net/if_ppp.h> 111 #include <net/if_pppvar.h> 112 113 int pppopen __P((dev_t dev, struct tty *tp)); 114 int pppclose __P((struct tty *tp, int flag)); 115 int pppread __P((struct tty *tp, struct uio *uio, int flag)); 116 int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); 117 int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag, 118 struct proc *)); 119 int pppinput __P((int c, struct tty *tp)); 120 int pppstart __P((struct tty *tp, int)); 121 122 u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len)); 123 void pppasyncstart __P((struct ppp_softc *)); 124 void pppasyncctlp __P((struct ppp_softc *)); 125 void pppasyncrelinq __P((struct ppp_softc *)); 126 void ppp_timeout __P((void *)); 127 void pppgetm __P((struct ppp_softc *sc)); 128 void pppdumpb __P((u_char *b, int l)); 129 void ppplogchar __P((struct ppp_softc *, int)); 130 131 /* 132 * Some useful mbuf macros not in mbuf.h. 133 */ 134 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) 135 136 #define M_DATASTART(m) \ 137 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ 138 (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) 139 140 #define M_DATASIZE(m) \ 141 (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ 142 (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) 143 144 /* 145 * Does c need to be escaped? 146 */ 147 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) 148 149 /* 150 * Procedures for using an async tty interface for PPP. 151 */ 152 153 /* This is a NetBSD-1.0 or later kernel. */ 154 #define CCOUNT(q) ((q)->c_cc) 155 156 #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */ 157 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ 158 159 /* 160 * Line specific open routine for async tty devices. 161 * Attach the given tty to the first available ppp unit. 162 * Called from device open routine or ttioctl. 163 */ 164 /* ARGSUSED */ 165 int 166 pppopen(dev, tp) 167 dev_t dev; 168 register struct tty *tp; 169 { 170 struct proc *p = curproc; /* XXX */ 171 register struct ppp_softc *sc; 172 int error, s; 173 174 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 175 return (error); 176 177 s = spltty(); 178 179 if (tp->t_line == PPPDISC) { 180 sc = (struct ppp_softc *) tp->t_sc; 181 if (sc != NULL && sc->sc_devp == (void *) tp) { 182 splx(s); 183 return (0); 184 } 185 } 186 187 if ((sc = pppalloc(p->p_pid)) == NULL) { 188 splx(s); 189 return ENXIO; 190 } 191 192 if (sc->sc_relinq) 193 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ 194 195 timeout_set(&sc->sc_timo, ppp_timeout, sc); 196 sc->sc_ilen = 0; 197 sc->sc_m = NULL; 198 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 199 sc->sc_asyncmap[0] = 0xffffffff; 200 sc->sc_asyncmap[3] = 0x60000000; 201 sc->sc_rasyncmap = 0; 202 sc->sc_devp = (void *) tp; 203 sc->sc_start = pppasyncstart; 204 sc->sc_ctlp = pppasyncctlp; 205 sc->sc_relinq = pppasyncrelinq; 206 sc->sc_outm = NULL; 207 pppgetm(sc); 208 sc->sc_if.if_flags |= IFF_RUNNING; 209 sc->sc_if.if_baudrate = tp->t_ospeed; 210 211 tp->t_sc = (caddr_t) sc; 212 ttyflush(tp, FREAD | FWRITE); 213 214 splx(s); 215 return (0); 216 } 217 218 /* 219 * Line specific close routine, called from device close routine 220 * and from ttioctl. 221 * Detach the tty from the ppp unit. 222 * Mimics part of ttyclose(). 223 */ 224 int 225 pppclose(tp, flag) 226 struct tty *tp; 227 int flag; 228 { 229 register struct ppp_softc *sc; 230 int s; 231 232 s = spltty(); 233 ttyflush(tp, FREAD|FWRITE); 234 tp->t_line = 0; 235 sc = (struct ppp_softc *) tp->t_sc; 236 if (sc != NULL) { 237 tp->t_sc = NULL; 238 if (tp == (struct tty *) sc->sc_devp) { 239 pppasyncrelinq(sc); 240 pppdealloc(sc); 241 } 242 } 243 splx(s); 244 return 0; 245 } 246 247 /* 248 * Relinquish the interface unit to another device. 249 */ 250 void 251 pppasyncrelinq(sc) 252 struct ppp_softc *sc; 253 { 254 int s; 255 256 s = spltty(); 257 if (sc->sc_outm) { 258 m_freem(sc->sc_outm); 259 sc->sc_outm = NULL; 260 } 261 if (sc->sc_m) { 262 m_freem(sc->sc_m); 263 sc->sc_m = NULL; 264 } 265 if (sc->sc_flags & SC_TIMEOUT) { 266 timeout_del(&sc->sc_timo); 267 sc->sc_flags &= ~SC_TIMEOUT; 268 } 269 splx(s); 270 } 271 272 /* 273 * Line specific (tty) read routine. 274 */ 275 int 276 pppread(tp, uio, flag) 277 register struct tty *tp; 278 struct uio *uio; 279 int flag; 280 { 281 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 282 struct mbuf *m, *m0; 283 register int s; 284 int error = 0; 285 286 if (sc == NULL) 287 return 0; 288 /* 289 * Loop waiting for input, checking that nothing disasterous 290 * happens in the meantime. 291 */ 292 s = spltty(); 293 for (;;) { 294 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) { 295 splx(s); 296 return 0; 297 } 298 if (sc->sc_inq.ifq_head != NULL) 299 break; 300 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0 301 && (tp->t_state & TS_ISOPEN)) { 302 splx(s); 303 return 0; /* end of file */ 304 } 305 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { 306 splx(s); 307 return (EWOULDBLOCK); 308 } 309 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0); 310 if (error) { 311 splx(s); 312 return error; 313 } 314 } 315 316 /* Pull place-holder byte out of canonical queue */ 317 getc(&tp->t_canq); 318 319 /* Get the packet from the input queue */ 320 IF_DEQUEUE(&sc->sc_inq, m0); 321 splx(s); 322 323 for (m = m0; m && uio->uio_resid; m = m->m_next) 324 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0) 325 break; 326 m_freem(m0); 327 return (error); 328 } 329 330 /* 331 * Line specific (tty) write routine. 332 */ 333 int 334 pppwrite(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, **mp; 341 struct sockaddr dst; 342 int len, error; 343 344 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 345 return 0; /* wrote 0 bytes */ 346 if (tp->t_line != PPPDISC) 347 return (EINVAL); 348 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 349 return EIO; 350 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || 351 uio->uio_resid < PPP_HDRLEN) 352 return (EMSGSIZE); 353 for (mp = &m0; uio->uio_resid; mp = &m->m_next) { 354 MGET(m, M_WAIT, MT_DATA); 355 *mp = m; 356 m->m_len = 0; 357 if (uio->uio_resid >= MCLBYTES / 2) 358 MCLGET(m, M_DONTWAIT); 359 len = M_TRAILINGSPACE(m); 360 if (len > uio->uio_resid) 361 len = uio->uio_resid; 362 if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) { 363 m_freem(m0); 364 return (error); 365 } 366 m->m_len = len; 367 } 368 dst.sa_family = AF_UNSPEC; 369 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); 370 m0->m_data += PPP_HDRLEN; 371 m0->m_len -= PPP_HDRLEN; 372 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0)); 373 } 374 375 /* 376 * Line specific (tty) ioctl routine. 377 * This discipline requires that tty device drivers call 378 * the line specific l_ioctl routine from their ioctl routines. 379 */ 380 /* ARGSUSED */ 381 int 382 ppptioctl(tp, cmd, data, flag, p) 383 struct tty *tp; 384 u_long cmd; 385 caddr_t data; 386 int flag; 387 struct proc *p; 388 { 389 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 390 int error, s; 391 392 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 393 return -1; 394 395 error = 0; 396 switch (cmd) { 397 case PPPIOCSASYNCMAP: 398 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 399 break; 400 sc->sc_asyncmap[0] = *(u_int *)data; 401 break; 402 403 case PPPIOCGASYNCMAP: 404 *(u_int *)data = sc->sc_asyncmap[0]; 405 break; 406 407 case PPPIOCSRASYNCMAP: 408 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 409 break; 410 sc->sc_rasyncmap = *(u_int *)data; 411 break; 412 413 case PPPIOCGRASYNCMAP: 414 *(u_int *)data = sc->sc_rasyncmap; 415 break; 416 417 case PPPIOCSXASYNCMAP: 418 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 419 break; 420 s = spltty(); 421 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 422 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ 423 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ 424 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ 425 splx(s); 426 break; 427 428 case PPPIOCGXASYNCMAP: 429 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); 430 break; 431 432 default: 433 error = pppioctl(sc, cmd, data, flag, p); 434 if (error == 0 && cmd == PPPIOCSMRU) 435 pppgetm(sc); 436 } 437 438 return error; 439 } 440 441 /* 442 * FCS lookup table as calculated by genfcstab. 443 */ 444 static u_int16_t fcstab[256] = { 445 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 446 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 447 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 448 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 449 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 450 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 451 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 452 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 453 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 454 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 455 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 456 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 457 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 458 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 459 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 460 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 461 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 462 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 463 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 464 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 465 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 466 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 467 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 468 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 469 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 470 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 471 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 472 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 473 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 474 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 475 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 476 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 477 }; 478 479 /* 480 * Calculate a new FCS given the current FCS and the new data. 481 */ 482 u_int16_t 483 pppfcs(fcs, cp, len) 484 register u_int16_t fcs; 485 register u_char *cp; 486 register int len; 487 { 488 while (len--) 489 fcs = PPP_FCS(fcs, *cp++); 490 return (fcs); 491 } 492 493 /* 494 * This gets called from pppoutput when a new packet is 495 * put on a queue, at splsoftnet. 496 */ 497 void 498 pppasyncstart(sc) 499 register struct ppp_softc *sc; 500 { 501 register struct tty *tp = (struct tty *) sc->sc_devp; 502 register struct mbuf *m; 503 register int len; 504 register u_char *start, *stop, *cp; 505 int n, ndone, done, idle; 506 struct mbuf *m2; 507 int s; 508 509 idle = 0; 510 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) { 511 /* 512 * See if we have an existing packet partly sent. 513 * If not, get a new packet and start sending it. 514 */ 515 m = sc->sc_outm; 516 if (m == NULL) { 517 /* 518 * Get another packet to be sent. 519 */ 520 m = ppp_dequeue(sc); 521 if (m == NULL) { 522 idle = 1; 523 break; 524 } 525 526 /* 527 * The extra PPP_FLAG will start up a new packet, and thus 528 * will flush any accumulated garbage. We do this whenever 529 * the line may have been idle for some time. 530 */ 531 if (CCOUNT(&tp->t_outq) == 0) { 532 ++sc->sc_stats.ppp_obytes; 533 (void) putc(PPP_FLAG, &tp->t_outq); 534 } 535 536 /* Calculate the FCS for the first mbuf's worth. */ 537 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); 538 } 539 540 for (;;) { 541 start = mtod(m, u_char *); 542 len = m->m_len; 543 stop = start + len; 544 while (len > 0) { 545 /* 546 * Find out how many bytes in the string we can 547 * handle without doing something special. 548 */ 549 for (cp = start; cp < stop; cp++) 550 if (ESCAPE_P(*cp)) 551 break; 552 n = cp - start; 553 if (n) { 554 /* NetBSD (0.9 or later), 4.3-Reno or similar. */ 555 ndone = n - b_to_q(start, n, &tp->t_outq); 556 len -= ndone; 557 start += ndone; 558 sc->sc_stats.ppp_obytes += ndone; 559 560 if (ndone < n) 561 break; /* packet doesn't fit */ 562 } 563 /* 564 * If there are characters left in the mbuf, 565 * the first one must be special. 566 * Put it out in a different form. 567 */ 568 if (len) { 569 s = spltty(); 570 if (putc(PPP_ESCAPE, &tp->t_outq)) { 571 splx(s); 572 break; 573 } 574 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { 575 (void) unputc(&tp->t_outq); 576 splx(s); 577 break; 578 } 579 splx(s); 580 sc->sc_stats.ppp_obytes += 2; 581 start++; 582 len--; 583 } 584 } 585 586 /* 587 * If we didn't empty this mbuf, remember where we're up to. 588 * If we emptied the last mbuf, try to add the FCS and closing 589 * flag, and if we can't, leave sc_outm pointing to m, but with 590 * m->m_len == 0, to remind us to output the FCS and flag later. 591 */ 592 done = len == 0; 593 if (done && m->m_next == NULL) { 594 u_char *p, *q; 595 int c; 596 u_char endseq[8]; 597 598 /* 599 * We may have to escape the bytes in the FCS. 600 */ 601 p = endseq; 602 c = ~sc->sc_outfcs & 0xFF; 603 if (ESCAPE_P(c)) { 604 *p++ = PPP_ESCAPE; 605 *p++ = c ^ PPP_TRANS; 606 } else 607 *p++ = c; 608 c = (~sc->sc_outfcs >> 8) & 0xFF; 609 if (ESCAPE_P(c)) { 610 *p++ = PPP_ESCAPE; 611 *p++ = c ^ PPP_TRANS; 612 } else 613 *p++ = c; 614 *p++ = PPP_FLAG; 615 616 /* 617 * Try to output the FCS and flag. If the bytes 618 * don't all fit, back out. 619 */ 620 s = spltty(); 621 for (q = endseq; q < p; ++q) 622 if (putc(*q, &tp->t_outq)) { 623 done = 0; 624 for (; q > endseq; --q) 625 unputc(&tp->t_outq); 626 break; 627 } 628 splx(s); 629 if (done) 630 sc->sc_stats.ppp_obytes += q - endseq; 631 } 632 633 if (!done) { 634 /* remember where we got to */ 635 m->m_data = start; 636 m->m_len = len; 637 break; 638 } 639 640 /* Finished with this mbuf; free it and move on. */ 641 MFREE(m, m2); 642 m = m2; 643 if (m == NULL) { 644 /* Finished a packet */ 645 break; 646 } 647 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); 648 } 649 650 /* 651 * If m == NULL, we have finished a packet. 652 * If m != NULL, we've either done as much work this time 653 * as we need to, or else we've filled up the output queue. 654 */ 655 sc->sc_outm = m; 656 if (m) 657 break; 658 } 659 660 /* Call pppstart to start output again if necessary. */ 661 s = spltty(); 662 pppstart(tp, 0); 663 664 /* 665 * This timeout is needed for operation on a pseudo-tty, 666 * because the pty code doesn't call pppstart after it has 667 * drained the t_outq. 668 */ 669 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) { 670 timeout_add(&sc->sc_timo, 1); 671 sc->sc_flags |= SC_TIMEOUT; 672 } 673 674 splx(s); 675 } 676 677 /* 678 * This gets called when a received packet is placed on 679 * the inq, at splsoftnet. 680 */ 681 void 682 pppasyncctlp(sc) 683 struct ppp_softc *sc; 684 { 685 struct tty *tp; 686 int s; 687 688 /* Put a placeholder byte in canq for ttselect()/ttnread(). */ 689 s = spltty(); 690 tp = (struct tty *) sc->sc_devp; 691 putc(0, &tp->t_canq); 692 ttwakeup(tp); 693 splx(s); 694 } 695 696 /* 697 * Start output on async tty interface. If the transmit queue 698 * has drained sufficiently, arrange for pppasyncstart to be 699 * called later at splsoftnet. 700 */ 701 int 702 pppstart(tp, force) 703 register struct tty *tp; 704 int force; 705 { 706 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 707 708 /* 709 * If there is stuff in the output queue, send it now. 710 * We are being called in lieu of ttstart and must do what it would. 711 */ 712 if (tp->t_oproc != NULL) 713 (*tp->t_oproc)(tp); 714 715 /* 716 * If the transmit queue has drained and the tty has not hung up 717 * or been disconnected from the ppp unit, then tell if_ppp.c that 718 * we need more output. 719 */ 720 if ((CCOUNT(&tp->t_outq) < PPP_LOWAT || force) 721 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 722 && sc != NULL && tp == (struct tty *) sc->sc_devp) { 723 ppp_restart(sc); 724 } 725 726 return 0; 727 } 728 729 /* 730 * Timeout routine - try to start some more output. 731 */ 732 void 733 ppp_timeout(x) 734 void *x; 735 { 736 struct ppp_softc *sc = (struct ppp_softc *) x; 737 struct tty *tp = (struct tty *) sc->sc_devp; 738 int s; 739 740 s = spltty(); 741 sc->sc_flags &= ~SC_TIMEOUT; 742 pppstart(tp, 1); 743 splx(s); 744 } 745 746 /* 747 * Allocate enough mbuf to handle current MRU. 748 */ 749 void 750 pppgetm(sc) 751 register struct ppp_softc *sc; 752 { 753 struct mbuf *m, **mp; 754 int len; 755 int s; 756 757 s = spltty(); 758 mp = &sc->sc_m; 759 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ 760 if ((m = *mp) == NULL) { 761 MGETHDR(m, M_DONTWAIT, MT_DATA); 762 if (m == NULL) 763 break; 764 *mp = m; 765 MCLGET(m, M_DONTWAIT); 766 } 767 len -= M_DATASIZE(m); 768 mp = &m->m_next; 769 } 770 splx(s); 771 } 772 773 /* 774 * tty interface receiver interrupt. 775 */ 776 static unsigned int paritytab[8] = { 777 0x96696996, 0x69969669, 0x69969669, 0x96696996, 778 0x69969669, 0x96696996, 0x96696996, 0x69969669 779 }; 780 781 int 782 pppinput(c, tp) 783 int c; 784 register struct tty *tp; 785 { 786 register struct ppp_softc *sc; 787 struct mbuf *m; 788 int ilen, s; 789 790 sc = (struct ppp_softc *) tp->t_sc; 791 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 792 return 0; 793 794 ++tk_nin; 795 ++sc->sc_stats.ppp_ibytes; 796 797 if (c & TTY_FE) { 798 /* framing error or overrun on this char - abort packet */ 799 if (sc->sc_flags & SC_DEBUG) 800 printf("%s: bad char %x\n", sc->sc_if.if_xname, c); 801 goto flush; 802 } 803 804 c &= 0xff; 805 806 /* 807 * Handle software flow control of output. 808 */ 809 if (tp->t_iflag & IXON) { 810 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 811 if ((tp->t_state & TS_TTSTOP) == 0) { 812 tp->t_state |= TS_TTSTOP; 813 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 814 } 815 return 0; 816 } 817 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { 818 tp->t_state &= ~TS_TTSTOP; 819 if (tp->t_oproc != NULL) 820 (*tp->t_oproc)(tp); 821 return 0; 822 } 823 } 824 825 s = spltty(); 826 if (c & 0x80) 827 sc->sc_flags |= SC_RCV_B7_1; 828 else 829 sc->sc_flags |= SC_RCV_B7_0; 830 if (paritytab[c >> 5] & (1 << (c & 0x1F))) 831 sc->sc_flags |= SC_RCV_ODDP; 832 else 833 sc->sc_flags |= SC_RCV_EVNP; 834 splx(s); 835 836 if (sc->sc_flags & SC_LOG_RAWIN) 837 ppplogchar(sc, c); 838 839 if (c == PPP_FLAG) { 840 ilen = sc->sc_ilen; 841 sc->sc_ilen = 0; 842 843 if (sc->sc_rawin_count > 0) 844 ppplogchar(sc, -1); 845 846 /* 847 * If SC_ESCAPED is set, then we've seen the packet 848 * abort sequence "}~". 849 */ 850 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) 851 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { 852 s = spltty(); 853 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ 854 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ 855 if (sc->sc_flags & SC_DEBUG) 856 printf("%s: bad fcs %x\n", sc->sc_if.if_xname, 857 sc->sc_fcs); 858 sc->sc_if.if_ierrors++; 859 sc->sc_stats.ppp_ierrors++; 860 } else 861 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); 862 splx(s); 863 return 0; 864 } 865 866 if (ilen < PPP_HDRLEN + PPP_FCSLEN) { 867 if (ilen) { 868 if (sc->sc_flags & SC_DEBUG) 869 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen); 870 s = spltty(); 871 sc->sc_if.if_ierrors++; 872 sc->sc_stats.ppp_ierrors++; 873 sc->sc_flags |= SC_PKTLOST; 874 splx(s); 875 } 876 return 0; 877 } 878 879 /* 880 * Remove FCS trailer. Somewhat painful... 881 */ 882 ilen -= 2; 883 if (--sc->sc_mc->m_len == 0) { 884 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 885 ; 886 sc->sc_mc = m; 887 } 888 sc->sc_mc->m_len--; 889 890 /* excise this mbuf chain */ 891 m = sc->sc_m; 892 sc->sc_m = sc->sc_mc->m_next; 893 sc->sc_mc->m_next = NULL; 894 895 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); 896 if (sc->sc_flags & SC_PKTLOST) { 897 s = spltty(); 898 sc->sc_flags &= ~SC_PKTLOST; 899 splx(s); 900 } 901 902 pppgetm(sc); 903 return 0; 904 } 905 906 if (sc->sc_flags & SC_FLUSH) { 907 if (sc->sc_flags & SC_LOG_FLUSH) 908 ppplogchar(sc, c); 909 return 0; 910 } 911 912 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 913 return 0; 914 915 s = spltty(); 916 if (sc->sc_flags & SC_ESCAPED) { 917 sc->sc_flags &= ~SC_ESCAPED; 918 c ^= PPP_TRANS; 919 } else if (c == PPP_ESCAPE) { 920 sc->sc_flags |= SC_ESCAPED; 921 splx(s); 922 return 0; 923 } 924 splx(s); 925 926 /* 927 * Initialize buffer on first octet received. 928 * First octet could be address or protocol (when compressing 929 * address/control). 930 * Second octet is control. 931 * Third octet is first or second (when compressing protocol) 932 * octet of protocol. 933 * Fourth octet is second octet of protocol. 934 */ 935 if (sc->sc_ilen == 0) { 936 /* reset the first input mbuf */ 937 if (sc->sc_m == NULL) { 938 pppgetm(sc); 939 if (sc->sc_m == NULL) { 940 if (sc->sc_flags & SC_DEBUG) 941 printf("%s: no input mbufs!\n", sc->sc_if.if_xname); 942 goto flush; 943 } 944 } 945 m = sc->sc_m; 946 m->m_len = 0; 947 m->m_data = M_DATASTART(sc->sc_m); 948 sc->sc_mc = m; 949 sc->sc_mp = mtod(m, char *); 950 sc->sc_fcs = PPP_INITFCS; 951 if (c != PPP_ALLSTATIONS) { 952 if (sc->sc_flags & SC_REJ_COMP_AC) { 953 if (sc->sc_flags & SC_DEBUG) 954 printf("%s: garbage received: 0x%x (need 0xFF)\n", 955 sc->sc_if.if_xname, c); 956 goto flush; 957 } 958 *sc->sc_mp++ = PPP_ALLSTATIONS; 959 *sc->sc_mp++ = PPP_UI; 960 sc->sc_ilen += 2; 961 m->m_len += 2; 962 } 963 } 964 if (sc->sc_ilen == 1 && c != PPP_UI) { 965 if (sc->sc_flags & SC_DEBUG) 966 printf("%s: missing UI (0x3), got 0x%x\n", 967 sc->sc_if.if_xname, c); 968 goto flush; 969 } 970 if (sc->sc_ilen == 2 && (c & 1) == 1) { 971 /* a compressed protocol */ 972 *sc->sc_mp++ = 0; 973 sc->sc_ilen++; 974 sc->sc_mc->m_len++; 975 } 976 if (sc->sc_ilen == 3 && (c & 1) == 0) { 977 if (sc->sc_flags & SC_DEBUG) 978 printf("%s: bad protocol %x\n", sc->sc_if.if_xname, 979 (sc->sc_mp[-1] << 8) + c); 980 goto flush; 981 } 982 983 /* packet beyond configured mru? */ 984 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { 985 if (sc->sc_flags & SC_DEBUG) 986 printf("%s: packet too big\n", sc->sc_if.if_xname); 987 goto flush; 988 } 989 990 /* is this mbuf full? */ 991 m = sc->sc_mc; 992 if (M_TRAILINGSPACE(m) <= 0) { 993 if (m->m_next == NULL) { 994 pppgetm(sc); 995 if (m->m_next == NULL) { 996 if (sc->sc_flags & SC_DEBUG) 997 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname); 998 goto flush; 999 } 1000 } 1001 sc->sc_mc = m = m->m_next; 1002 m->m_len = 0; 1003 m->m_data = M_DATASTART(m); 1004 sc->sc_mp = mtod(m, char *); 1005 } 1006 1007 ++m->m_len; 1008 *sc->sc_mp++ = c; 1009 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1010 return 0; 1011 1012 flush: 1013 if (!(sc->sc_flags & SC_FLUSH)) { 1014 s = spltty(); 1015 sc->sc_if.if_ierrors++; 1016 sc->sc_stats.ppp_ierrors++; 1017 sc->sc_flags |= SC_FLUSH; 1018 splx(s); 1019 if (sc->sc_flags & SC_LOG_FLUSH) 1020 ppplogchar(sc, c); 1021 } 1022 return 0; 1023 } 1024 1025 #define MAX_DUMP_BYTES 128 1026 1027 void 1028 ppplogchar(sc, c) 1029 struct ppp_softc *sc; 1030 int c; 1031 { 1032 if (c >= 0) 1033 sc->sc_rawin[sc->sc_rawin_count++] = c; 1034 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) 1035 || (c < 0 && sc->sc_rawin_count > 0)) { 1036 printf("%s input: ", sc->sc_if.if_xname); 1037 pppdumpb(sc->sc_rawin, sc->sc_rawin_count); 1038 sc->sc_rawin_count = 0; 1039 } 1040 } 1041 1042 void 1043 pppdumpb(b, l) 1044 u_char *b; 1045 int l; 1046 { 1047 char buf[3*MAX_DUMP_BYTES+4]; 1048 char *bp = buf; 1049 static char digits[] = "0123456789abcdef"; 1050 1051 while (l--) { 1052 if (bp >= buf + sizeof(buf) - 3) { 1053 *bp++ = '>'; 1054 break; 1055 } 1056 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1057 *bp++ = digits[*b++ & 0xf]; 1058 *bp++ = ' '; 1059 } 1060 1061 *bp = 0; 1062 printf("%s\n", buf); 1063 } 1064 1065 #endif /* NPPP > 0 */ 1066