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