File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / tahoeif / tty_if_sl.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:29:50 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

/*
 *	Serial Line interface
 *	Modified for Power 6/32. 10/05/84
 *
 *	Rick Adams
 *	Center for Seismic Studies
 *	1300 N 17th Street, Suite 1450
 *	Arlington, Virginia 22209
 *	(703)276-7900
 *	[email protected]
 *	seismo!rick
 *
 *	Some things done here could obviously be done in a better way,
 *	but they were done this way to minimize the number of files
 *	that had to be changed to accomodate this device.
 *	A lot of this code belongs in the tty driver.
 */

#include "vx.h"
#if NVX > 0
long vxstart();
long vxparam();
#endif NVX

#include "sl.h"
#if NSL > 0

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/mbuf.h"
#include "../h/buf.h"
#include "../h/protosw.h"
/*#include "../h/socket.h"*/
#include "../h/vmmac.h"
#include "../h/errno.h"
#include "../h/ioctl.h"
#include "../h/tty.h"

#include "../net/netisr.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/ip.h"
#include "../netinet/ip_var.h"

#include "../tahoe/mtpr.h"

#define	SLINES	(NSL*16)
struct sl_softc sl_softc[SLINES];

#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 */

#define SLTU	1500

int sloutput(), slioctl();

/*------------- debugging tools -------------*/
#ifdef SL_DEBUG
int	slprintfs;
#define	SLOPEN		1
#define	SLOUTPUT	2
#define	SLINPUT		4
#define	SLSTART		8
#define	SLALL		(SLOPEN | SLOUTPUT | SLINPUT | SLSTART)
#define SL_TRACE(X,Y)	{if (slprintfs & X) Y}
#else SL_DEBUG
#define SL_TRACE(X,Y)
#endif SL_DEBUG
/*
 * Changes:
 *	.	reset sc_m when enqueueing messages to IP input queue.
 *	.	reset sc_m when deallocating sc_m if cannot allocate
 *		more mbufs.
 *	.	restore ipl() before returning from slstart() when 
 *		sc_ttyp is NULL.
 *	.	fix the window in slstart() by changing sc_oactive
 *		with high ipl() so that slstart() would not be re-entered
 *		when tcp time-out occurs.
 *	.	slstart() transmits another packet when done with one.
 *
 *	.	when putc() fails, slstart() "backspaces" in such
 *		a way that the FRAME_END is never preceeded by 
 *		FRAME_ESCAPE. Otherwise, FRAME_ESCAPE could preceed
 *		FRAME_END and causes the receiver to concatenate two
 *		packets when packetizing input stream.
 */
/*
 * Routine called when the serial line IP line discipline is entered.
 * In effect, this also acts as "slattach", except it's not called at
 * autoconfigure time but when the serial line is enabled for networking.
 */
slopen(dev, tp)
	dev_t dev;
	register struct tty *tp;
{
	register struct sl_softc *sc = sl_softc;
	register struct sockaddr_in *sin;
	register int nsl;
	extern int ifqmaxlen;
	int addloop = 0;

	if (tp->t_slsoftc)
		return EBUSY;

	for (nsl = 0; sc->sc_ttyp;) {
		if (++nsl >= SLINES)
			return(ENOSPC);
		sc++;
	}

	/* This is a real kludge. Since we do the attach in the rc file,
	   the loopback driver gets configured first. Now Berkeley, in its
	   infinite wisdom, when connecting to a machine through a gateway,
	   chooses the FIRST interface on its list. Guess what that is when you
	   don't have an ethernet? That's right! It's the loopback driver!
	   The following crock is an attempt to get around that.
	 */

	if ( ifnet && ifnet->if_name[0] == 'l' && ifnet->if_name[1] == 'o'
		&& ifnet->if_name[2] == '\0') {
		/* the loopback device is configured in first */
		ifnet = ifnet->if_next;
		addloop++;
	}
	SL_TRACE(SLOPEN,
		printf("sl%lx open:tty(%lx):softc(%lx)\n",
					nsl,(long)tp,(long)sc);)
	tp->t_slsoftc = (struct sl_softc *)sc;
	sc->sc_ttyp = tp;
	sc->sc_if.if_unit = nsl;
	sc->sc_if.if_name = "sl";
	sc->sc_if.if_mtu = SLTU;
	sc->sc_if.if_output = sloutput;
	sc->sc_if.if_ioctl = slioctl;
	sc->sc_if.if_flags = IFF_POINTOPOINT;
	sc->sc_if.if_oerrors = sc->sc_if.if_ierrors = 0;
	sc->sc_if.if_opackets = sc->sc_if.if_ipackets = 0;
	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
	if_attach(&sc->sc_if);

	if (addloop)
		loattach();

	return 0;
}

