This enables plugins called via hooks/notifiers triggered
[mpls-ppp.git] / NeXT / ppp_tty.c
blob280ba196834c9fcf71c0534e1117de725f990383
1 /* $ID: ppp_tty.c,v 1.4 1994/12/13 03:42:17 paulus Exp paulus $ */
3 /*
4 * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
5 * tty devices.
7 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
21 * 3. The name "Carnegie Mellon University" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For permission or any legal
24 * details, please contact
25 * Office of Technology Transfer
26 * Carnegie Mellon University
27 * 5000 Forbes Avenue
28 * Pittsburgh, PA 15213-3890
29 * (412) 268-4387, fax: (412) 268-7395
30 * tech-transfer@andrew.cmu.edu
32 * 4. Redistributions of any form whatsoever must retain the following
33 * acknowledgment:
34 * "This product includes software developed by Computing Services
35 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
37 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
38 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
40 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
43 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45 * Drew D. Perkins
46 * Carnegie Mellon University
47 * 4910 Forbes Ave.
48 * Pittsburgh, PA 15213
49 * (412) 268-8576
50 * ddp@andrew.cmu.edu
52 * Based on:
53 * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
55 * Copyright (c) 1987 Regents of the University of California.
56 * All rights reserved.
58 * Redistribution and use in source and binary forms are permitted
59 * provided that the above copyright notice and this paragraph are
60 * duplicated in all such forms and that any documentation,
61 * advertising materials, and other materials related to such
62 * distribution and use acknowledge that the software was developed
63 * by the University of California, Berkeley. The name of the
64 * University may not be used to endorse or promote products derived
65 * from this software without specific prior written permission.
66 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
67 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
68 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
70 * Serial Line interface
72 * Rick Adams
73 * Center for Seismic Studies
74 * 1300 N 17th Street, Suite 1450
75 * Arlington, Virginia 22209
76 * (703)276-7900
77 * rick@seismo.ARPA
78 * seismo!rick
80 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
81 * Converted to 4.3BSD Beta by Chris Torek.
82 * Other changes made at Berkeley, based in part on code by Kirk Smith.
84 * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
85 * Added VJ tcp header compression; more unified ioctls
87 * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
88 * Cleaned up a lot of the mbuf-related code to fix bugs that
89 * caused system crashes and packet corruption. Changed pppstart
90 * so that it doesn't just give up with a collision if the whole
91 * packet doesn't fit in the output ring buffer.
93 * Added priority queueing for interactive IP packets, following
94 * the model of if_sl.c, plus hooks for bpf.
95 * Paul Mackerras (paulus@cs.anu.edu.au).
97 * Rewritten for NextStep's funky kernel functions, I/O threads,
98 * and netbufs (instead of real mbufs). Also, ifnets don't install
99 * into the kernel under NS as they do under BSD. We have tried to
100 * make the code remain as similar to the NetBSD version without
101 * incurring too much hassle. This code is the merge of
102 * Philip Prindeville's <philipp@res.enst.fr>/Pete French's <pete@ohm.york.ac.uk>
103 * and Stephen Perkins' <perkins@cps.msu.edu> independent ports.
107 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
108 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:59 cgd Exp */
110 /* #include "ppp.h" */
111 #if NUM_PPP > 0
113 #define KERNEL 1
114 #define KERNEL_FEATURES 1
115 #define INET 1
117 #if NS_TARGET >= 40
118 #if NS_TARGET >= 41
119 #include <kernserv/lock.h>
120 #else
121 #include <kern/lock.h>
122 #endif /* NS_TARGET */
123 #endif /* NS_TARGET */
125 #include <sys/param.h>
126 #if NS_TARGET >= 41
127 typedef simple_lock_data_t lock_data_t; /* XXX */
128 #endif /* NS_TARGET */
129 #include <sys/proc.h>
130 #include <sys/user.h>
131 #include "netbuf.h"
132 #include <sys/socket.h>
133 #include <sys/ioctl.h>
134 #include <sys/file.h>
135 #include <sys/tty.h>
136 #include <sys/conf.h>
137 #include <sys/dk.h>
138 #include <sys/uio.h>
139 #include <sys/errno.h>
140 #if !(NS_TARGET >= 40)
141 /* XXX what happened to this header file? */
142 #include <machine/param.h>
143 #endif
145 #include <kernserv/prototypes.h>
146 /* NeXT broke spl.h in 3.2/m68k. Thanks EPS! */
148 #if defined(m68k)
149 #import "spl.h"
150 #else
151 #include <driverkit/generalFuncs.h>
152 #import <kernserv/machine/spl.h>
153 #endif
155 #include <kernserv/kern_server_types.h>
157 #include <net/if.h>
158 #include <net/route.h>
160 #ifdef VJC
161 #include <netinet/in.h>
162 #include <netinet/in_systm.h>
163 #include <netinet/ip.h>
164 #endif
166 #include <net/ppp_defs.h>
167 #ifdef VJC
168 #include <net/vjcompress.h>
169 #endif
170 #include <net/if_ppp.h>
171 #include "if_pppvar.h"
173 #include "inlines.h"
175 int pppopen __P((dev_t dev, struct tty *tp));
176 void pppclose __P((struct tty *tp));
177 int pppread __P((struct tty *tp, struct uio *uio));
178 int pppwrite __P((struct tty *tp, struct uio *uio));
179 int ppptioctl __P((struct tty *tp, int cmd, void *data, int flag));
180 void pppinput __P((int c, struct tty *tp));
181 void pppstart __P((struct tty *tp));
184 * Must return an actual netbuf_t since other protocols
185 * use this to get our buffers.
187 netbuf_t pppgetbuf __P((netif_t));
190 * Must accept an actual netbuf_t since others use this
191 * Procedure to access our output routine.
193 int pppoutput __P((netif_t ifp, netbuf_t m, void *arg));
195 static u_int16_t pppfcs __P((u_int16_t fcs, u_char *cp, int len));
196 static void pppasyncstart __P((struct ppp_softc *));
197 static void pppasyncctlp __P((struct ppp_softc *));
198 static void pppasyncrelinq __P((struct ppp_softc *));
199 static int ppp_timeout __P((void *));
200 void pppgetm __P((struct ppp_softc *sc));
201 static void pppdumpb __P((u_char *b, int l));
202 void ppplogchar __P((struct ppp_softc *, int));
204 extern kern_server_t instance;
207 * Does c need to be escaped?
209 #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
211 #define CCOUNT(q) ((q)->c_cc)
213 #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */
215 #include "linedisc.h"
218 extern int ttymodem(struct tty*, int);
219 extern int ttselect(struct tty *tp, int rw);
222 static NETBUF_T
223 pppgetinbuf(netif_t ifp)
225 register struct ppp_softc *sc = &ppp_softc[if_unit(ifp)];
226 NETBUF_T nb;
227 int len = MAX(sc->sc_mru, PPP_MTU) + sizeof (struct ifnet *) +
228 #ifdef VJC
229 VJ_HDRLEN +
230 #endif
231 PPP_HDRLEN + PPP_FCSLEN;
232 nb = NB_ALLOC(len);
233 if (nb != NULL)
235 #ifdef VJC
236 NB_SHRINK_TOP(nb, VJ_HDRLEN + PPP_HDRLEN);
237 #else
238 NB_SHRINK_TOP(nb, PPP_HDRLEN);
239 #endif
242 return nb;
246 * I was a bit worried about reentrancy here. +++SJP
249 void
250 pppfillfreeq(void *arg)
252 struct ppp_softc *sc = (struct ppp_softc *)arg;
253 NETBUF_T nb;
254 volatile static int in = 0;
256 if (in)
257 return;
258 in = 1;
260 while(!nbq_high(&sc->sc_freeq)) {
261 nb = pppgetinbuf(sc->sc_if);
262 if (! nb) break;
263 nbq_enqueue(&sc->sc_freeq, nb);
266 in = 0;
270 * Line specific open routine for async tty devices.
271 * Attach the given tty to the first available ppp unit.
273 /* ARGSUSED */
275 pppopen(dev, tp)
276 dev_t dev;
277 register struct tty *tp;
279 struct proc *p = curproc; /* XXX */
280 register struct ppp_softc *sc;
281 int s;
283 if (! suser())
284 return EPERM;
286 if (tp->t_line == PPPDISC) {
287 sc = (struct ppp_softc *) tp->t_sc;
288 if (sc != NULL && sc->sc_devp == (void *) tp)
289 return (0);
292 if ((sc = pppalloc(p->p_pid)) == NULL)
293 return ENXIO;
295 if (sc->sc_relinq)
296 (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */
298 pppfillfreeq((void *) sc); /* fill the free queue - we may block */
300 s = splimp();
301 sc->sc_ilen = 0;
302 sc->sc_m = NULL;
303 bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
304 sc->sc_asyncmap[0] = 0xffffffff;
305 sc->sc_asyncmap[3] = 0x60000000; /* 0x7D and 0x7E */
306 sc->sc_rasyncmap = 0;
307 sc->sc_devp = (void *) tp;
308 sc->sc_start = pppasyncstart;
309 sc->sc_ctlp = pppasyncctlp;
310 sc->sc_relinq = pppasyncrelinq;
311 sc->sc_outm = NULL;
312 pppgetm(sc);
313 if_flags_set(sc->sc_if, if_flags(sc->sc_if) | IFF_RUNNING);
315 tp->t_sc = (caddr_t) sc;
316 ttyflush(tp, FREAD | FWRITE);
317 splx(s);
319 return (0);
323 * Line specific close routine.
324 * Detach the tty from the ppp unit.
325 * Mimics part of ttyclose().
327 void
328 pppclose(tp)
329 struct tty *tp;
331 register struct ppp_softc *sc;
332 int s;
334 ttywflush(tp);
335 s = splimp(); /* paranoid; splnet probably ok */
336 tp->t_line = 0;
337 sc = (struct ppp_softc *) tp->t_sc;
338 if (sc != NULL) {
339 tp->t_sc = NULL;
340 if (tp == (struct tty *) sc->sc_devp) {
341 pppasyncrelinq(sc);
342 pppdealloc(sc);
345 splx(s);
346 return;
350 * Relinquish the interface unit to another device.
352 static void
353 pppasyncrelinq(sc)
354 struct ppp_softc *sc;
356 int s;
358 s = splimp();
359 if (sc->sc_outm) {
360 NB_FREE(sc->sc_outm);
361 sc->sc_outm = NULL;
363 if (sc->sc_m) {
364 NB_FREE(sc->sc_m);
365 sc->sc_m = NULL;
367 if (sc->sc_flags & SC_TIMEOUT) {
368 ns_untimeout(ppp_timeout, (void *) sc);
369 sc->sc_flags &= ~SC_TIMEOUT;
371 splx(s);
375 * Line specific (tty) read routine.
378 pppread(tp, uio)
379 register struct tty *tp;
380 struct uio *uio;
382 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
383 NETBUF_T m;
384 register int s;
385 int error = 0;
386 struct nty *np = ttynty(tp);
388 #ifdef NEW_CLOCAL
389 if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
390 return 0; /* end of file */
392 #else
394 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
395 return 0; /* end of file */
397 #endif /* NEW_CLOCAL */
399 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
400 return 0;
401 s = splimp();
402 while (nbq_empty(&sc->sc_inq) && tp->t_line == PPPDISC) {
403 if (tp->t_state & (TS_ASYNC | TS_NBIO)) {
404 splx(s);
405 return (EWOULDBLOCK);
407 sleep((caddr_t)&tp->t_rawq, TTIPRI);
409 if (tp->t_line != PPPDISC) {
410 splx(s);
411 return (-1);
414 /* Pull place-holder byte out of canonical queue */
415 getc(&tp->t_canq);
417 /* Get the packet from the input queue */
418 m = nbq_dequeue(&sc->sc_inq);
419 splx(s);
420 if (nbuf == NULL){
421 if (sc->sc_flags & SC_DEBUG)
422 IOLogDbg("Read didn't get a buffer at %s %d\n", __FILE__, __LINE__);
423 return -1;
425 error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_READ, uio);
426 NB_FREE(m);
427 return (error);
431 * Line specific (tty) write routine.
434 pppwrite(tp, uio)
435 register struct tty *tp;
436 struct uio *uio;
438 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
439 NETBUF_T m;
440 struct sockaddr dst;
441 int len, error;
442 struct nty *np = ttynty(tp);
444 #ifdef NEW_CLOCAL
446 if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0)
447 return 0; /* wrote 0 bytes */
449 #else
451 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0)
452 return 0; /* wrote 0 bytes */
454 #endif /* NEW_CLOCAL */
456 if (tp->t_line != PPPDISC)
457 return (EINVAL);
458 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
459 return EIO;
460 if (uio->uio_resid > if_mtu(sc->sc_if) + PPP_HDRLEN ||
461 uio->uio_resid < PPP_HDRLEN)
462 return (EMSGSIZE);
463 m = nb_TO_NB(pppgetbuf(sc->sc_if));
465 if (m == NULL){
466 if (sc->sc_flags & SC_DEBUG)
467 IOLogDbg("No buffers available for user level write()\n");
468 return(ENOBUFS);
470 NB_GROW_TOP(m, PPP_HDRLEN);
471 len = uio->uio_resid;
472 if (error = uiomove(NB_MAP(m), NB_SIZE(m), UIO_WRITE, uio)) {
473 NB_FREE(m);
474 return error;
476 NB_SHRINK_BOT(m, NB_SIZE(m) - len);
477 dst.sa_family = AF_UNSPEC;
478 bcopy(mtod(m, u_char *), dst.sa_data, PPP_HDRLEN);
480 NB_SHRINK_TOP(m, PPP_HDRLEN);
481 return (pppoutput(sc->sc_if, NB_TO_nb(m), &dst));
485 * Line specific (tty) ioctl routine.
486 * This discipline requires that tty device drivers call
487 * the line specific l_ioctl routine from their ioctl routines.
489 /* ARGSUSED */
491 ppptioctl(tp, cmd, data, flag)
492 struct tty *tp;
493 void *data;
494 int cmd, flag;
496 struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
497 int error, s;
499 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
500 return -1;
502 error = 0;
503 switch (cmd) {
504 case PPPIOCSASYNCMAP:
505 if (! suser())
506 return EPERM;
508 sc->sc_asyncmap[0] = *(u_int *)data;
509 break;
511 case PPPIOCGASYNCMAP:
512 *(u_int *)data = sc->sc_asyncmap[0];
513 break;
515 case PPPIOCSRASYNCMAP:
516 if (! suser())
517 return EPERM;
518 sc->sc_rasyncmap = *(u_int *)data;
519 break;
521 case PPPIOCGRASYNCMAP:
522 *(u_int *)data = sc->sc_rasyncmap;
523 break;
525 case PPPIOCSXASYNCMAP:
526 if (! suser())
527 return EPERM;
528 s = spltty();
529 bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
530 sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */
531 sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */
532 sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */
533 splx(s);
534 break;
536 case PPPIOCGXASYNCMAP:
537 bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
538 break;
540 default:
541 error = pppioctl(sc, cmd, data, flag);
542 if (error == 0 && cmd == PPPIOCSMRU)
543 pppgetm(sc);
546 #ifdef i386
547 if (! error && (cmd & IOC_OUT)) {
548 struct uthread *_u = uthread_from_thread(current_thread());
550 /* third arg is destination in ioctl() call... */
551 copyout(data, (caddr_t) _u->uu_arg[2], (cmd >> 16) & IOCPARM_MASK);
553 #endif
555 return error;
559 * FCS lookup table as calculated by genfcstab.
561 static const u_int16_t fcstab[256] = {
562 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
563 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
564 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
565 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
566 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
567 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
568 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
569 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
570 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
571 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
572 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
573 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
574 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
575 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
576 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
577 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
578 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
579 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
580 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
581 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
582 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
583 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
584 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
585 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
586 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
587 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
588 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
589 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
590 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
591 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
592 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
593 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
597 * Calculate a new FCS given the current FCS and the new data.
599 static u_int16_t
600 pppfcs(fcs, cp, len)
601 register u_int16_t fcs;
602 register u_char *cp;
603 register int len;
605 while (len--)
606 fcs = PPP_FCS(fcs, *cp++);
607 return (fcs);
611 * This gets called from pppoutput when a new packet is
612 * put on a queue.
614 static void
615 pppasyncstart(sc)
616 register struct ppp_softc *sc;
618 register struct tty *tp = (struct tty *) sc->sc_devp;
619 int s;
621 s = splimp();
622 pppstart(tp);
623 splx(s);
627 * This gets called when a received packet is placed on
628 * the inq.
630 static void
631 pppasyncctlp(sc)
632 struct ppp_softc *sc;
634 struct tty *tp;
636 /* Put a placeholder byte in canq for ttselect()/ttnread(). */
637 tp = (struct tty *) sc->sc_devp;
638 putc(0, &tp->t_canq);
639 ttwakeup(tp);
643 * Start output on async tty interface. Get another datagram
644 * to send from the interface queue and start sending it.
646 void
647 pppstart(tp)
648 register struct tty *tp;
650 register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
651 register NETBUF_T m;
652 register int len;
653 register u_char *start, *stop, *cp;
654 int n, ndone, done, idle;
655 struct nty *np = ttynty(tp);
657 #ifdef NEW_CLOCAL
659 if ((tp->t_state & TS_CARR_ON) == 0 && (np->t_pflags & TP_CLOCAL) == 0
661 #else
663 if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_flags & CLOCAL) == 0
665 #endif /* NEW_CLOCAL */
667 || sc == NULL || tp != (struct tty *) sc->sc_devp) {
668 if (tp->t_oproc != NULL)
669 (*tp->t_oproc)(tp);
670 return;
673 idle = 0;
674 #ifdef OLD_MUX
675 while (CCOUNT(&tp->t_outq) == 0) {
676 #else
677 while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
678 #endif
680 * See if we have an existing packet partly sent.
681 * If not, get a new packet and start sending it.
683 m = sc->sc_outm;
684 if (m == NULL) {
686 * Get another packet to be sent.
688 m = ppp_dequeue(sc);
689 if (m == NULL) {
690 idle = 1;
691 break;
695 * The extra PPP_FLAG will start up a new packet, and thus
696 * will flush any accumulated garbage. We do this whenever
697 * the line may have been idle for some time.
699 if (CCOUNT(&tp->t_outq) == 0) {
700 ++sc->sc_bytessent;
701 (void) putc(PPP_FLAG, &tp->t_outq);
704 /* Calculate the FCS for the first netbuf's worth. */
705 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), NB_SIZE(m));
706 sc->sc_outfcs ^= 0xffff;
708 cp = mtod(m, u_char *) + NB_SIZE(m);
709 NB_GROW_BOT(m, PPP_FCSLEN);
710 *cp++ = sc->sc_outfcs & 0xFF;
711 *cp++ = (sc->sc_outfcs >> 8) & 0xFF;
714 start = mtod(m, u_char *);
715 len = NB_SIZE(m);
716 stop = start + len;
717 while (len > 0) {
719 * Find out how many bytes in the string we can
720 * handle without doing something special.
722 for (cp = start; cp < stop; cp++)
723 if (ESCAPE_P(*cp))
724 break;
726 n = cp - start;
728 if (n) {
730 * b_to_q returns the number of characters
731 * _not_ sent
733 * NetBSD (0.9 or later), 4.3-Reno or similar.
735 ndone = n - b_to_q(start, n, &tp->t_outq);
736 len -= ndone;
737 start += ndone;
738 sc->sc_bytessent += ndone;
740 if (ndone < n)
741 break; /* packet doesn't fit */
746 * If there are characters left in the netbuf,
747 * the first one must be special..
748 * Put it out in a different form.
750 if (len) {
751 if (putc(PPP_ESCAPE, &tp->t_outq))
752 break;
753 if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
754 (void) unputc(&tp->t_outq);
755 break;
757 sc->sc_bytessent += 2;
758 start++;
759 len--;
763 * If we didn't empty this netbuf, remember where we're up to.
765 done = len == 0;
767 if (!done) {
768 /* remember where we got to */
769 NB_SHRINK_TOP(m, start - mtod(m, u_char *));
770 break; /* can't do any more at the moment */
774 * Output trailing PPP flag and finish packet.
775 * We make the length zero in case the flag
776 * cannot be output immediately.
778 NB_SHRINK_TOP(m, NB_SIZE(m));
779 if (putc(PPP_FLAG, &tp->t_outq))
780 break;
781 sc->sc_bytessent++;
784 /* Finished with this netbuf; free it and move on. */
785 NB_FREE(m);
786 m = NULL;
787 incr_cnt(sc->sc_if, if_opackets);
789 sc->sc_outm = m;
793 * If there is stuff in the output queue, send it now.
794 * We are being called in lieu of ttstart and must do what it would.
796 if (tp->t_oproc != NULL)
797 (*tp->t_oproc)(tp);
800 * This timeout is needed for operation on a pseudo-tty,
801 * because the pty code doesn't call pppstart after it has
802 * drained the t_outq.
804 if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
805 #if NS_TARGET >= 40
806 timeout(ppp_timeout, (void *) sc, 1);
807 #else
808 ns_timeout(ppp_timeout, (void *) sc, 1 * (1000000000L / HZ), CALLOUT_PRI_SOFTINT0);
809 #endif /*NS_TARGET */
810 sc->sc_flags |= SC_TIMEOUT;
813 return;
817 * Timeout routine - try to start some more output.
819 static int
820 ppp_timeout(x)
821 void *x;
823 struct ppp_softc *sc = (struct ppp_softc *) x;
824 struct tty *tp = (struct tty *) sc->sc_devp;
825 int s;
827 s = splimp();
828 sc->sc_flags &= ~SC_TIMEOUT;
829 pppstart(tp);
830 splx(s);
831 return 0;
835 * Allocate enough netbuf to handle current MRU.
837 * Warning Will Robinson: pppgetm() can get called at interrupt-level!
839 void
840 pppgetm(sc)
841 register struct ppp_softc *sc;
843 int s;
845 s = splimp();
847 * When the MRU is being changed, we could conceivably end up
848 * nuking a packet being received, but I doubt it, since the
849 * hand-shake is lock-step (ie. single packet).
851 if (sc->sc_m != NULL)
852 NB_FREE(sc->sc_m);
853 sc->sc_m = nbq_dequeue(&sc->sc_freeq);
854 splx(s);
858 * 4.3 says this is an unused function. However,
859 * it appears to be returning a NULL terminated string
860 * of several characters. My guess is that the serial
861 * driver is doing a little buffering so that we don't
862 * get burdend with interrupts.
864 * This function gets called when you use the NeXT
865 * supplied serial drivers. It does not get called
866 * with the MuX driver.
868 * In order to expedite the work done here, we
869 * handle most things here that don't require
870 * processing of a PPP_FLAG.
874 void
875 ppprend(cp, n, tp)
876 unsigned char *cp;
877 int n;
878 struct tty *tp;
881 #ifndef OPTIMIZE_PPPREND
882 #warning PPPREND Not optimized!!!
883 while (n--) pppinput((u_char) *cp++, tp);
884 #else
887 register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
888 register int ret;
890 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
892 printf("Warning, bad softc structure at %s %d\n", __FILE__, __LINE__);
893 return;
897 * We can handle FLUSHs, ESCAPES, and non PPP_FLAG characters
900 while (n)
902 if (sc->sc_flags & SC_FLUSH)
906 if (*(cp++) == PPP_FLAG)
908 pppinput(PPP_FLAG, tp);
909 --n;
910 break;
912 else if (sc->sc_flags & SC_LOG_FLUSH)
913 ppplogchar(sc, *cp);
915 while(--n);
917 else if (sc->sc_ilen > 3 &&
918 (NB_SIZE(sc->sc_m) - sc->sc_ilen) > n &&
919 *cp != PPP_FLAG &&
920 *cp != PPP_ESCAPE) /* Dont really handle escapes properly...should */
922 unsigned char* cp1 = cp;
923 if (sc->sc_flags & SC_ESCAPED)
925 sc->sc_flags &= ~SC_ESCAPED;
926 *cp ^= PPP_TRANS;
931 sc->sc_fcs = PPP_FCS(sc->sc_fcs, *(cp++));
932 if (sc->sc_flags & SC_LOG_RAWIN)
933 ppplogchar(sc, *cp);
935 } while(--n && *cp != PPP_FLAG && *cp != PPP_ESCAPE);
938 bcopy(cp1, sc->sc_mp, (cp-cp1));
940 sc->sc_bytesrcvd += (cp - cp1);
941 sc->sc_ilen += (cp-cp1);
942 sc->sc_mp += (cp-cp1);
945 else
947 --n;
948 pppinput(*(cp++), tp);
952 #endif /* OPTIMIZE_PPPREND */
956 * tty interface receiver interrupt.
958 static const unsigned paritytab[8] = {
959 0x96696996, 0x69969669, 0x69969669, 0x96696996,
960 0x69969669, 0x96696996, 0x96696996, 0x69969669
963 void
964 pppinput(c, tp)
965 int c;
966 register struct tty *tp;
968 register struct ppp_softc *sc;
969 NETBUF_T m;
970 int ilen, s;
972 sc = (struct ppp_softc *) tp->t_sc;
973 if (sc == NULL || tp != (struct tty *) sc->sc_devp)
974 return;
976 ++tk_nin;
977 ++sc->sc_bytesrcvd;
979 if (c & TTY_FE) {
980 /* framing error or overrun on this char - abort packet */
981 IOLogDbg("ppp%d: bad char 0x%x\n", if_unit(sc->sc_if), c);
982 goto flush;
985 c &= 0xff;
987 if (c & 0x80)
988 sc->sc_flags |= SC_RCV_B7_1;
989 else
990 sc->sc_flags |= SC_RCV_B7_0;
991 if (paritytab[c >> 5] & (1 << (c & 0x1F)))
992 sc->sc_flags |= SC_RCV_ODDP;
993 else
994 sc->sc_flags |= SC_RCV_EVNP;
996 if (sc->sc_flags & SC_LOG_RAWIN)
997 ppplogchar(sc, c);
999 if (c == PPP_FLAG) {
1001 if (sc->sc_ilen == 0)
1002 return;
1004 ilen = sc->sc_ilen;
1005 sc->sc_ilen = 0;
1007 if (sc->sc_rawin_count > 0)
1008 ppplogchar(sc, -1);
1011 * From the RFC:
1012 * Each Control Escape octet is also
1013 * removed, and the following octet is exclusive-or'd with hexadecimal
1014 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1016 * So, if SC_ESCAPED is set, then we've seen the packet
1017 * abort sequence "}~".
1019 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) ||
1020 ((ilen > 0) && (sc->sc_fcs != PPP_GOODFCS)))
1022 sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
1023 if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0)
1025 IOLog("ppp%d: bad fcs 0x%04x\n", if_unit(sc->sc_if), sc->sc_fcs);
1026 incr_cnt(sc->sc_if, if_ierrors);
1028 else
1030 IOLog("ppp%d: bad packet flushed...\n", if_unit(sc->sc_if));
1031 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
1033 return;
1036 if (ilen < (PPP_HDRLEN + PPP_FCSLEN))
1038 if (ilen)
1040 IOLogDbg("ppp%d: too short (%d)\n", if_unit(sc->sc_if), ilen);
1041 incr_cnt(sc->sc_if, if_ierrors);
1042 sc->sc_flags |= SC_PKTLOST;
1044 return;
1048 * Remove FCS trailer. Set packet length...
1050 ilen -= PPP_FCSLEN;
1051 NB_SHRINK_BOT(sc->sc_m, NB_SIZE(sc->sc_m) - ilen);
1053 /* excise this netbuf */
1054 m = sc->sc_m;
1055 sc->sc_m = NULL;
1057 ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
1058 sc->sc_flags &= ~SC_PKTLOST;
1060 pppgetm(sc);
1061 return;
1064 if (sc->sc_flags & SC_FLUSH) {
1065 if (sc->sc_flags & SC_LOG_FLUSH)
1066 ppplogchar(sc, c);
1067 return;
1071 * From the RFC:
1072 * On reception, prior to FCS computation, each octet with value less
1073 * than hexadecimal 0x20 is checked. If it is flagged in the receiving
1074 * ACCM, it is simply removed (it may have been inserted by intervening
1075 * data communications equipment). Each Control Escape octet is also
1076 * removed, and the following octet is exclusive-or'd with hexadecimal
1077 * 0x20, unless it is the Flag Sequence (which aborts a frame).
1079 if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) {
1080 return;
1083 if (sc->sc_flags & SC_ESCAPED) {
1084 sc->sc_flags &= ~SC_ESCAPED;
1085 c ^= PPP_TRANS;
1086 } else if (c == PPP_ESCAPE) {
1087 sc->sc_flags |= SC_ESCAPED;
1088 return;
1092 * Initialize buffer on first octet received.
1093 * First octet could be address or protocol (when compressing
1094 * address/control).
1095 * Second octet is control.
1096 * Third octet is first or second (when compressing protocol)
1097 * octet of protocol.
1098 * Fourth octet is second octet of protocol.
1100 if (sc->sc_ilen == 0) {
1102 /* reset the input netbuf */
1103 if (sc->sc_m == NULL) {
1104 pppgetm(sc);
1105 if (sc->sc_m == NULL) {
1107 * We schedule a call here as pppindrain will
1108 * not get scheduled and we need the free buffers
1110 IOLog("ppp%d: no input netbufs!\n", if_unit(sc->sc_if));
1111 (void)pppsched(pppfillfreeq, sc);
1112 goto flush;
1115 m = sc->sc_m;
1116 sc->sc_mp = mtod(m, char *);
1117 sc->sc_fcs = PPP_INITFCS;
1119 if (c != PPP_ALLSTATIONS) {
1120 if (sc->sc_flags & SC_REJ_COMP_AC) {
1121 IOLogDbg("ppp%d: garbage received: 0x%02x (need 0x%02x)\n",
1122 if_unit(sc->sc_if), c, PPP_ALLSTATIONS);
1123 goto flush;
1125 *sc->sc_mp++ = PPP_ALLSTATIONS;
1126 *sc->sc_mp++ = PPP_UI;
1127 sc->sc_ilen += 2;
1132 if (sc->sc_ilen == 1 && c != PPP_UI) {
1133 IOLogDbg("ppp%d: missing UI (0x%02x), got 0x%02x\n",
1134 if_unit(sc->sc_if), PPP_UI, c);
1135 goto flush;
1138 if (sc->sc_ilen == 2 && (c & 1) == 1) {
1139 /* a compressed protocol */
1140 *sc->sc_mp++ = 0;
1141 sc->sc_ilen++;
1144 if (sc->sc_ilen == 3 && (c & 1) == 0) {
1145 IOLogDbg("ppp%d: bad protocol %x\n", if_unit(sc->sc_if),
1146 (sc->sc_mp[-1] << 8) + c);
1147 goto flush;
1150 /* packet beyond configured mru? */
1151 if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
1152 IOLogDbg("ppp%d: packet too big (%d bytes)\n", if_unit(sc->sc_if),
1153 sc->sc_ilen);
1154 goto flush;
1157 /* ilen was incremented above... */
1158 *sc->sc_mp++ = c;
1159 sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
1160 return;
1162 flush:
1163 if (!(sc->sc_flags & SC_FLUSH)) {
1164 incr_cnt(sc->sc_if, if_ierrors);
1165 sc->sc_flags |= SC_FLUSH;
1166 if (sc->sc_flags & SC_LOG_FLUSH)
1167 ppplogchar(sc, c);
1169 return;
1173 install_ppp_ld(void)
1175 return tty_ld_install(PPPDISC, NORMAL_LDISC, pppopen,
1176 pppclose, pppread, pppwrite, ppptioctl,
1177 pppinput, ppprend, pppstart, ttymodem,
1178 ttselect);
1181 #define MAX_DUMP_BYTES 128
1183 void
1184 ppplogchar(sc, c)
1185 struct ppp_softc *sc;
1186 int c;
1188 if (c >= 0)
1189 sc->sc_rawin[sc->sc_rawin_count++] = c;
1190 if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
1191 || c < 0 && sc->sc_rawin_count > 0) {
1192 IOLog("ppp%d input:\n", if_unit(sc->sc_if));
1193 pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
1194 sc->sc_rawin_count = 0;
1198 static void
1199 pppdumpb(b, l)
1200 u_char *b;
1201 int l;
1203 char buf[3*MAX_DUMP_BYTES+4];
1204 char *bp = buf;
1205 static char digits[] = "0123456789abcdef";
1207 while (l--) {
1208 if (bp >= buf + sizeof(buf) - 3) {
1209 *bp++ = '>';
1210 break;
1212 *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
1213 *bp++ = digits[*b++ & 0xf];
1214 *bp++ = ' ';
1217 *bp = 0;
1218 IOLog("%s\n", buf);
1220 #endif /* NUM_PPP > 0 */