1 /* $NetBSD: ppp_tty.c,v 1.30 2002/03/17 19:41:11 atatat 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.30 2002/03/17 19:41:11 atatat 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 (EPASSTHROUGH); 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 #ifdef ALTQ 899 /* 900 * if ALTQ is enabled, don't invoke NETISR_PPP. 901 * pppintr() could loop without doing anything useful 902 * under rate-limiting. 903 */ 904 if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd)) 905 return 0; 906 #endif 907 if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) 908 && sc != NULL && tp == (struct tty *) sc->sc_devp) { 909 ppp_restart(sc); 910 } 911 912 return 0; 913 } 914 915 /* 916 * Timeout routine - try to start some more output. 917 */ 918 static void 919 ppp_timeout(x) 920 void *x; 921 { 922 struct ppp_softc *sc = (struct ppp_softc *) x; 923 struct tty *tp = (struct tty *) sc->sc_devp; 924 int s; 925 926 s = spltty(); 927 sc->sc_flags &= ~SC_TIMEOUT; 928 pppstart(tp); 929 splx(s); 930 } 931 932 /* 933 * Allocate enough mbuf to handle current MRU. 934 */ 935 static void 936 pppgetm(sc) 937 struct ppp_softc *sc; 938 { 939 struct mbuf *m, **mp; 940 int len; 941 942 mp = &sc->sc_m; 943 for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ 944 if ((m = *mp) == NULL) { 945 MGETHDR(m, M_DONTWAIT, MT_DATA); 946 if (m == NULL) 947 break; 948 *mp = m; 949 MCLGET(m, M_DONTWAIT); 950 } 951 len -= M_DATASIZE(m); 952 mp = &m->m_next; 953 } 954 } 955 956 /* 957 * tty interface receiver interrupt. 958 */ 959 static const unsigned paritytab[8] = { 960 0x96696996, 0x69969669, 0x69969669, 0x96696996, 961 0x69969669, 0x96696996, 0x96696996, 0x69969669 962 }; 963 964 int 965 pppinput(c, tp) 966 int c; 967 struct tty *tp; 968 { 969 struct ppp_softc *sc; 970 struct mbuf *m; 971 int ilen, s; 972 973 sc = (struct ppp_softc *) tp->t_sc; 974 if (sc == NULL || tp != (struct tty *) sc->sc_devp) 975 return 0; 976 977 ++tk_nin; 978 ++sc->sc_stats.ppp_ibytes; 979 980 if (c & TTY_FE) { 981 /* framing error or overrun on this char - abort packet */ 982 if (sc->sc_flags & SC_DEBUG) 983 printf("%s: bad char %x\n", sc->sc_if.if_xname, c); 984 goto flush; 985 } 986 987 c &= 0xff; 988 989 /* 990 * Handle software flow control of output. 991 */ 992 if (tp->t_iflag & IXON) { 993 if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 994 if ((tp->t_state & TS_TTSTOP) == 0) { 995 tp->t_state |= TS_TTSTOP; 996 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 997 } 998 return 0; 999 } 1000 if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { 1001 tp->t_state &= ~TS_TTSTOP; 1002 if (tp->t_oproc != NULL) 1003 (*tp->t_oproc)(tp); 1004 return 0; 1005 } 1006 } 1007 1008 s = spltty(); 1009 if (c & 0x80) 1010 sc->sc_flags |= SC_RCV_B7_1; 1011 else 1012 sc->sc_flags |= SC_RCV_B7_0; 1013 if (paritytab[c >> 5] & (1 << (c & 0x1F))) 1014 sc->sc_flags |= SC_RCV_ODDP; 1015 else 1016 sc->sc_flags |= SC_RCV_EVNP; 1017 splx(s); 1018 1019 if (sc->sc_flags & SC_LOG_RAWIN) 1020 ppplogchar(sc, c); 1021 1022 if (c == PPP_FLAG) { 1023 ilen = sc->sc_ilen; 1024 sc->sc_ilen = 0; 1025 1026 if (sc->sc_rawin_count > 0) 1027 ppplogchar(sc, -1); 1028 1029 /* 1030 * If SC_ESCAPED is set, then we've seen the packet 1031 * abort sequence "}~". 1032 */ 1033 if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) 1034 || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { 1035 s = spltty(); 1036 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ 1037 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ 1038 if (sc->sc_flags & SC_DEBUG) 1039 printf("%s: bad fcs %x\n", sc->sc_if.if_xname, 1040 sc->sc_fcs); 1041 sc->sc_if.if_ierrors++; 1042 sc->sc_stats.ppp_ierrors++; 1043 } else 1044 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); 1045 splx(s); 1046 return 0; 1047 } 1048 1049 if (ilen < PPP_HDRLEN + PPP_FCSLEN) { 1050 if (ilen) { 1051 if (sc->sc_flags & SC_DEBUG) 1052 printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen); 1053 s = spltty(); 1054 sc->sc_if.if_ierrors++; 1055 sc->sc_stats.ppp_ierrors++; 1056 sc->sc_flags |= SC_PKTLOST; 1057 splx(s); 1058 } 1059 return 0; 1060 } 1061 1062 /* 1063 * Remove FCS trailer. Somewhat painful... 1064 */ 1065 ilen -= 2; 1066 if (--sc->sc_mc->m_len == 0) { 1067 for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) 1068 ; 1069 sc->sc_mc = m; 1070 } 1071 sc->sc_mc->m_len--; 1072 1073 /* excise this mbuf chain */ 1074 m = sc->sc_m; 1075 sc->sc_m = sc->sc_mc->m_next; 1076 sc->sc_mc->m_next = NULL; 1077 1078 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); 1079 if (sc->sc_flags & SC_PKTLOST) { 1080 s = spltty(); 1081 sc->sc_flags &= ~SC_PKTLOST; 1082 splx(s); 1083 } 1084 1085 pppgetm(sc); 1086 return 0; 1087 } 1088 1089 if (sc->sc_flags & SC_FLUSH) { 1090 if (sc->sc_flags & SC_LOG_FLUSH) 1091 ppplogchar(sc, c); 1092 return 0; 1093 } 1094 1095 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) 1096 return 0; 1097 1098 s = spltty(); 1099 if (sc->sc_flags & SC_ESCAPED) { 1100 sc->sc_flags &= ~SC_ESCAPED; 1101 c ^= PPP_TRANS; 1102 } else if (c == PPP_ESCAPE) { 1103 sc->sc_flags |= SC_ESCAPED; 1104 splx(s); 1105 return 0; 1106 } 1107 splx(s); 1108 1109 /* 1110 * Initialize buffer on first octet received. 1111 * First octet could be address or protocol (when compressing 1112 * address/control). 1113 * Second octet is control. 1114 * Third octet is first or second (when compressing protocol) 1115 * octet of protocol. 1116 * Fourth octet is second octet of protocol. 1117 */ 1118 if (sc->sc_ilen == 0) { 1119 /* reset the first input mbuf */ 1120 if (sc->sc_m == NULL) { 1121 pppgetm(sc); 1122 if (sc->sc_m == NULL) { 1123 if (sc->sc_flags & SC_DEBUG) 1124 printf("%s: no input mbufs!\n", sc->sc_if.if_xname); 1125 goto flush; 1126 } 1127 } 1128 m = sc->sc_m; 1129 m->m_len = 0; 1130 m->m_data = M_DATASTART(sc->sc_m); 1131 sc->sc_mc = m; 1132 sc->sc_mp = mtod(m, char *); 1133 sc->sc_fcs = PPP_INITFCS; 1134 if (c != PPP_ALLSTATIONS) { 1135 if (sc->sc_flags & SC_REJ_COMP_AC) { 1136 if (sc->sc_flags & SC_DEBUG) 1137 printf("%s: garbage received: 0x%x (need 0xFF)\n", 1138 sc->sc_if.if_xname, c); 1139 goto flush; 1140 } 1141 *sc->sc_mp++ = PPP_ALLSTATIONS; 1142 *sc->sc_mp++ = PPP_UI; 1143 sc->sc_ilen += 2; 1144 m->m_len += 2; 1145 } 1146 } 1147 if (sc->sc_ilen == 1 && c != PPP_UI) { 1148 if (sc->sc_flags & SC_DEBUG) 1149 printf("%s: missing UI (0x3), got 0x%x\n", 1150 sc->sc_if.if_xname, c); 1151 goto flush; 1152 } 1153 if (sc->sc_ilen == 2 && (c & 1) == 1) { 1154 /* a compressed protocol */ 1155 *sc->sc_mp++ = 0; 1156 sc->sc_ilen++; 1157 sc->sc_mc->m_len++; 1158 } 1159 if (sc->sc_ilen == 3 && (c & 1) == 0) { 1160 if (sc->sc_flags & SC_DEBUG) 1161 printf("%s: bad protocol %x\n", sc->sc_if.if_xname, 1162 (sc->sc_mp[-1] << 8) + c); 1163 goto flush; 1164 } 1165 1166 /* packet beyond configured mru? */ 1167 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { 1168 if (sc->sc_flags & SC_DEBUG) 1169 printf("%s: packet too big\n", sc->sc_if.if_xname); 1170 goto flush; 1171 } 1172 1173 /* is this mbuf full? */ 1174 m = sc->sc_mc; 1175 if (M_TRAILINGSPACE(m) <= 0) { 1176 if (m->m_next == NULL) { 1177 pppgetm(sc); 1178 if (m->m_next == NULL) { 1179 if (sc->sc_flags & SC_DEBUG) 1180 printf("%s: too few input mbufs!\n", sc->sc_if.if_xname); 1181 goto flush; 1182 } 1183 } 1184 sc->sc_mc = m = m->m_next; 1185 m->m_len = 0; 1186 m->m_data = M_DATASTART(m); 1187 sc->sc_mp = mtod(m, char *); 1188 } 1189 1190 ++m->m_len; 1191 *sc->sc_mp++ = c; 1192 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); 1193 return 0; 1194 1195 flush: 1196 if (!(sc->sc_flags & SC_FLUSH)) { 1197 s = spltty(); 1198 sc->sc_if.if_ierrors++; 1199 sc->sc_stats.ppp_ierrors++; 1200 sc->sc_flags |= SC_FLUSH; 1201 splx(s); 1202 if (sc->sc_flags & SC_LOG_FLUSH) 1203 ppplogchar(sc, c); 1204 } 1205 return 0; 1206 } 1207 1208 #define MAX_DUMP_BYTES 128 1209 1210 static void 1211 ppplogchar(sc, c) 1212 struct ppp_softc *sc; 1213 int c; 1214 { 1215 if (c >= 0) 1216 sc->sc_rawin[sc->sc_rawin_count++] = c; 1217 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) 1218 || (c < 0 && sc->sc_rawin_count > 0)) { 1219 printf("%s input: ", sc->sc_if.if_xname); 1220 pppdumpb(sc->sc_rawin, sc->sc_rawin_count); 1221 sc->sc_rawin_count = 0; 1222 } 1223 } 1224 1225 static void 1226 pppdumpb(b, l) 1227 u_char *b; 1228 int l; 1229 { 1230 char buf[3*MAX_DUMP_BYTES+4]; 1231 char *bp = buf; 1232 static char digits[] = "0123456789abcdef"; 1233 1234 while (l--) { 1235 if (bp >= buf + sizeof(buf) - 3) { 1236 *bp++ = '>'; 1237 break; 1238 } 1239 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ 1240 *bp++ = digits[*b++ & 0xf]; 1241 *bp++ = ' '; 1242 } 1243 1244 *bp = 0; 1245 printf("%s\n", buf); 1246 } 1247 1248 static void 1249 pppdumpframe(sc, m, xmit) 1250 struct ppp_softc *sc; 1251 struct mbuf* m; 1252 int xmit; 1253 { 1254 int i,lcount,copycount,count; 1255 char lbuf[16]; 1256 char *data; 1257 1258 if (m == NULL) 1259 return; 1260 1261 for(count=m->m_len,data=mtod(m,char*);m != NULL;) { 1262 /* build a line of output */ 1263 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) { 1264 if (!count) { 1265 m = m->m_next; 1266 if (m == NULL) 1267 break; 1268 count = m->m_len; 1269 data = mtod(m,char*); 1270 } 1271 copycount = (count > sizeof(lbuf)-lcount) ? 1272 sizeof(lbuf)-lcount : count; 1273 bcopy(data,&lbuf[lcount],copycount); 1274 data += copycount; 1275 count -= copycount; 1276 } 1277 1278 /* output line (hex 1st, then ascii) */ 1279 printf("%s %s:", sc->sc_if.if_xname, 1280 xmit ? "output" : "input "); 1281 for(i=0;i<lcount;i++) 1282 printf("%02x ",(u_char)lbuf[i]); 1283 for(;i<sizeof(lbuf);i++) 1284 printf(" "); 1285 for(i=0;i<lcount;i++) 1286 printf("%c",(lbuf[i] >= 040 && 1287 lbuf[i] <= 0176) ? lbuf[i] : '.'); 1288 printf("\n"); 1289 } 1290 } 1291