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