Copyrights added to each file.
[unix-history] / sys / net / if_sl.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1987, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
70c5ff60 33 * from: @(#)if_sl.c 7.22 (Berkeley) 4/20/91
4c45483e 34 * $Id: if_sl.c,v 1.5 1993/11/16 02:47:24 wollman Exp $
15637ed4
RG
35 */
36
37/*
38 * Serial Line interface
39 *
40 * Rick Adams
41 * Center for Seismic Studies
42 * 1300 N 17th Street, Suite 1450
43 * Arlington, Virginia 22209
44 * (703)276-7900
45 * rick@seismo.ARPA
46 * seismo!rick
47 *
48 * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
49 * N.B.: this belongs in netinet, not net, the way it stands now.
50 * Should have a link-layer type designation, but wouldn't be
51 * backwards-compatible.
52 *
53 * Converted to 4.3BSD Beta by Chris Torek.
54 * Other changes made at Berkeley, based in part on code by Kirk Smith.
55 * W. Jolitz added slip abort.
56 *
57 * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov).
58 * Added priority queuing for "interactive" traffic; hooks for TCP
59 * header compression; ICMP filtering (at 2400 baud, some cretin
60 * pinging you can use up all your bandwidth). Made low clist behavior
61 * more robust and slightly less likely to hang serial line.
62 * Sped up a bunch of things.
63 *
64 * Note that splimp() is used throughout to block both (tty) input
65 * interrupts and network activity; thus, splimp must be >= spltty.
66 */
67
4c45483e 68/* $Id: if_sl.c,v 1.5 1993/11/16 02:47:24 wollman Exp $ */
15637ed4
RG
69/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
70
71#include "sl.h"
72#if NSL > 0
73
74#include "param.h"
b983fd86 75#include "systm.h"
f331c318 76#include "kernel.h" /* sigh */
15637ed4
RG
77#include "proc.h"
78#include "mbuf.h"
79#include "buf.h"
80#include "dkstat.h"
81#include "socket.h"
82#include "ioctl.h"
83#include "file.h"
84#include "tty.h"
85#include "kernel.h"
86#include "conf.h"
87
88#include "if.h"
89#include "if_types.h"
90#include "netisr.h"
91#include "route.h"
92#if INET
93#include "netinet/in.h"
94#include "netinet/in_systm.h"
95#include "netinet/in_var.h"
96#include "netinet/ip.h"
97#else
98Huh? Slip without inet?
99#endif
100
101#include "machine/mtpr.h"
102
103#include "slcompress.h"
104#include "if_slvar.h"
105#include "slip.h"
106
107#include "bpfilter.h"
108#if NBPFILTER > 0
109#include <sys/time.h>
110#include <net/bpf.h>
111#endif
112
113/*
114 * SLMAX is a hard limit on input packet size. To simplify the code
115 * and improve performance, we require that packets fit in an mbuf
116 * cluster, and if we get a compressed packet, there's enough extra
117 * room to expand the header into a max length tcp/ip header (128
118 * bytes). So, SLMAX can be at most
119 * MCLBYTES - 128
120 *
121 * SLMTU is a hard limit on output packet size. To insure good
122 * interactive response, SLMTU wants to be the smallest size that
123 * amortizes the header cost. (Remember that even with
124 * type-of-service queuing, we have to wait for any in-progress
125 * packet to finish. I.e., we wait, on the average, 1/2 * mtu /
126 * cps, where cps is the line speed in characters per second.
127 * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The
128 * average compressed header size is 6-8 bytes so any MTU > 90
129 * bytes will give us 90% of the line bandwidth. A 100ms wait is
130 * tolerable (500ms is not), so want an MTU around 296. (Since TCP
131 * will send 256 byte segments (to allow for 40 byte headers), the
132 * typical packet size on the wire will be around 260 bytes). In
133 * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
134 * leave the interface MTU relatively high (so we don't IP fragment
135 * when acting as a gateway to someone using a stupid MTU).
136 *
137 * Similar considerations apply to SLIP_HIWAT: It's the amount of
138 * data that will be queued 'downstream' of us (i.e., in clists
139 * waiting to be picked up by the tty output interrupt). If we
140 * queue a lot of data downstream, it's immune to our t.o.s. queuing.
141 * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
142 * telnet/ftp will see a 1 sec wait, independent of the mtu (the
143 * wait is dependent on the ftp window size but that's typically
144 * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize
145 * the cost (in idle time on the wire) of the tty driver running
146 * off the end of its clists & having to call back slstart for a
147 * new packet. For a tty interface with any buffering at all, this
148 * cost will be zero. Even with a totally brain dead interface (like
149 * the one on a typical workstation), the cost will be <= 1 character
150 * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
151 * at most 1% while maintaining good interactive response.
152 */
153#if NBPFILTER > 0
154#define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
155#else
156#define BUFOFFSET (128+sizeof(struct ifnet **))
157#endif
158#define SLMAX (MCLBYTES - BUFOFFSET)
159#define SLBUFSIZE (SLMAX + BUFOFFSET)
f331c318
GW
160
161#ifdef experimental
162/*
163 * In this code, the SLMTU is the actual interface MTU as advertised
164 * in our ifnet structures. SLRMTU is the MTU we stick into routes
165 * via slrtrequest() to tell TCP to produce small packets.
166 */
167#ifndef SLMTU
168#define SLMTU 1500 /* same as Ethernet */
169#endif
170#ifndef SLRMTU
171#define SLRMTU 296 /* for good latency */
172#endif
173#else
174#define SLMTU 296
175#define SLRMTU SLMTU
176#endif
177
15637ed4
RG
178#define SLIP_HIWAT roundup(50,CBSIZE)
179
180/*
181 * SLIP ABORT ESCAPE MECHANISM:
182 * (inspired by HAYES modem escape arrangement)
183 * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
184 * signals a "soft" exit from slip mode by usermode process
185 */
186
187#ifdef ABT_ESC
188#undef ABT_ESC
189#define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/
190#define ABT_WAIT 1 /* in seconds - idle before an escape & after */
191#define ABT_RECYCLE (5*2+2) /* in seconds - time window processing abort */
192#define ABT_SOFT 3 /* count of escapes */
193#endif /* ABT_ESC */
194
195/*
196 * The following disgusting hack gets around the problem that IP TOS
197 * can't be set yet. We want to put "interactive" traffic on a high
198 * priority queue. To decide if traffic is interactive, we check that
199 * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
200 */
201static u_short interactive_ports[8] = {
202 0, 513, 0, 0,
203 0, 21, 0, 23,
204};
205#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
206
207struct sl_softc sl_softc[NSL];
208
209#define FRAME_END 0xc0 /* Frame End */
210#define FRAME_ESCAPE 0xdb /* Frame Esc */
211#define TRANS_FRAME_END 0xdc /* transposed frame end */
212#define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */
213
214#define t_sc T_LINEP
215
f331c318
GW
216/*
217 * Prototypes.
218 */
219void slattach(void);
220static int slinit(struct sl_softc *);
221int slopen(int /*dev_t*/, struct tty *);
222int slclose(struct tty *);
223int sltioctl(struct tty *, int, caddr_t, int);
4c45483e 224int sloutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *);
f331c318
GW
225void slstart(struct tty *);
226static struct mbuf *sl_btom(struct sl_softc *, int);
227void slinput(int, struct tty *);
228static int slrtrequest(int, struct rtentry *, struct sockaddr *);
229int slioctl(struct ifnet *, int, caddr_t);
230
15637ed4
RG
231/*
232 * Called from boot code to establish sl interfaces.
233 */
f331c318
GW
234void
235slattach(void)
15637ed4
RG
236{
237 register struct sl_softc *sc;
238 register int i = 0;
239
240 for (sc = sl_softc; i < NSL; sc++) {
241 sc->sc_if.if_name = "sl";
242 sc->sc_if.if_unit = i++;
243 sc->sc_if.if_mtu = SLMTU;
244 sc->sc_if.if_flags = IFF_POINTOPOINT;
f331c318
GW
245 /*
246 * Multicast support is trivial for point-to-point
247 * netifs.
248 */
249#ifdef MULTICAST
250 sc->sc_if.if_flags |= IFF_MULTICAST;
251#endif
15637ed4
RG
252 sc->sc_if.if_type = IFT_SLIP;
253 sc->sc_if.if_ioctl = slioctl;
254 sc->sc_if.if_output = sloutput;
255 sc->sc_if.if_snd.ifq_maxlen = 50;
256 sc->sc_fastq.ifq_maxlen = 32;
257 if_attach(&sc->sc_if);
258#if NBPFILTER > 0
259 bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP,
260 SLIP_HDRLEN);
261#endif
262 }
263}
264
265static int
266slinit(sc)
267 register struct sl_softc *sc;
268{
269 register caddr_t p;
270
271 if (sc->sc_ep == (u_char *) 0) {
272 MCLALLOC(p, M_WAIT);
273 if (p)
274 sc->sc_ep = (u_char *)p + SLBUFSIZE;
275 else {
276 printf("sl%d: can't allocate buffer\n", sc - sl_softc);
277 sc->sc_if.if_flags &= ~IFF_UP;
278 return (0);
279 }
280 }
281 sc->sc_buf = sc->sc_ep - SLMAX;
282 sc->sc_mp = sc->sc_buf;
283 sl_compress_init(&sc->sc_comp);
284 return (1);
285}
286
287/*
288 * Line specific open routine.
289 * Attach the given tty to the first available sl unit.
290 */
291/* ARGSUSED */
f331c318 292int
15637ed4
RG
293slopen(dev, tp)
294 dev_t dev;
295 register struct tty *tp;
296{
297 struct proc *p = curproc; /* XXX */
298 register struct sl_softc *sc;
299 register int nsl;
300 int error;
301
302 if (error = suser(p->p_ucred, &p->p_acflag))
303 return (error);
304
305 if (tp->t_line == SLIPDISC)
306 return (0);
307
308 for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++)
309 if (sc->sc_ttyp == NULL) {
310 if (slinit(sc) == 0)
311 return (ENOBUFS);
312 tp->t_sc = (caddr_t)sc;
313 sc->sc_ttyp = tp;
314 sc->sc_if.if_baudrate = tp->t_ospeed;
315 ttyflush(tp, FREAD | FWRITE);
316 return (0);
317 }
318 return (ENXIO);
319}
320
321/*
322 * Line specific close routine.
323 * Detach the tty from the sl unit.
324 * Mimics part of ttyclose().
325 */
f331c318 326int
15637ed4
RG
327slclose(tp)
328 struct tty *tp;
329{
330 register struct sl_softc *sc;
331 int s;
332
333 ttywflush(tp);
334 s = splimp(); /* actually, max(spltty, splnet) */
335 tp->t_line = 0;
336 sc = (struct sl_softc *)tp->t_sc;
337 if (sc != NULL) {
338 if_down(&sc->sc_if);
339 sc->sc_ttyp = NULL;
340 tp->t_sc = NULL;
341 MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE));
342 sc->sc_ep = 0;
343 sc->sc_mp = 0;
344 sc->sc_buf = 0;
345 }
346 splx(s);
4c45483e 347 return 0;
15637ed4
RG
348}
349
350/*
351 * Line specific (tty) ioctl routine.
352 * Provide a way to get the sl unit number.
353 */
354/* ARGSUSED */
f331c318 355int
15637ed4
RG
356sltioctl(tp, cmd, data, flag)
357 struct tty *tp;
f331c318 358 int cmd;
15637ed4 359 caddr_t data;
f331c318 360 int flag;
15637ed4
RG
361{
362 struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
363 int s;
364
365 switch (cmd) {
366 case SLIOCGUNIT:
367 *(int *)data = sc->sc_if.if_unit;
368 break;
369
370 case SLIOCGFLAGS:
371 *(int *)data = sc->sc_flags;
372 break;
373
374 case SLIOCSFLAGS:
375#define SC_MASK 0xffff
376 s = splimp();
377 sc->sc_flags =
378 (sc->sc_flags &~ SC_MASK) | ((*(int *)data) & SC_MASK);
379 splx(s);
380 break;
381
382 default:
383 return (-1);
384 }
385 return (0);
386}
387
388/*
389 * Queue a packet. Start transmission if not active.
390 */
f331c318 391int
4c45483e 392sloutput(ifp, m, dst, rt)
15637ed4
RG
393 struct ifnet *ifp;
394 register struct mbuf *m;
395 struct sockaddr *dst;
4c45483e 396 struct rtentry *rt;
15637ed4
RG
397{
398 register struct sl_softc *sc = &sl_softc[ifp->if_unit];
399 register struct ip *ip;
400 register struct ifqueue *ifq;
401 int s;
402
403 /*
404 * `Cannot happen' (see slioctl). Someday we will extend
405 * the line protocol to support other address families.
406 */
407 if (dst->sa_family != AF_INET) {
408 printf("sl%d: af%d not supported\n", sc->sc_if.if_unit,
409 dst->sa_family);
410 m_freem(m);
411 return (EAFNOSUPPORT);
412 }
413
414 if (sc->sc_ttyp == NULL) {
415 m_freem(m);
416 return (ENETDOWN); /* sort of */
417 }
b983fd86
RG
418 if (((sc->sc_ttyp->t_state & TS_CARR_ON) == 0)
419 && ((sc->sc_ttyp->t_cflag & CLOCAL) == 0)) {
15637ed4 420 m_freem(m);
b983fd86 421 return (ENETDOWN);
15637ed4
RG
422 }
423 ifq = &sc->sc_if.if_snd;
424 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
425 u_short srcport = ntohs(((short *)ip)[ip->ip_hl << 1]);
426 u_short dstport = ntohs(((short *)ip)[(ip->ip_hl << 1) + 1]);
427
428 if (INTERACTIVE(srcport) || INTERACTIVE(dstport)) {
429 ifq = &sc->sc_fastq;
430 }
431
432 } else if (sc->sc_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
433 m_freem(m);
434 return (0);
435 }
436 s = splimp();
437 if (IF_QFULL(ifq)) {
438 IF_DROP(ifq);
439 m_freem(m);
440 splx(s);
441 sc->sc_if.if_oerrors++;
442 return (ENOBUFS);
443 }
444 IF_ENQUEUE(ifq, m);
445 sc->sc_if.if_lastchange = time;
446 if (RB_LEN(&sc->sc_ttyp->t_out) == 0)
447 slstart(sc->sc_ttyp);
448 splx(s);
449 return (0);
450}
451
452/*
453 * Start output on interface. Get another datagram
454 * to send from the interface queue and map it to
455 * the interface before starting output.
456 */
f331c318 457void
15637ed4
RG
458slstart(tp)
459 register struct tty *tp;
460{
461 register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
462 register struct mbuf *m;
463 register u_char *cp;
464 register struct ip *ip;
465 int s;
466 struct mbuf *m2;
467#if NBPFILTER > 0
468 u_char bpfbuf[SLMTU + SLIP_HDRLEN];
4c45483e 469 register int len = 0;
15637ed4
RG
470#endif
471
472 for (;;) {
473 /*
99f7d84f 474 * Call output process whether or not there is any output.
15637ed4
RG
475 * We are being called in lieu of ttstart and must do what
476 * it would.
477 */
99f7d84f
RG
478 (*tp->t_oproc)(tp);
479 if (RB_LEN(&tp->t_out) > SLIP_HIWAT)
480 return;
481
15637ed4
RG
482 /*
483 * This happens briefly when the line shuts down.
484 */
485 if (sc == NULL)
486 return;
487
488 /*
489 * Do not remove the packet from the IP queue if it
490 * doesn't look like the packet will fit into the
491 * current COM output queue, with a packet full of
492 * escapes this could be as bad as SLMTU*2. The value
493 * of RBSZ in tty.h also has to be upped to be at least
494 * SLMTU*2.
495 */
b983fd86 496 if (min(RBSZ, 4 * SLMTU + 4) - RB_LEN(&tp->t_out) < 2 * SLMTU + 2)
15637ed4
RG
497 return;
498
499 /*
500 * Get a packet and send it to the interface.
501 */
502 s = splimp();
503 IF_DEQUEUE(&sc->sc_fastq, m);
504 if (m == NULL)
505 IF_DEQUEUE(&sc->sc_if.if_snd, m);
506 splx(s);
507 if (m == NULL)
508 return;
509 /*
510 * We do the header compression here rather than in sl_output
511 * because the packets will be out of order if we are using TOS
512 * queueing, and the connection id compression will get messed
513 * up when this happens.
514 */
515#if NBPFILTER > 0
516 if (sc->sc_bpf) {
517 /*
518 * We need to save the TCP/IP header before it's compressed.
519 * To avoid complicated code, we just copy the entire packet
520 * into a stack buffer (since this is a serial line, packets
521 * should be short and/or the copy should be negligible cost
522 * compared to the packet transmission time).
523 */
524 register struct mbuf *m1 = m;
525 register u_char *cp = bpfbuf + SLIP_HDRLEN;
526 len = 0;
527 do {
528 register int mlen = m1->m_len;
529
530 bcopy(mtod(m1, caddr_t), cp, mlen);
531 cp += mlen;
532 len += mlen;
533 } while (m1 = m1->m_next);
534 }
535#endif
536 if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
537 if (sc->sc_flags & SC_COMPRESS)
538 *mtod(m, u_char *) |= sl_compress_tcp(m, ip, &sc->sc_comp, 1);
539 }
540#if NBPFILTER > 0
541 if (sc->sc_bpf) {
542 /*
543 * Put the SLIP pseudo-"link header" in place. The compressed
544 * header is now at the beginning of the mbuf.
545 */
546 bpfbuf[SLX_DIR] = SLIPDIR_OUT;
547 bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN);
548 bpf_tap(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN);
549 }
550#endif
551
552 sc->sc_if.if_lastchange = time;
553
554 /*
555 * The extra FRAME_END will start up a new packet, and thus
556 * will flush any accumulated garbage. We do this whenever
557 * the line may have been idle for some time.
558 */
559 if (RB_LEN(&tp->t_out) == 0) {
560 ++sc->sc_bytessent;
561 (void) putc(FRAME_END, &tp->t_out);
562 }
563
564 while (m) {
565 register u_char *ep;
566
567 cp = mtod(m, u_char *); ep = cp + m->m_len;
568 while (cp < ep) {
569 /*
570 * Find out how many bytes in the string we can
571 * handle without doing something special.
572 */
573 register u_char *bp = cp;
574
575 while (cp < ep) {
576 switch (*cp++) {
577 case FRAME_ESCAPE:
578 case FRAME_END:
579 --cp;
580 goto out;
581 }
582 }
583 out:
584 if (cp > bp) {
585 /*
586 * Put the non-special bytes
587 * into the tty output queue.
588 */
589 sc->sc_bytessent += rb_write(
590 &tp->t_out,
591 (char *) bp,
592 cp - bp);
593 }
594 /*
595 * If there are characters left in the mbuf,
596 * the first one must be special..
597 * Put it out in a different form.
598 */
599 if (cp < ep) {
600 if (putc(FRAME_ESCAPE, &tp->t_out))
601 break;
602 if (putc(*cp++ == FRAME_ESCAPE ?
603 TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
604 &tp->t_out)) {
605 (void) unputc(&tp->t_out);
606 break;
607 }
608 sc->sc_bytessent += 2;
609 }
610 }
611 MFREE(m, m2);
612 m = m2;
613 }
614
615 if (putc(FRAME_END, &tp->t_out)) {
616 /*
617 * Not enough room. Remove a char to make room
618 * and end the packet normally.
619 * If you get many collisions (more than one or two
620 * a day) you probably do not have enough clists
621 * and you should increase "nclist" in param.c.
622 */
623 (void) unputc(&tp->t_out);
624 (void) putc(FRAME_END, &tp->t_out);
625 sc->sc_if.if_collisions++;
626 } else {
627 ++sc->sc_bytessent;
628 sc->sc_if.if_opackets++;
629 }
630 sc->sc_if.if_obytes = sc->sc_bytessent;
631 }
632}
633
634/*
635 * Copy data buffer to mbuf chain; add ifnet pointer.
636 */
637static struct mbuf *
638sl_btom(sc, len)
639 register struct sl_softc *sc;
640 register int len;
641{
642 register struct mbuf *m;
643
644 MGETHDR(m, M_DONTWAIT, MT_DATA);
645 if (m == NULL)
646 return (NULL);
647
648 /*
649 * If we have more than MHLEN bytes, it's cheaper to
650 * queue the cluster we just filled & allocate a new one
651 * for the input buffer. Otherwise, fill the mbuf we
652 * allocated above. Note that code in the input routine
653 * guarantees that packet will fit in a cluster.
654 */
655 if (len >= MHLEN) {
656 MCLGET(m, M_DONTWAIT);
657 if ((m->m_flags & M_EXT) == 0) {
658 /*
659 * we couldn't get a cluster - if memory's this
660 * low, it's time to start dropping packets.
661 */
662 (void) m_free(m);
663 return (NULL);
664 }
665 sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE;
666 m->m_data = (caddr_t)sc->sc_buf;
667 m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET);
668 } else
669 bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len);
670
671 m->m_len = len;
672 m->m_pkthdr.len = len;
673 m->m_pkthdr.rcvif = &sc->sc_if;
674 return (m);
675}
676
677/*
678 * tty interface receiver interrupt.
679 */
f331c318 680void
15637ed4
RG
681slinput(c, tp)
682 register int c;
683 register struct tty *tp;
684{
685 register struct sl_softc *sc;
686 register struct mbuf *m;
687 register int len;
688 int s;
689#if NBPFILTER > 0
690 u_char chdr[CHDR_LEN];
691#endif
692 tk_nin++;
693 sc = (struct sl_softc *)tp->t_sc;
694 if (sc == NULL)
695 return;
b983fd86
RG
696 if ((c & TTY_ERRORMASK) || (((tp->t_state & TS_CARR_ON) == 0)
697 && ((tp->t_cflag & CLOCAL) == 0))) {
99f7d84f 698 /* XXX */
15637ed4
RG
699 sc->sc_flags |= SC_ERROR;
700 return;
701 }
702
703 ++sc->sc_bytesrcvd;
704 ++sc->sc_if.if_ibytes;
705
706#ifdef ABT_ESC
707 if (sc->sc_flags & SC_ABORT) {
708 /* if we see an abort after "idle" time, count it */
709 if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) {
710 sc->sc_abortcount++;
711 /* record when the first abort escape arrived */
712 if (sc->sc_abortcount == 1)
713 sc->sc_starttime = time.tv_sec;
714 }
715 /*
716 * if we have an abort, see that we have not run out of time,
717 * or that we have an "idle" time after the complete escape
718 * sequence
719 */
720 if (sc->sc_abortcount) {
721 if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE)
722 sc->sc_abortcount = 0;
723 if (sc->sc_abortcount >= ABT_SOFT &&
724 time.tv_sec >= sc->sc_lasttime + ABT_WAIT) {
725 slclose(tp);
726 return;
727 }
728 }
729 sc->sc_lasttime = time.tv_sec;
730 }
731#endif
732
733 switch (c) {
734
735 case TRANS_FRAME_ESCAPE:
736 if (sc->sc_escape)
737 c = FRAME_ESCAPE;
738 break;
739
740 case TRANS_FRAME_END:
741 if (sc->sc_escape)
742 c = FRAME_END;
743 break;
744
745 case FRAME_ESCAPE:
746 sc->sc_escape = 1;
747 return;
748
749 case FRAME_END:
750 if (sc->sc_flags & SC_ERROR) {
751 sc->sc_flags &= ~SC_ERROR;
752 goto newpack;
753 }
754 len = sc->sc_mp - sc->sc_buf;
755 if (len < 3)
756 /* less than min length packet - ignore */
757 goto newpack;
758
759#if NBPFILTER > 0
760 if (sc->sc_bpf)
761 /*
762 * Save the compressed header, so we can
763 * tack it on later. Note that we just
764 * we will end up copying garbage in some
765 * cases but this is okay. We remember
766 * where the buffer started so we can
767 * compute the new header length.
768 */
769 bcopy(sc->sc_buf, chdr, CHDR_LEN);
770#endif
771 if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
772 if (c & 0x80)
773 c = TYPE_COMPRESSED_TCP;
774 else if (c == TYPE_UNCOMPRESSED_TCP)
775 *sc->sc_buf &= 0x4f; /* XXX */
776 /*
777 * We've got something that's not an IP packet.
778 * If compression is enabled, try to decompress it.
779 * Otherwise, if `auto-enable' compression is on and
780 * it's a reasonable packet, decompress it and then
781 * enable compression. Otherwise, drop it.
782 */
783 if (sc->sc_flags & SC_COMPRESS) {
784 len = sl_uncompress_tcp(&sc->sc_buf, len,
785 (u_int)c, &sc->sc_comp);
786 if (len <= 0)
787 goto error;
788 } else if ((sc->sc_flags & SC_AUTOCOMP) &&
789 c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
790 len = sl_uncompress_tcp(&sc->sc_buf, len,
791 (u_int)c, &sc->sc_comp);
792 if (len <= 0)
793 goto error;
794 sc->sc_flags |= SC_COMPRESS;
795 } else
796 goto error;
797 }
798#if NBPFILTER > 0
799 if (sc->sc_bpf) {
800 /*
801 * Put the SLIP pseudo-"link header" in place.
802 * We couldn't do this any earlier since
803 * decompression probably moved the buffer
804 * pointer. Then, invoke BPF.
805 */
806 register u_char *hp = sc->sc_buf - SLIP_HDRLEN;
807
808 hp[SLX_DIR] = SLIPDIR_IN;
809 bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN);
810 bpf_tap(sc->sc_bpf, hp, len + SLIP_HDRLEN);
811 }
812#endif
813 m = sl_btom(sc, len);
814 if (m == NULL)
815 goto error;
816
817 sc->sc_if.if_ipackets++;
818 sc->sc_if.if_lastchange = time;
819 s = splimp();
820 if (IF_QFULL(&ipintrq)) {
821 IF_DROP(&ipintrq);
822 sc->sc_if.if_ierrors++;
823 sc->sc_if.if_iqdrops++;
824 m_freem(m);
825 } else {
826 IF_ENQUEUE(&ipintrq, m);
827 schednetisr(NETISR_IP);
828 }
829 splx(s);
830 goto newpack;
831 }
832 if (sc->sc_mp < sc->sc_ep) {
833 *sc->sc_mp++ = c;
834 sc->sc_escape = 0;
835 return;
836 }
837 sc->sc_flags |= SC_ERROR;
838error:
839 sc->sc_if.if_ierrors++;
840newpack:
841 sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
842 sc->sc_escape = 0;
843}
844
f331c318
GW
845#ifdef experimental
846/*
847 * Get a route change request.
848 * We fill in the MTU and lock it so that MTU discovery won't try
849 * to change it back to the interface MTU.
850 */
851static int
852slrtrequest(int cmd, struct rtentry *rt, struct sockaddr *gate) {
853 if(rt) {
854 rt->rt_rmx.rmx_mtu = SLRMTU;
855 rt->rt_rmx.rmx_locks |= RTV_MTU;
856 }
857}
858#endif
859
15637ed4
RG
860/*
861 * Process an ioctl request.
862 */
f331c318 863int
15637ed4
RG
864slioctl(ifp, cmd, data)
865 register struct ifnet *ifp;
866 int cmd;
867 caddr_t data;
868{
869 register struct ifaddr *ifa = (struct ifaddr *)data;
870 int s = splimp(), error = 0;
871
872 switch (cmd) {
873
f331c318 874 case SIOCAIFADDR:
15637ed4 875 case SIOCSIFADDR:
f331c318 876 if (ifa->ifa_addr->sa_family == AF_INET) {
15637ed4 877 ifp->if_flags |= IFF_UP;
f331c318
GW
878#ifdef experimental
879 ifa->ifa_rtrequest = slrtrequest;
880#endif
881 } else {
15637ed4 882 error = EAFNOSUPPORT;
f331c318 883 }
15637ed4
RG
884 break;
885
886 case SIOCSIFDSTADDR:
887 if (ifa->ifa_addr->sa_family != AF_INET)
888 error = EAFNOSUPPORT;
889 break;
890
891 default:
892 error = EINVAL;
893 }
894 splx(s);
895 return (error);
896}
897#endif