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