/*ARGSUSED*/
sltioctl(tp, cmd, data, flag)
	struct tty *tp;
	caddr_t data;
{
	register struct sl_softc *sc = (struct sl_softc *)tp->t_slsoftc;

	/*
	 * This is done this way, because we want these attributes to
	 * be present AFTER the user program closes the line.
	 */
	if (cmd == TIOCGETD) {
		*(int *)data = (int)sc->sc_if.if_unit;
		tp->t_state &= ~TS_HUPCLS;
		tp->t_flags |= NOHANG;
		sc->sc_ttyspeed = tp->t_ispeed;
		return 0;
	}
	return EINVAL;
}

sloutput(ifp, m, dst)
	register struct ifnet *ifp;
	register struct mbuf *m;
	struct sockaddr *dst;
{
	int s;

	SL_TRACE(SLOUTPUT, printf("sl%lx: output\n",ifp->if_unit);)
	if (dst->sa_family != AF_INET) {
		printf("sl%d: af%d not supported\n", ifp->if_unit,
			dst->sa_family);
		m_freem(m);
		return (EAFNOSUPPORT);
	}
	s = splimp();
	if (IF_QFULL(&ifp->if_snd)) {
		IF_DROP(&ifp->if_snd);
		m_freem(m);
		splx(s);
		sl_softc[ifp->if_unit].sc_if.if_collisions++;
		return (ENOBUFS);
	}
	IF_ENQUEUE(&ifp->if_snd, m);
	if (sl_softc[ifp->if_unit].sc_oactive == 0)
		slstart(ifp->if_unit, s);	/* slstart does an splx(s) */
	else
		splx(s);
	return (0);
}

/*
 * Start output on interface.  Get another datagram
 * to send from the interface queue and map it to
 * the interface before starting output.
 */
slstart(n, s)
	int n, s;
{
	register struct sl_softc *sc = &sl_softc[n];
	register struct tty *tp;
	struct mbuf *m, *mp;

	tp = sc->sc_ttyp;
	if (tp == NULL) {
		printf("sl%d: sc_ttyp is NULL\n", n);
		splx(s);
		return;
	}
next:
	sc->sc_oactive = 1;
	IF_DEQUEUE(&sc->sc_if.if_snd, m);
	if (m == 0) {
		sc->sc_oactive = 0;
		splx(s);
		return;
	}
	splx(s);

	SL_TRACE(SLSTART,printf("slstart %lx\n", tp);)
	for (mp = m; mp; mp = mp->m_next) {
		register unsigned len = mp->m_len;
		register u_char *mcp;
		u_char c;

		mcp = mtod(mp, u_char *);
		while (len--) {
			c = *mcp++;
			if (c == FRAME_ESCAPE || c == FRAME_END) {
				if (putc(FRAME_ESCAPE, &tp->t_outq))
					goto full;
				c = c == FRAME_ESCAPE ?
					TRANS_FRAME_ESCAPE : TRANS_FRAME_END;
			}
			if (putc(c, &tp->t_outq))
				goto full;
		}
	}
	if (putc(FRAME_END, &tp->t_outq)) {
full:
		SL_TRACE(SLSTART,printf("slstart: line is full\n");)
		/*
		 * If you get many oerrors (more than 1 or two a day),
		 * you probably do not have enough clists and you should 
		 * increase the number of them.
		 */
		m_freem(m);
		(void) unputc(&tp->t_outq);	/* make some space */
		(void) unputc(&tp->t_outq);	/* make some space */
		putc('\0', &tp->t_outq);	/* end the packet */
		putc(FRAME_END, &tp->t_outq);	/* end the packet */
		sc->sc_if.if_oerrors++;
		sc->sc_oactive = 0;
		ttstart(tp);
		return EIO;
	}
	m_freem(m);
	ttstart(tp);
	sc->sc_if.if_opackets++;

	s = splimp();
	sc->sc_oactive = 0;
	splx(s);

/*	s = splimp();
/*	goto next;
/**/
}

/*
 * tty interface receiver interrupt.
 */
