1 /* $OpenBSD: ppp_tty.c,v 1.44 2016/09/15 02:00:18 dlg 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/socket.h> 105 #include <sys/timeout.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 #include <sys/rwlock.h> 114 #include <sys/pool.h> 115 116 #include <net/if.h> 117 #include <net/if_var.h> 118 119 #ifdef VJC 120 #include <netinet/in.h> 121 #include <netinet/ip.h> 122 #include <net/slcompress.h> 123 #endif 124 125 #include <net/bpf.h> 126 #include <net/ppp_defs.h> 127 #include <net/if_ppp.h> 128 #include <net/if_pppvar.h> 129 130 int pppstart_internal(struct tty *tp, int); 131 132 u_int16_t pppfcs(u_int16_t fcs, u_char *cp, int len); 133 void pppasyncstart(struct ppp_softc *); 134 void pppasyncctlp(struct ppp_softc *); 135 void pppasyncrelinq(struct ppp_softc *); 136 void ppp_timeout(void *); 137 void ppppkt(struct ppp_softc *sc); 138 void pppdumpb(u_char *b, int l); 139 void ppplogchar(struct ppp_softc *, int); 140 141 struct rwlock ppp_pkt_init = RWLOCK_INITIALIZER("ppppktini"); 142 struct pool ppp_pkts; 143 144 #define PKT_MAXLEN(_sc) ((_sc)->sc_mru + PPP_HDRLEN + PPP_FCSLEN) 145 146 /* 147 * Does c need to be escaped? 148 */ 149 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) 150 151 /* 152 * Procedures for using an async tty interface for PPP. 153 */ 154 155 /* This is a NetBSD-1.0 or later kernel. */ 156 #define CCOUNT(q) ((q)->c_cc) 157 158 /* 159 * Line specific open routine for async tty devices. 160 * Attach the given tty to the first available ppp unit. 161 * Called from device open routine or ttioctl. 162 */ 163 int 164 pppopen(dev_t dev, struct tty *tp, struct proc *p) 165 { 166 struct ppp_softc *sc; 167 int error, s; 168 169 if ((error = suser(p, 0)) != 0) 170 return (error); 171 172 rw_enter_write(&ppp_pkt_init); 173 if (ppp_pkts.pr_size == 0) { 174 extern struct kmem_pa_mode kp_dma_contig; 175 176 pool_init(&ppp_pkts, sizeof(struct ppp_pkt), 0, 177 IPL_TTY, 0, "ppppkts", NULL); /* IPL_SOFTTTY */ 178 pool_set_constraints(&ppp_pkts, &kp_dma_contig); 179 } 180 rw_exit_write(&ppp_pkt_init); 181 182 s = spltty(); 183 184 if (tp->t_line == PPPDISC) { 185 sc = (struct ppp_softc *) tp->t_sc; 186 if (sc != NULL && sc->sc_devp == (void *) tp) { 187 splx(s); 188 return (0); 189 } 190 } 191 192 if ((sc = pppalloc(p->p_p->ps_pid)) == NULL) { 193 splx(s); 194 return ENXIO; 195 } 196 197 if (sc->sc_relinq) 198 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ 199 200 timeout_set(&sc->sc_timo, ppp_timeout, sc); 201 sc->sc_ilen = 0; 202 sc->sc_pkt = NULL; 203 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 204 sc->sc_asyncmap[0] = 0xffffffff; 205 sc->sc_asyncmap[3] = 0x60000000; 206 sc->sc_rasyncmap = 0; 207 sc->sc_devp = (void *) tp; 208 sc->sc_start = pppasyncstart; 209 sc->sc_ctlp = pppasyncctlp; 210 sc->sc_relinq = pppasyncrelinq; 211 sc->sc_outm = NULL; 212 ppppkt(sc); 213 sc->sc_if.if_flags |= IFF_RUNNING; 214 sc->sc_if.if_baudrate = tp->t_ospeed; 215 216 tp->t_sc = (caddr_t) sc; 217 ttyflush(tp, FREAD | FWRITE); 218 219 splx(s); 220 return (0); 221 } 222 223 /* 224 * Line specific close routine, called from device close routine 225 * and from ttioctl. 226 * Detach the tty from the ppp unit. 227 * Mimics part of ttyclose(). 228 */ 229 int 230 pppclose(struct tty *tp, int flag, struct proc *p) 231 { 232 struct ppp_softc *sc; 233 int s; 234 235 s = spltty(); 236 ttyflush(tp, FREAD|FWRITE); 237 tp->t_line = 0; 238 sc = (struct ppp_softc *) tp->t_sc; 239 if (sc != NULL) { 240 tp->t_sc = NULL; 241 if (tp == (struct tty *) sc->sc_devp) { 242 pppasyncrelinq(sc); 243 pppdealloc(sc); 244 } 245 } 246 splx(s); 247 return 0; 248 } 249 250 /* 251 * Relinquish the interface unit to another device. 252 */ 253 void 254 pppasyncrelinq(struct ppp_softc *sc) 255 { 256 int s; 257 258 s = spltty(); 259 m_freem(sc->sc_outm); 260 sc->sc_outm = NULL; 261 262 if (sc->sc_pkt != NULL) { 263 ppp_pkt_free(sc->sc_pkt); 264 sc->sc_pkt = sc->sc_pktc = NULL; 265 } 266 if (sc->sc_flags & SC_TIMEOUT) { 267 timeout_del(&sc->sc_timo); 268 sc->sc_flags &= ~SC_TIMEOUT; 269 } 270 splx(s); 271 } 272 273 /* 274 * Line specific (tty) read routine. 275 */ 276 int 277 pppread(struct tty *tp, struct uio *uio, int flag) 278 { 279 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 280 struct mbuf *m, *m0; 281 int s; 282 int error = 0; 283 284 if (sc == NULL) 285 return 0; 286 /* 287 * Loop waiting for input, checking that nothing disasterous 288 * happens in the meantime. 289 */ 290 s = spltty(); 291 for (;;) { 292 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) { 293 splx(s); 294 return 0; 295 } 296 /* Get the packet from the input queue */ 297 m0 = mq_dequeue(&sc->sc_inq); 298 if (m0 != 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 splx(s); 319 320 for (m = m0; m && uio->uio_resid; m = m->m_next) 321 if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0) 322 break; 323 m_freem(m0); 324 return (error); 325 } 326 327 /* 328 * Line specific (tty) write routine. 329 */ 330 int 331 pppwrite(struct tty *tp, struct uio *uio, int flag) 332 { 333 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 334 struct mbuf *m, *m0, **mp; 335 struct sockaddr dst; 336 u_int len; 337 int error; 338 339 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 340 return 0; /* wrote 0 bytes */ 341 if (tp->t_line != PPPDISC) 342 return (EINVAL); 343 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 344 return EIO; 345 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || 346 uio->uio_resid < PPP_HDRLEN) 347 return (EMSGSIZE); 348 for (mp = &m0; uio->uio_resid; mp = &m->m_next) { 349 if (mp == &m0) { 350 MGETHDR(m, M_WAIT, MT_DATA); 351 m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN; 352 m->m_pkthdr.ph_ifidx = 0; 353 } else 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, NULL); 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 int 381 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p) 382 { 383 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 384 int error, s; 385 386 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 387 return -1; 388 389 error = 0; 390 switch (cmd) { 391 case PPPIOCSASYNCMAP: 392 if ((error = suser(p, 0)) != 0) 393 break; 394 sc->sc_asyncmap[0] = *(u_int *)data; 395 break; 396 397 case PPPIOCGASYNCMAP: 398 *(u_int *)data = sc->sc_asyncmap[0]; 399 break; 400 401 case PPPIOCSRASYNCMAP: 402 if ((error = suser(p, 0)) != 0) 403 break; 404 sc->sc_rasyncmap = *(u_int *)data; 405 break; 406 407 case PPPIOCGRASYNCMAP: 408 *(u_int *)data = sc->sc_rasyncmap; 409 break; 410 411 case PPPIOCSXASYNCMAP: 412 if ((error = suser(p, 0)) != 0) 413 break; 414 s = spltty(); 415 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 416 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ 417 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ 418 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ 419 splx(s); 420 break; 421 422 case PPPIOCGXASYNCMAP: 423 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); 424 break; 425 426 default: 427 error = pppioctl(sc, cmd, data, flag, p); 428 if (error == 0 && cmd == PPPIOCSMRU) 429 ppppkt(sc); 430 } 431 432 return error; 433 } 434 435 /* 436 * FCS lookup table as calculated by genfcstab. 437 */ 438 static u_int16_t fcstab[256] = { 439 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 440 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 441 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 442 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 443 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 444 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 445 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 446 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 447 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 448 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 449 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 450 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 451 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 452 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 453 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 454 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 455 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 456 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 457 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 458 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 459 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 460 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 461 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 462 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 463 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 464 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 465 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 466 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 467 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 468 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 469 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 470 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 471 }; 472 473 /* 474 * Calculate a new FCS given the current FCS and the new data. 475 */ 476 u_int16_t 477 pppfcs(u_int16_t fcs, u_char *cp, int len) 478 { 479 while (len--) 480 fcs = PPP_FCS(fcs, *cp++); 481 return (fcs); 482 } 483 484 /* 485 * This gets called from pppoutput when a new packet is 486 * put on a queue, at splsoftnet. 487 */ 488 void 489 pppasyncstart(struct ppp_softc *sc) 490 { 491 struct tty *tp = (struct tty *) sc->sc_devp; 492 struct mbuf *m; 493 int len; 494 u_char *start, *stop, *cp; 495 int n, ndone, done, idle; 496 struct mbuf *m2; 497 int s; 498 499 idle = 0; 500 while (CCOUNT(&tp->t_outq) < tp->t_hiwat) { 501 /* 502 * See if we have an existing packet partly sent. 503 * If not, get a new packet and start sending it. 504 */ 505 m = sc->sc_outm; 506 if (m == NULL) { 507 /* 508 * Get another packet to be sent. 509 */ 510 m = ppp_dequeue(sc); 511 if (m == NULL) { 512 idle = 1; 513 break; 514 } 515 516 /* 517 * The extra PPP_FLAG will start up a new packet, and thus 518 * will flush any accumulated garbage. We do this whenever 519 * the line may have been idle for some time. 520 */ 521 if (CCOUNT(&tp->t_outq) == 0) { 522 ++sc->sc_stats.ppp_obytes; 523 (void) putc(PPP_FLAG, &tp->t_outq); 524 } 525 526 /* Calculate the FCS for the first mbuf's worth. */ 527 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); 528 } 529 530 for (;;) { 531 start = mtod(m, u_char *); 532 len = m->m_len; 533 stop = start + len; 534 while (len > 0) { 535 /* 536 * Find out how many bytes in the string we can 537 * handle without doing something special. 538 */ 539 for (cp = start; cp < stop; cp++) 540 if (ESCAPE_P(*cp)) 541 break; 542 n = cp - start; 543 if (n) { 544 /* NetBSD (0.9 or later), 4.3-Reno or similar. */ 545 ndone = n - b_to_q(start, n, &tp->t_outq); 546 len -= ndone; 547 start += ndone; 548 sc->sc_stats.ppp_obytes += ndone; 549 550 if (ndone < n) 551 break; /* packet doesn't fit */ 552 } 553 /* 554 * If there are characters left in the mbuf, 555 * the first one must be special. 556 * Put it out in a different form. 557 */ 558 if (len) { 559 s = spltty(); 560 if (putc(PPP_ESCAPE, &tp->t_outq)) { 561 splx(s); 562 break; 563 } 564 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { 565 (void) unputc(&tp->t_outq); 566 splx(s); 567 break; 568 } 569 splx(s); 570 sc->sc_stats.ppp_obytes += 2; 571 start++; 572 len--; 573 } 574 } 575 576 /* 577 * If we didn't empty this mbuf, remember where we're up to. 578 * If we emptied the last mbuf, try to add the FCS and closing 579 * flag, and if we can't, leave sc_outm pointing to m, but with 580 * m->m_len == 0, to remind us to output the FCS and flag later. 581 */ 582 done = len == 0; 583 if (done && m->m_next == NULL) { 584 u_char *p, *q; 585 int c; 586 u_char endseq[8]; 587 588 /* 589 * We may have to escape the bytes in the FCS. 590 */ 591 p = endseq; 592 c = ~sc->sc_outfcs & 0xFF; 593 if (ESCAPE_P(c)) { 594 *p++ = PPP_ESCAPE; 595 *p++ = c ^ PPP_TRANS; 596 } else 597 *p++ = c; 598 c = (~sc->sc_outfcs >> 8) & 0xFF; 599 if (ESCAPE_P(c)) { 600 *p++ = PPP_ESCAPE; 601 *p++ = c ^ PPP_TRANS; 602 } else 603 *p++ = c; 604 *p++ = PPP_FLAG; 605 606 /* 607 * Try to output the FCS and flag. If the bytes 608 * don't all fit, back out. 609 */ 610 s = spltty(); 611 for (q = endseq; q < p; ++q) 612 if (putc(*q, &tp->t_outq)) { 613 done = 0; 614 for (; q > endseq; --q) 615 unputc(&tp->t_outq); 616 break; 617 } 618 splx(s); 619 if (done) 620 sc->sc_stats.ppp_obytes += q - endseq; 621 } 622 623 if (!done) { 624 /* remember where we got to */ 625 m->m_data = start; 626 m->m_len = len; 627 break; 628 } 629 630 /* Finished with this mbuf; free it and move on. */ 631 m2 = m_free(m); 632 m = m2; 633 if (m == NULL) { 634 /* Finished a packet */ 635 break; 636 } 637 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); 638 } 639 640 /* 641 * If m == NULL, we have finished a packet. 642 * If m != NULL, we've either done as much work this time 643 * as we need to, or else we've filled up the output queue. 644 */ 645 sc->sc_outm = m; 646 if (m) 647 break; 648 } 649 650 /* Call pppstart to start output again if necessary. */ 651 s = spltty(); 652 pppstart_internal(tp, 0); 653 654 /* 655 * This timeout is needed for operation on a pseudo-tty, 656 * because the pty code doesn't call pppstart after it has 657 * drained the t_outq. 658 */ 659 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) { 660 timeout_add(&sc->sc_timo, 1); 661 sc->sc_flags |= SC_TIMEOUT; 662 } 663 664 splx(s); 665 } 666 667 /* 668 * This gets called when a received packet is placed on 669 * the inq, at splsoftnet. 670 */ 671 void 672 pppasyncctlp(struct ppp_softc *sc) 673 { 674 struct tty *tp; 675 int s; 676 677 /* Put a placeholder byte in canq for ttpoll()/ttnread(). */ 678 s = spltty(); 679 tp = (struct tty *) sc->sc_devp; 680 putc(0, &tp->t_canq); 681 ttwakeup(tp); 682 splx(s); 683 } 684 685 /* 686 * Start output on async tty interface. If the transmit queue 687 * has drained sufficiently, arrange for pppasyncstart to be 688 * called later at splsoftnet. 689 */ 690 int 691 pppstart_internal(struct tty *tp, int force) 692 { 693 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 694 695 /* 696 * If there is stuff in the output queue, send it now. 697 * We are being called in lieu of ttstart and must do what it would. 698 */ 699 if (tp->t_oproc != NULL) 700 (*tp->t_oproc)(tp); 701 702 /* 703 * If the transmit queue has drained and the tty has not hung up 704 * or been disconnected from the ppp unit, then tell if_ppp.c that 705 * we need more output. 706 */ 707 if ((CCOUNT(&tp->t_outq) < tp->t_lowat || force) 708 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 709 && sc != NULL && tp == (struct tty *) sc->sc_devp) { 710 ppp_restart(sc); 711 } 712 713 return 0; 714 } 715 716 int 717 pppstart(struct tty *tp) 718 { 719 return pppstart_internal(tp, 0); 720 } 721 722 /* 723 * Timeout routine - try to start some more output. 724 */ 725 void 726 ppp_timeout(void *x) 727 { 728 struct ppp_softc *sc = (struct ppp_softc *) x; 729 struct tty *tp = (struct tty *) sc->sc_devp; 730 int s; 731 732 s = spltty(); 733 sc->sc_flags &= ~SC_TIMEOUT; 734 pppstart_internal(tp, 1); 735 splx(s); 736 } 737 738 /* 739 * Allocate enough mbuf to handle current MRU. 740 */ 741 void 742 ppppkt(struct ppp_softc *sc) 743 { 744 struct ppp_pkt **pktp, *pkt; 745 int len; 746 int s; 747 748 s = spltty(); 749 pktp = &sc->sc_pkt; 750 for (len = PKT_MAXLEN(sc); len > 0; len -= sizeof(pkt->p_buf)) { 751 pkt = *pktp; 752 if (pkt == NULL) { 753 pkt = pool_get(&ppp_pkts, PR_NOWAIT); 754 if (pkt == NULL) 755 break; 756 PKT_NEXT(pkt) = NULL; 757 PKT_PREV(pkt) = *pktp; 758 PKT_LEN(pkt) = 0; 759 *pktp = pkt; 760 } 761 pktp = &PKT_NEXT(pkt); 762 } 763 splx(s); 764 } 765 766 void 767 ppp_pkt_free(struct ppp_pkt *pkt) 768 { 769 struct ppp_pkt *next; 770 771 while (pkt != NULL) { 772 next = PKT_NEXT(pkt); 773 pool_put(&ppp_pkts, pkt); 774 pkt = next; 775 } 776 } 777 778 /* 779 * tty interface receiver interrupt. 780 */ 781 static unsigned int paritytab[8] = { 782 0x96696996, 0x69969669, 0x69969669, 0x96696996, 783 0x69969669, 0x96696996, 0x96696996, 0x69969669 784 }; 785 786 int 787 pppinput(int c, struct tty *tp) 788 { 789 struct ppp_softc *sc; 790 struct ppp_pkt *pkt; 791 int ilen, s; 792 793 sc = (struct ppp_softc *) tp->t_sc; 794 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 795 return 0; 796 797 ++tk_nin; 798 ++sc->sc_stats.ppp_ibytes; 799 800 if (c & TTY_FE) { 801 /* framing error or overrun on this char - abort packet */ 802 if (sc->sc_flags & SC_DEBUG) 803 printf("%s: bad char %x\n", sc->sc_if.if_xname, c); 804 goto flush; 805 } 806 807 c &= 0xff; 808 809 /* 810 * Handle software flow control of output. 811 */ 812 if (tp->t_iflag & IXON) { 813 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 814 if ((tp->t_state & TS_TTSTOP) == 0) { 815 tp->t_state |= TS_TTSTOP; 816 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 817 } 818 return 0; 819 } 820 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { 821 tp->t_state &= ~TS_TTSTOP; 822 if (tp->t_oproc != NULL) 823 (*tp->t_oproc)(tp); 824 return 0; 825 } 826 } 827 828 s = spltty(); 829 if (c & 0x80) 830 sc->sc_flags |= SC_RCV_B7_1; 831 else 832 sc->sc_flags |= SC_RCV_B7_0; 833 if (paritytab[c >> 5] & (1 << (c & 0x1F))) 834 sc->sc_flags |= SC_RCV_ODDP; 835 else 836 sc->sc_flags |= SC_RCV_EVNP; 837 splx(s); 838 839 if (sc->sc_flags & SC_LOG_RAWIN) 840 ppplogchar(sc, c); 841 842 if (c == PPP_FLAG) { 843 ilen = sc->sc_ilen; 844 sc->sc_ilen = 0; 845 846 if (sc->sc_rawin_count > 0) 847 ppplogchar(sc, -1); 848 849 /* 850 * If SC_ESCAPED is set, then we've seen the packet 851 * abort sequence "}~". 852 */ 853 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) 854 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { 855 s = spltty(); 856 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ 857 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ 858 if (sc->sc_flags & SC_DEBUG) 859 printf("%s: bad fcs %x\n", sc->sc_if.if_xname, 860 sc->sc_fcs); 861 sc->sc_if.if_ierrors++; 862 sc->sc_stats.ppp_ierrors++; 863 } else 864 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); 865 splx(s); 866 return 0; 867 } 868 869 if (ilen < PPP_HDRLEN + PPP_FCSLEN) { 870 if (ilen) { 871 if (sc->sc_flags & SC_DEBUG) 872 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen); 873 s = spltty(); 874 sc->sc_if.if_ierrors++; 875 sc->sc_stats.ppp_ierrors++; 876 sc->sc_flags |= SC_PKTLOST; 877 splx(s); 878 } 879 return 0; 880 } 881 882 /* 883 * Remove FCS trailer. 884 */ 885 ilen -= 2; 886 pkt = sc->sc_pktc; 887 if (--PKT_LEN(pkt) == 0) { 888 pkt = PKT_PREV(pkt); 889 sc->sc_pktc = pkt; 890 } 891 PKT_LEN(pkt)--; 892 893 /* excise this mbuf chain */ 894 pkt = sc->sc_pkt; 895 sc->sc_pkt = sc->sc_pktc = PKT_NEXT(sc->sc_pktc); 896 PKT_NEXT(pkt) = NULL; 897 898 ppppktin(sc, pkt, sc->sc_flags & SC_PKTLOST); 899 if (sc->sc_flags & SC_PKTLOST) { 900 s = spltty(); 901 sc->sc_flags &= ~SC_PKTLOST; 902 splx(s); 903 } 904 905 ppppkt(sc); 906 return 0; 907 } 908 909 if (sc->sc_flags & SC_FLUSH) { 910 if (sc->sc_flags & SC_LOG_FLUSH) 911 ppplogchar(sc, c); 912 return 0; 913 } 914 915 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 916 return 0; 917 918 s = spltty(); 919 if (sc->sc_flags & SC_ESCAPED) { 920 sc->sc_flags &= ~SC_ESCAPED; 921 c ^= PPP_TRANS; 922 } else if (c == PPP_ESCAPE) { 923 sc->sc_flags |= SC_ESCAPED; 924 splx(s); 925 return 0; 926 } 927 splx(s); 928 929 /* 930 * Initialize buffer on first octet received. 931 * First octet could be address or protocol (when compressing 932 * address/control). 933 * Second octet is control. 934 * Third octet is first or second (when compressing protocol) 935 * octet of protocol. 936 * Fourth octet is second octet of protocol. 937 */ 938 if (sc->sc_ilen == 0) { 939 /* reset the first input mbuf */ 940 if (sc->sc_pkt == NULL) { 941 ppppkt(sc); 942 if (sc->sc_pkt == NULL) { 943 if (sc->sc_flags & SC_DEBUG) 944 printf("%s: no input mbufs!\n", sc->sc_if.if_xname); 945 goto flush; 946 } 947 } 948 pkt = sc->sc_pkt; 949 PKT_LEN(pkt) = 0; 950 sc->sc_pktc = pkt; 951 sc->sc_pktp = pkt->p_buf; 952 sc->sc_fcs = PPP_INITFCS; 953 if (c != PPP_ALLSTATIONS) { 954 if (sc->sc_flags & SC_REJ_COMP_AC) { 955 if (sc->sc_flags & SC_DEBUG) 956 printf("%s: garbage received: 0x%x (need 0xFF)\n", 957 sc->sc_if.if_xname, c); 958 goto flush; 959 } 960 *sc->sc_pktp++ = PPP_ALLSTATIONS; 961 *sc->sc_pktp++ = PPP_UI; 962 sc->sc_ilen += 2; 963 PKT_LEN(pkt) += 2; 964 } 965 } 966 if (sc->sc_ilen == 1 && c != PPP_UI) { 967 if (sc->sc_flags & SC_DEBUG) 968 printf("%s: missing UI (0x3), got 0x%x\n", 969 sc->sc_if.if_xname, c); 970 goto flush; 971 } 972 if (sc->sc_ilen == 2 && (c & 1) == 1) { 973 /* a compressed protocol */ 974 *sc->sc_pktp++ = 0; 975 sc->sc_ilen++; 976 PKT_LEN(sc->sc_pktc)++; 977 } 978 if (sc->sc_ilen == 3 && (c & 1) == 0) { 979 if (sc->sc_flags & SC_DEBUG) 980 printf("%s: bad protocol %x\n", sc->sc_if.if_xname, 981 (sc->sc_pktp[-1] << 8) + c); 982 goto flush; 983 } 984 985 /* packet beyond configured mru? */ 986 if (++sc->sc_ilen > PKT_MAXLEN(sc)) { 987 if (sc->sc_flags & SC_DEBUG) 988 printf("%s: packet too big\n", sc->sc_if.if_xname); 989 goto flush; 990 } 991 992 /* is this packet full? */ 993 pkt = sc->sc_pktc; 994 if (PKT_LEN(pkt) >= sizeof(pkt->p_buf)) { 995 if (PKT_NEXT(pkt) == NULL) { 996 ppppkt(sc); 997 if (PKT_NEXT(pkt) == NULL) { 998 if (sc->sc_flags & SC_DEBUG) 999 printf("%s: too few input packets!\n", sc->sc_if.if_xname); 1000 goto flush; 1001 } 1002 } 1003 sc->sc_pktc = pkt = PKT_NEXT(pkt); 1004 PKT_LEN(pkt) = 0; 1005 sc->sc_pktp = pkt->p_buf; 1006 } 1007 1008 ++PKT_LEN(pkt); 1009 *sc->sc_pktp++ = c; 1010 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1011 return 0; 1012 1013 flush: 1014 if (!(sc->sc_flags & SC_FLUSH)) { 1015 s = spltty(); 1016 sc->sc_if.if_ierrors++; 1017 sc->sc_stats.ppp_ierrors++; 1018 sc->sc_flags |= SC_FLUSH; 1019 splx(s); 1020 if (sc->sc_flags & SC_LOG_FLUSH) 1021 ppplogchar(sc, c); 1022 } 1023 return 0; 1024 } 1025 1026 #define MAX_DUMP_BYTES 128 1027 1028 void 1029 ppplogchar(struct ppp_softc *sc, int c) 1030 { 1031 if (c >= 0) 1032 sc->sc_rawin[sc->sc_rawin_count++] = c; 1033 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) 1034 || (c < 0 && sc->sc_rawin_count > 0)) { 1035 printf("%s input: ", sc->sc_if.if_xname); 1036 pppdumpb(sc->sc_rawin, sc->sc_rawin_count); 1037 sc->sc_rawin_count = 0; 1038 } 1039 } 1040 1041 void 1042 pppdumpb(u_char *b, int l) 1043 { 1044 char buf[3*MAX_DUMP_BYTES+4]; 1045 char *bp = buf; 1046 static char digits[] = "0123456789abcdef"; 1047 1048 while (l--) { 1049 if (bp >= buf + sizeof(buf) - 3) { 1050 *bp++ = '>'; 1051 break; 1052 } 1053 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1054 *bp++ = digits[*b++ & 0xf]; 1055 *bp++ = ' '; 1056 } 1057 1058 *bp = 0; 1059 printf("%s\n", buf); 1060 } 1061 1062 #endif /* NPPP > 0 */ 1063