1 /* $OpenBSD: ppp_tty.c,v 1.32 2015/04/10 13:58:20 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 114 #include <net/if.h> 115 #include <net/if_var.h> 116 #include <net/if_types.h> 117 118 #ifdef VJC 119 #include <netinet/in.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_t dev, struct tty *tp) 183 { 184 struct proc *p = curproc; /* XXX */ 185 struct ppp_softc *sc; 186 int error, s; 187 188 if ((error = suser(p, 0)) != 0) 189 return (error); 190 191 s = spltty(); 192 193 if (tp->t_line == PPPDISC) { 194 sc = (struct ppp_softc *) tp->t_sc; 195 if (sc != NULL && sc->sc_devp == (void *) tp) { 196 splx(s); 197 return (0); 198 } 199 } 200 201 if ((sc = pppalloc(p->p_p->ps_pid)) == NULL) { 202 splx(s); 203 return ENXIO; 204 } 205 206 if (sc->sc_relinq) 207 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ 208 209 timeout_set(&sc->sc_timo, ppp_timeout, sc); 210 sc->sc_ilen = 0; 211 sc->sc_m = NULL; 212 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 213 sc->sc_asyncmap[0] = 0xffffffff; 214 sc->sc_asyncmap[3] = 0x60000000; 215 sc->sc_rasyncmap = 0; 216 sc->sc_devp = (void *) tp; 217 sc->sc_start = pppasyncstart; 218 sc->sc_ctlp = pppasyncctlp; 219 sc->sc_relinq = pppasyncrelinq; 220 sc->sc_outm = NULL; 221 pppgetm(sc); 222 sc->sc_if.if_flags |= IFF_RUNNING; 223 sc->sc_if.if_baudrate = tp->t_ospeed; 224 225 tp->t_sc = (caddr_t) sc; 226 ttyflush(tp, FREAD | FWRITE); 227 228 splx(s); 229 return (0); 230 } 231 232 /* 233 * Line specific close routine, called from device close routine 234 * and from ttioctl. 235 * Detach the tty from the ppp unit. 236 * Mimics part of ttyclose(). 237 */ 238 int 239 pppclose(struct tty *tp, int flag) 240 { 241 struct ppp_softc *sc; 242 int s; 243 244 s = spltty(); 245 ttyflush(tp, FREAD|FWRITE); 246 tp->t_line = 0; 247 sc = (struct ppp_softc *) tp->t_sc; 248 if (sc != NULL) { 249 tp->t_sc = NULL; 250 if (tp == (struct tty *) sc->sc_devp) { 251 pppasyncrelinq(sc); 252 pppdealloc(sc); 253 } 254 } 255 splx(s); 256 return 0; 257 } 258 259 /* 260 * Relinquish the interface unit to another device. 261 */ 262 void 263 pppasyncrelinq(struct ppp_softc *sc) 264 { 265 int s; 266 267 s = spltty(); 268 if (sc->sc_outm) { 269 m_freem(sc->sc_outm); 270 sc->sc_outm = NULL; 271 } 272 if (sc->sc_m) { 273 m_freem(sc->sc_m); 274 sc->sc_m = NULL; 275 } 276 if (sc->sc_flags & SC_TIMEOUT) { 277 timeout_del(&sc->sc_timo); 278 sc->sc_flags &= ~SC_TIMEOUT; 279 } 280 splx(s); 281 } 282 283 /* 284 * Line specific (tty) read routine. 285 */ 286 int 287 pppread(struct tty *tp, struct uio *uio, int flag) 288 { 289 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 290 struct mbuf *m, *m0; 291 int s; 292 int error = 0; 293 294 if (sc == NULL) 295 return 0; 296 /* 297 * Loop waiting for input, checking that nothing disasterous 298 * happens in the meantime. 299 */ 300 s = spltty(); 301 for (;;) { 302 if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) { 303 splx(s); 304 return 0; 305 } 306 /* Get the packet from the input queue */ 307 m0 = mq_dequeue(&sc->sc_inq); 308 if (m0 != NULL) 309 break; 310 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0 311 && (tp->t_state & TS_ISOPEN)) { 312 splx(s); 313 return 0; /* end of file */ 314 } 315 if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { 316 splx(s); 317 return (EWOULDBLOCK); 318 } 319 error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0); 320 if (error) { 321 splx(s); 322 return error; 323 } 324 } 325 326 /* Pull place-holder byte out of canonical queue */ 327 getc(&tp->t_canq); 328 splx(s); 329 330 for (m = m0; m && uio->uio_resid; m = m->m_next) 331 if ((error = uiomovei(mtod(m, u_char *), m->m_len, uio)) != 0) 332 break; 333 m_freem(m0); 334 return (error); 335 } 336 337 /* 338 * Line specific (tty) write routine. 339 */ 340 int 341 pppwrite(struct tty *tp, struct uio *uio, int flag) 342 { 343 struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; 344 struct mbuf *m, *m0, **mp; 345 struct sockaddr dst; 346 int len, error; 347 348 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 349 return 0; /* wrote 0 bytes */ 350 if (tp->t_line != PPPDISC) 351 return (EINVAL); 352 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 353 return EIO; 354 if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || 355 uio->uio_resid < PPP_HDRLEN) 356 return (EMSGSIZE); 357 for (mp = &m0; uio->uio_resid; mp = &m->m_next) { 358 if (mp == &m0) { 359 MGETHDR(m, M_WAIT, MT_DATA); 360 m->m_pkthdr.len = uio->uio_resid - PPP_HDRLEN; 361 m->m_pkthdr.rcvif = NULL; 362 } else 363 MGET(m, M_WAIT, MT_DATA); 364 *mp = m; 365 m->m_len = 0; 366 if (uio->uio_resid >= MCLBYTES / 2) 367 MCLGET(m, M_DONTWAIT); 368 len = M_TRAILINGSPACE(m); 369 if (len > uio->uio_resid) 370 len = uio->uio_resid; 371 if ((error = uiomovei(mtod(m, u_char *), len, uio)) != 0) { 372 m_freem(m0); 373 return (error); 374 } 375 m->m_len = len; 376 } 377 dst.sa_family = AF_UNSPEC; 378 bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); 379 m0->m_data += PPP_HDRLEN; 380 m0->m_len -= PPP_HDRLEN; 381 return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0)); 382 } 383 384 /* 385 * Line specific (tty) ioctl routine. 386 * This discipline requires that tty device drivers call 387 * the line specific l_ioctl routine from their ioctl routines. 388 */ 389 /* ARGSUSED */ 390 int 391 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p) 392 { 393 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 394 int error, s; 395 396 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 397 return -1; 398 399 error = 0; 400 switch (cmd) { 401 case PPPIOCSASYNCMAP: 402 if ((error = suser(p, 0)) != 0) 403 break; 404 sc->sc_asyncmap[0] = *(u_int *)data; 405 break; 406 407 case PPPIOCGASYNCMAP: 408 *(u_int *)data = sc->sc_asyncmap[0]; 409 break; 410 411 case PPPIOCSRASYNCMAP: 412 if ((error = suser(p, 0)) != 0) 413 break; 414 sc->sc_rasyncmap = *(u_int *)data; 415 break; 416 417 case PPPIOCGRASYNCMAP: 418 *(u_int *)data = sc->sc_rasyncmap; 419 break; 420 421 case PPPIOCSXASYNCMAP: 422 if ((error = suser(p, 0)) != 0) 423 break; 424 s = spltty(); 425 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); 426 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ 427 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ 428 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ 429 splx(s); 430 break; 431 432 case PPPIOCGXASYNCMAP: 433 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); 434 break; 435 436 default: 437 error = pppioctl(sc, cmd, data, flag, p); 438 if (error == 0 && cmd == PPPIOCSMRU) 439 pppgetm(sc); 440 } 441 442 return error; 443 } 444 445 /* 446 * FCS lookup table as calculated by genfcstab. 447 */ 448 static u_int16_t fcstab[256] = { 449 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 450 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 451 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 452 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 453 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 454 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 455 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 456 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 457 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 458 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 459 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 460 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 461 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 462 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 463 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 464 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 465 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 466 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 467 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 468 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 469 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 470 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 471 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 472 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 473 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 474 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 475 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 476 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 477 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 478 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 479 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 480 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 481 }; 482 483 /* 484 * Calculate a new FCS given the current FCS and the new data. 485 */ 486 u_int16_t 487 pppfcs(u_int16_t fcs, u_char *cp, int len) 488 { 489 while (len--) 490 fcs = PPP_FCS(fcs, *cp++); 491 return (fcs); 492 } 493 494 /* 495 * This gets called from pppoutput when a new packet is 496 * put on a queue, at splsoftnet. 497 */ 498 void 499 pppasyncstart(struct ppp_softc *sc) 500 { 501 struct tty *tp = (struct tty *) sc->sc_devp; 502 struct mbuf *m; 503 int len; 504 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(struct ppp_softc *sc) 683 { 684 struct tty *tp; 685 int s; 686 687 /* Put a placeholder byte in canq for ttpoll()/ttnread(). */ 688 s = spltty(); 689 tp = (struct tty *) sc->sc_devp; 690 putc(0, &tp->t_canq); 691 ttwakeup(tp); 692 splx(s); 693 } 694 695 /* 696 * Start output on async tty interface. If the transmit queue 697 * has drained sufficiently, arrange for pppasyncstart to be 698 * called later at splsoftnet. 699 */ 700 int 701 pppstart(struct tty *tp, int force) 702 { 703 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; 704 705 /* 706 * If there is stuff in the output queue, send it now. 707 * We are being called in lieu of ttstart and must do what it would. 708 */ 709 if (tp->t_oproc != NULL) 710 (*tp->t_oproc)(tp); 711 712 /* 713 * If the transmit queue has drained and the tty has not hung up 714 * or been disconnected from the ppp unit, then tell if_ppp.c that 715 * we need more output. 716 */ 717 if ((CCOUNT(&tp->t_outq) < PPP_LOWAT || force) 718 && !((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 719 && sc != NULL && tp == (struct tty *) sc->sc_devp) { 720 ppp_restart(sc); 721 } 722 723 return 0; 724 } 725 726 /* 727 * Timeout routine - try to start some more output. 728 */ 729 void 730 ppp_timeout(void *x) 731 { 732 struct ppp_softc *sc = (struct ppp_softc *) x; 733 struct tty *tp = (struct tty *) sc->sc_devp; 734 int s; 735 736 s = spltty(); 737 sc->sc_flags &= ~SC_TIMEOUT; 738 pppstart(tp, 1); 739 splx(s); 740 } 741 742 /* 743 * Allocate enough mbuf to handle current MRU. 744 */ 745 void 746 pppgetm(struct ppp_softc *sc) 747 { 748 struct mbuf *m, **mp; 749 int len; 750 int s; 751 752 s = spltty(); 753 mp = &sc->sc_m; 754 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ 755 if ((m = *mp) == NULL) { 756 MGETHDR(m, M_DONTWAIT, MT_DATA); 757 if (m == NULL) 758 break; 759 *mp = m; 760 MCLGET(m, M_DONTWAIT); 761 } 762 len -= M_DATASIZE(m); 763 mp = &m->m_next; 764 } 765 splx(s); 766 } 767 768 /* 769 * tty interface receiver interrupt. 770 */ 771 static unsigned int paritytab[8] = { 772 0x96696996, 0x69969669, 0x69969669, 0x96696996, 773 0x69969669, 0x96696996, 0x96696996, 0x69969669 774 }; 775 776 int 777 pppinput(int c, struct tty *tp) 778 { 779 struct ppp_softc *sc; 780 struct mbuf *m; 781 int ilen, s; 782 783 sc = (struct ppp_softc *) tp->t_sc; 784 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 785 return 0; 786 787 ++tk_nin; 788 ++sc->sc_stats.ppp_ibytes; 789 790 if (c & TTY_FE) { 791 /* framing error or overrun on this char - abort packet */ 792 if (sc->sc_flags & SC_DEBUG) 793 printf("%s: bad char %x\n", sc->sc_if.if_xname, c); 794 goto flush; 795 } 796 797 c &= 0xff; 798 799 /* 800 * Handle software flow control of output. 801 */ 802 if (tp->t_iflag & IXON) { 803 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 804 if ((tp->t_state & TS_TTSTOP) == 0) { 805 tp->t_state |= TS_TTSTOP; 806 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 807 } 808 return 0; 809 } 810 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { 811 tp->t_state &= ~TS_TTSTOP; 812 if (tp->t_oproc != NULL) 813 (*tp->t_oproc)(tp); 814 return 0; 815 } 816 } 817 818 s = spltty(); 819 if (c & 0x80) 820 sc->sc_flags |= SC_RCV_B7_1; 821 else 822 sc->sc_flags |= SC_RCV_B7_0; 823 if (paritytab[c >> 5] & (1 << (c & 0x1F))) 824 sc->sc_flags |= SC_RCV_ODDP; 825 else 826 sc->sc_flags |= SC_RCV_EVNP; 827 splx(s); 828 829 if (sc->sc_flags & SC_LOG_RAWIN) 830 ppplogchar(sc, c); 831 832 if (c == PPP_FLAG) { 833 ilen = sc->sc_ilen; 834 sc->sc_ilen = 0; 835 836 if (sc->sc_rawin_count > 0) 837 ppplogchar(sc, -1); 838 839 /* 840 * If SC_ESCAPED is set, then we've seen the packet 841 * abort sequence "}~". 842 */ 843 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) 844 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { 845 s = spltty(); 846 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ 847 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ 848 if (sc->sc_flags & SC_DEBUG) 849 printf("%s: bad fcs %x\n", sc->sc_if.if_xname, 850 sc->sc_fcs); 851 sc->sc_if.if_ierrors++; 852 sc->sc_stats.ppp_ierrors++; 853 } else 854 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); 855 splx(s); 856 return 0; 857 } 858 859 if (ilen < PPP_HDRLEN + PPP_FCSLEN) { 860 if (ilen) { 861 if (sc->sc_flags & SC_DEBUG) 862 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen); 863 s = spltty(); 864 sc->sc_if.if_ierrors++; 865 sc->sc_stats.ppp_ierrors++; 866 sc->sc_flags |= SC_PKTLOST; 867 splx(s); 868 } 869 return 0; 870 } 871 872 /* 873 * Remove FCS trailer. Somewhat painful... 874 */ 875 ilen -= 2; 876 if (--sc->sc_mc->m_len == 0) { 877 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 878 ; 879 sc->sc_mc = m; 880 } 881 sc->sc_mc->m_len--; 882 883 /* excise this mbuf chain */ 884 m = sc->sc_m; 885 sc->sc_m = sc->sc_mc->m_next; 886 sc->sc_mc->m_next = NULL; 887 888 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); 889 if (sc->sc_flags & SC_PKTLOST) { 890 s = spltty(); 891 sc->sc_flags &= ~SC_PKTLOST; 892 splx(s); 893 } 894 895 pppgetm(sc); 896 return 0; 897 } 898 899 if (sc->sc_flags & SC_FLUSH) { 900 if (sc->sc_flags & SC_LOG_FLUSH) 901 ppplogchar(sc, c); 902 return 0; 903 } 904 905 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 906 return 0; 907 908 s = spltty(); 909 if (sc->sc_flags & SC_ESCAPED) { 910 sc->sc_flags &= ~SC_ESCAPED; 911 c ^= PPP_TRANS; 912 } else if (c == PPP_ESCAPE) { 913 sc->sc_flags |= SC_ESCAPED; 914 splx(s); 915 return 0; 916 } 917 splx(s); 918 919 /* 920 * Initialize buffer on first octet received. 921 * First octet could be address or protocol (when compressing 922 * address/control). 923 * Second octet is control. 924 * Third octet is first or second (when compressing protocol) 925 * octet of protocol. 926 * Fourth octet is second octet of protocol. 927 */ 928 if (sc->sc_ilen == 0) { 929 /* reset the first input mbuf */ 930 if (sc->sc_m == NULL) { 931 pppgetm(sc); 932 if (sc->sc_m == NULL) { 933 if (sc->sc_flags & SC_DEBUG) 934 printf("%s: no input mbufs!\n", sc->sc_if.if_xname); 935 goto flush; 936 } 937 } 938 m = sc->sc_m; 939 m->m_len = 0; 940 m->m_data = M_DATASTART(sc->sc_m); 941 sc->sc_mc = m; 942 sc->sc_mp = mtod(m, char *); 943 sc->sc_fcs = PPP_INITFCS; 944 if (c != PPP_ALLSTATIONS) { 945 if (sc->sc_flags & SC_REJ_COMP_AC) { 946 if (sc->sc_flags & SC_DEBUG) 947 printf("%s: garbage received: 0x%x (need 0xFF)\n", 948 sc->sc_if.if_xname, c); 949 goto flush; 950 } 951 *sc->sc_mp++ = PPP_ALLSTATIONS; 952 *sc->sc_mp++ = PPP_UI; 953 sc->sc_ilen += 2; 954 m->m_len += 2; 955 } 956 } 957 if (sc->sc_ilen == 1 && c != PPP_UI) { 958 if (sc->sc_flags & SC_DEBUG) 959 printf("%s: missing UI (0x3), got 0x%x\n", 960 sc->sc_if.if_xname, c); 961 goto flush; 962 } 963 if (sc->sc_ilen == 2 && (c & 1) == 1) { 964 /* a compressed protocol */ 965 *sc->sc_mp++ = 0; 966 sc->sc_ilen++; 967 sc->sc_mc->m_len++; 968 } 969 if (sc->sc_ilen == 3 && (c & 1) == 0) { 970 if (sc->sc_flags & SC_DEBUG) 971 printf("%s: bad protocol %x\n", sc->sc_if.if_xname, 972 (sc->sc_mp[-1] << 8) + c); 973 goto flush; 974 } 975 976 /* packet beyond configured mru? */ 977 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { 978 if (sc->sc_flags & SC_DEBUG) 979 printf("%s: packet too big\n", sc->sc_if.if_xname); 980 goto flush; 981 } 982 983 /* is this mbuf full? */ 984 m = sc->sc_mc; 985 if (M_TRAILINGSPACE(m) <= 0) { 986 if (m->m_next == NULL) { 987 pppgetm(sc); 988 if (m->m_next == NULL) { 989 if (sc->sc_flags & SC_DEBUG) 990 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname); 991 goto flush; 992 } 993 } 994 sc->sc_mc = m = m->m_next; 995 m->m_len = 0; 996 m->m_data = M_DATASTART(m); 997 sc->sc_mp = mtod(m, char *); 998 } 999 1000 ++m->m_len; 1001 *sc->sc_mp++ = c; 1002 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1003 return 0; 1004 1005 flush: 1006 if (!(sc->sc_flags & SC_FLUSH)) { 1007 s = spltty(); 1008 sc->sc_if.if_ierrors++; 1009 sc->sc_stats.ppp_ierrors++; 1010 sc->sc_flags |= SC_FLUSH; 1011 splx(s); 1012 if (sc->sc_flags & SC_LOG_FLUSH) 1013 ppplogchar(sc, c); 1014 } 1015 return 0; 1016 } 1017 1018 #define MAX_DUMP_BYTES 128 1019 1020 void 1021 ppplogchar(struct ppp_softc *sc, int c) 1022 { 1023 if (c >= 0) 1024 sc->sc_rawin[sc->sc_rawin_count++] = c; 1025 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) 1026 || (c < 0 && sc->sc_rawin_count > 0)) { 1027 printf("%s input: ", sc->sc_if.if_xname); 1028 pppdumpb(sc->sc_rawin, sc->sc_rawin_count); 1029 sc->sc_rawin_count = 0; 1030 } 1031 } 1032 1033 void 1034 pppdumpb(u_char *b, int l) 1035 { 1036 char buf[3*MAX_DUMP_BYTES+4]; 1037 char *bp = buf; 1038 static char digits[] = "0123456789abcdef"; 1039 1040 while (l--) { 1041 if (bp >= buf + sizeof(buf) - 3) { 1042 *bp++ = '>'; 1043 break; 1044 } 1045 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1046 *bp++ = digits[*b++ & 0xf]; 1047 *bp++ = ' '; 1048 } 1049 1050 *bp = 0; 1051 printf("%s\n", buf); 1052 } 1053 1054 #endif /* NPPP > 0 */ 1055