slinput(c, tp)
register c;
register struct tty *tp;
{
	register struct sl_softc *sc;
	register struct mbuf *m;
	register struct ifqueue *inq;
	register int s;

	SL_TRACE(SLINPUT, printf("slinput %x,", c & 0xff);)
	sc = (struct sl_softc *)tp->t_slsoftc;
	if (sc == NULL) {
		printf("sl: t_slsoftc is NULL,tty %lx\n",(long)tp);
		return;
	}
	c &= 0xff;
	if (sc->sc_escaped) {
		sc->sc_escaped = 0;
		switch(c) {
		case TRANS_FRAME_ESCAPE:
			c = FRAME_ESCAPE;
			break;
		case TRANS_FRAME_END:
			c = FRAME_END;
			break;
		default:
			sc->sc_if.if_ierrors++;
			return;
		}
	} else {
		switch(c) {
		case FRAME_END:
			if (sc->sc_mt == 0) {
				sc->sc_if.if_ierrors++;
				return;
			}
			sc->sc_if.if_ipackets++;
			sc->sc_mt->m_len -= sc->sc_len;
			schednetisr(NETISR_IP);
			inq = &ipintrq;

			s = splimp();
			if (IF_QFULL(inq)) {
				IF_DROP(inq);
				sc->sc_if.if_ierrors++;
				m_freem(sc->sc_m);
			} else
				IF_ENQUEUE(inq, sc->sc_m);
			splx(s);
			sc->sc_m = sc->sc_mt = 0;
			sc->sc_len = 0;
			return;
		case FRAME_ESCAPE:
			sc->sc_escaped = 1;
			return;
		}
	}
	if (sc->sc_len <= 0) {	/* have to get more buffer space */
		struct mbuf *mm;
		MGET(mm, M_DONTWAIT, MT_DATA);
		MBUFNULL(34, mm);	/* for debugging */
		if (mm == 0) {
			m_freem(sc->sc_m);
			sc->sc_m = sc->sc_mt = 0;
			sc->sc_len = 0;
			sc->sc_if.if_collisions++;
			return;
		}
		if (sc->sc_mt == 0) {
			sc->sc_mt = sc->sc_m = mm;
		} else {
			sc->sc_mt->m_next = mm;
			sc->sc_mt = mm;
		}
		sc->sc_len = mm->m_len = MLEN;
		sc->sc_mp = mtod(mm, u_char *);
	}

	*sc->sc_mp++ = c;
	sc->sc_len--;
}

/*
 * Process an ioctl request.
 */
slioctl(ifp, cmd, data)
	register struct ifnet *ifp;
	int cmd;
	caddr_t data;
{
	struct tty *tp;
	struct sockaddr_in *sin;
	struct sl_softc *sc;
	struct rtentry route;
	int s = splimp(), error = 0;
	register struct ifreq *ifr = (struct ifreq *)data;



	switch (cmd) {

	case SIOCSIFADDR:
		if (ifp->if_flags & IFF_RUNNING)
			if_rtinit(ifp, -1);	/* delete previous route */
		sin = (struct sockaddr_in *)&ifr->ifr_addr;
		ifp->if_addr = *(struct sockaddr *)sin;
		sin = (struct sockaddr_in *)&ifp->if_dstaddr;
		ifp->if_net = in_netof(sin->sin_addr);
		ifp->if_flags |= IFF_UP | IFF_RUNNING;
		/* set up routing table entry */
		if ((ifp->if_flags & IFF_ROUTE) == 0) {
			rtinit(&ifp->if_dstaddr, &ifp->if_addr,
				ifp, RTF_HOST|RTF_UP);
			ifp->if_flags |= IFF_ROUTE;
		}
		/*
		 * Since the way a tty line is attached as a network interface
		 * is to open it, do an "ioctl" to attach it, and close it,
		 * and since the close will reset the line discipline, we
		 * must set the line discipline here.
		 */
		sc = &sl_softc[ifp->if_unit];
		tp = sc->sc_ttyp;
		tp->t_line = SLIPDISC;
		tp->t_flags = RAW|EVENP|ODDP;
		tp->t_ispeed = tp->t_ospeed = sc->sc_ttyspeed;

		/* Unfortunately, the tty driver does not have any
		 * way of jumping directly to the correct param routine
		 * so, to get the line set to the correct baudrate
		 * we are forced to use the following kludge
		 * (Fortunately, it is only called once per line)
		 * THIS CAN BE FIXED WITH THE SYSTEM V RELEASE 2
		 * TTY DRIVER, WHICH DOES HAVE A t_proc ARGUMENT FOR
		 * DO A "param".
		 */
#if NVX > 0
		if (tp->t_oproc == vxstart)
			vxparam(tp->t_dev);
		else
#endif NVX
		{
			printf("Serial line attach: Unknown device\n");
			error = ENODEV;
		}
		break;

	case SIOCSIFDSTADDR:
		sin = (struct sockaddr_in *)&ifr->ifr_dstaddr;
		ifp->if_dstaddr = *(struct sockaddr *)sin;
		break;

	case SIOCIFDETACH:
		bzero((caddr_t)&route, sizeof (route));
		route.rt_dst = ifp->if_dstaddr;
		route.rt_gateway = ifp->if_addr;
		route.rt_flags = RTF_HOST | RTF_UP;
		(void) rtrequest(SIOCDELRT, &route);
		if_detach(ifp);
		sc = &sl_softc[ifp->if_unit];
		tp = sc->sc_ttyp;
		tp->t_slsoftc = 0;
		sc->sc_ttyp = 0;
		ttyclose(tp);
		break;

	default:
		error = EINVAL;
	}
	splx(s);
	return (error);
}
#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.