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