* Copyright (c) 1987 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
* @(#)if_sl.c 7.6 (Berkeley) %G%
* Center for Seismic Studies
* 1300 N 17th Street, Suite 1450
* Arlington, Virginia 22209
* Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
* N.B.: this belongs in netinet, not net, the way it stands now.
* Should have a link-layer type designation, but wouldn't be
* Converted to 4.3BSD Beta by Chris Torek.
* Other changes made at Berkeley, based in part on code by Kirk Smith.
/* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/in_var.h"
#include "../netinet/ip.h"
#include "../machine/mtpr.h"
* N.B.: SLMTU is now a hard limit on input packet size.
* SLMTU must be <= CLBYTES - sizeof(struct ifnet *).
#define SLIP_HIWAT 1000 /* don't start a new packet if HIWAT on queue */
#define CLISTRESERVE 1000 /* Can't let clists get too low */
struct ifnet sc_if
; /* network-visible interface */
short sc_flags
; /* see below */
short sc_ilen
; /* length of input-packet-so-far */
struct tty
*sc_ttyp
; /* pointer to tty structure */
char *sc_mp
; /* pointer to next available buf char */
char *sc_buf
; /* input buffer */
#define SC_ESCAPED 0x0001 /* saw a FRAME_ESCAPE */
#define SC_OACTIVE 0x0002 /* output tty is active */
#define FRAME_END 0300 /* Frame End */
#define FRAME_ESCAPE 0333 /* Frame Esc */
#define TRANS_FRAME_END 0334 /* transposed frame end */
#define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */
int sloutput(), slioctl(), ttrstrt();
* Called from boot code to establish sl interfaces.
register struct sl_softc
*sc
;
for (sc
= sl_softc
; i
< NSL
; sc
++) {
sc
->sc_if
.if_name
= "sl";
sc
->sc_if
.if_mtu
= SLMTU
;
sc
->sc_if
.if_flags
= IFF_POINTOPOINT
;
sc
->sc_if
.if_ioctl
= slioctl
;
sc
->sc_if
.if_output
= sloutput
;
sc
->sc_if
.if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
* Line specific open routine.
* Attach the given tty to the first available sl unit.
register struct sl_softc
*sc
;
if (tp
->t_line
== SLIPDISC
)
for (nsl
= 0, sc
= sl_softc
; nsl
< NSL
; nsl
++, sc
++)
if (sc
->sc_ttyp
== NULL
) {
ttyflush(tp
, FREAD
| FWRITE
);
* Line specific close routine.
* Detach the tty from the sl unit.
* Mimics part of ttyclose().
register struct sl_softc
*sc
;
s
= splimp(); /* paranoid; splnet probably ok */
sc
= (struct sl_softc
*)tp
->t_sc
;
MCLFREE((struct mbuf
*)sc
->sc_buf
);
* Line specific (tty) ioctl routine.
* Provide a way to get the sl unit number.
sltioctl(tp
, cmd
, data
, flag
)
*(int *)data
= ((struct sl_softc
*)tp
->t_sc
)->sc_if
.if_unit
;
* Queue a packet. Start transmission if not active.
register struct ifnet
*ifp
;
register struct sl_softc
*sc
;
* `Cannot happen' (see slioctl). Someday we will extend
* the line protocol to support other address families.
if (dst
->sa_family
!= AF_INET
) {
printf("sl%d: af%d not supported\n", ifp
->if_unit
,
sc
= &sl_softc
[ifp
->if_unit
];
if (sc
->sc_ttyp
== NULL
) {
return (ENETDOWN
); /* sort of */
if ((sc
->sc_ttyp
->t_state
& TS_CARR_ON
) == 0) {
if (IF_QFULL(&ifp
->if_snd
)) {
IF_ENQUEUE(&ifp
->if_snd
, m
);
if ((sc
->sc_flags
& SC_OACTIVE
) == 0) {
* Start output on interface. Get another datagram
* to send from the interface queue and map it to
* the interface before starting output.
register struct sl_softc
*sc
= (struct sl_softc
*)tp
->t_sc
;
* If there is more in the output queue, just send it now.
* We are being called in lieu of ttstart and must do what
if (tp
->t_outq
.c_cc
> SLIP_HIWAT
)
* This happens briefly when the line shuts down.
* If system is getting low on clists
* and we have something running already, stop here.
if (cfreecount
< CLISTRESERVE
+ SLMTU
&&
sc
->sc_flags
& SC_OACTIVE
)
* Get a packet and send it to the interface.
IF_DEQUEUE(&sc
->sc_if
.if_snd
, m
);
if (tp
->t_outq
.c_cc
== 0)
sc
->sc_flags
&= ~SC_OACTIVE
;
flush
= !(sc
->sc_flags
& SC_OACTIVE
);
sc
->sc_flags
|= SC_OACTIVE
;
* The extra FRAME_END will start up a new packet, and thus
* will flush any accumulated garbage. We do this whenever
* the line may have been idle for some time.
(void) putc(FRAME_END
, &tp
->t_outq
);
* Find out how many bytes in the string we can
* handle without doing something special.
nd
= locc(FRAME_ESCAPE
, len
, cp
);
np
= locc(FRAME_END
, len
, cp
);
* Put n characters at once
* into the tty output queue.
if (b_to_q((char *)cp
, n
, &tp
->t_outq
))
* If there are characters left in the mbuf,
* the first one must be special..
* Put it out in a different form.
if (putc(FRAME_ESCAPE
, &tp
->t_outq
))
if (putc(*cp
== FRAME_ESCAPE
?
TRANS_FRAME_ESCAPE
: TRANS_FRAME_END
,
(void) unputc(&tp
->t_outq
);
if (putc(FRAME_END
, &tp
->t_outq
)) {
* Not enough room. Remove a char to make room
* and end the packet normally.
* If you get many collisions (more than one or two
* a day) you probably do not have enough clists
* and you should increase "nclist" in param.c.
(void) unputc(&tp
->t_outq
);
(void) putc(FRAME_END
, &tp
->t_outq
);
sc
->sc_if
.if_collisions
++;
register struct sl_softc
*sc
;
if (sc
->sc_buf
== (char *) 0) {
sc
->sc_mp
= sc
->sc_buf
+ sizeof(struct ifnet
*);
printf("sl%d: can't allocate buffer\n", sc
- sl_softc
);
sc
->sc_if
.if_flags
&= ~IFF_UP
;
* Copy data buffer to mbuf chain; add ifnet pointer ifp.
register struct mbuf
*m
, **mp
;
cp
= sc
->sc_buf
+ sizeof(struct ifnet
*);
MGET(m
, M_DONTWAIT
, MT_DATA
);
* If we have at least NBPG bytes,
* allocate a new page. Swap the current buffer page
* with the new one. We depend on having a space
* left at the beginning of the buffer
* for the interface pointer.
if (m
->m_len
== CLBYTES
) {
m
->m_off
= (int)sc
->sc_buf
- (int)m
;
CLBYTES
- sizeof(struct ifnet
*));
count
= MIN(len
, CLBYTES
);
count
= MIN(len
, MLEN
- sizeof(ifp
));
bcopy(cp
, mtod(m
, caddr_t
), count
);
*mtod(m
, struct ifnet
**) = ifp
;
* tty interface receiver interrupt.
register struct sl_softc
*sc
;
sc
= (struct sl_softc
*)tp
->t_sc
;
if (sc
->sc_flags
& SC_ESCAPED
) {
sc
->sc_flags
&= ~SC_ESCAPED
;
sc
->sc_mp
= sc
->sc_buf
+ sizeof(struct ifnet
*);
if (sc
->sc_ilen
== 0) /* ignore */
m
= sl_btom(sc
, sc
->sc_ilen
, &sc
->sc_if
);
sc
->sc_mp
= sc
->sc_buf
+ sizeof(struct ifnet
*);
if (IF_QFULL(&ipintrq
)) {
sc
->sc_flags
|= SC_ESCAPED
;
if (++sc
->sc_ilen
> SLMTU
) {
sc
->sc_mp
= sc
->sc_buf
+ sizeof(struct ifnet
*);
* Process an ioctl request.
register struct ifnet
*ifp
;
register struct ifaddr
*ifa
= (struct ifaddr
*)data
;
int s
= splimp(), error
= 0;
if (ifa
->ifa_addr
.sa_family
== AF_INET
)
if (ifa
->ifa_addr
.sa_family
!= AF_INET
)