xref: /csrg-svn/sys/net/if_sl.c (revision 26121)
1*26121Skarels /*
2*26121Skarels  * Serial Line interface
3*26121Skarels  *
4*26121Skarels  * Rick Adams
5*26121Skarels  * Center for Seismic Studies
6*26121Skarels  * 1300 N 17th Street, Suite 1450
7*26121Skarels  * Arlington, Virginia 22209
8*26121Skarels  * (703)276-7900
9*26121Skarels  * rick@seismo.ARPA
10*26121Skarels  * seismo!rick
11*26121Skarels  *
12*26121Skarels  * Some things done here could obviously be done in a better way,
13*26121Skarels  * but they were done this way to minimize the number of files
14*26121Skarels  * that had to be changed to accomodate this device.
15*26121Skarels  * A lot of this code belongs in the tty driver.
16*26121Skarels  *
17*26121Skarels  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
18*26121Skarels  * N.B.: this belongs in netinet, not vaxif, the way it stands now.
19*26121Skarels  *
20*26121Skarels  * Converted to 4.3BSD Beta by Chris Torek.
21*26121Skarels  */
22*26121Skarels 
23*26121Skarels /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
24*26121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
25*26121Skarels 
26*26121Skarels #include "sl.h"
27*26121Skarels #if NSL > 0
28*26121Skarels 
29*26121Skarels #include "param.h"
30*26121Skarels #include "mbuf.h"
31*26121Skarels #include "buf.h"
32*26121Skarels #include "socket.h"
33*26121Skarels #include "ioctl.h"
34*26121Skarels #include "tty.h"
35*26121Skarels #include "errno.h"
36*26121Skarels 
37*26121Skarels #include "../net/if.h"
38*26121Skarels #include "../net/netisr.h"
39*26121Skarels #include "../net/route.h"
40*26121Skarels #include "../netinet/in.h"
41*26121Skarels #include "../netinet/in_systm.h"
42*26121Skarels #include "../netinet/ip.h"
43*26121Skarels #include "../netinet/ip_var.h"
44*26121Skarels 
45*26121Skarels #ifdef vax
46*26121Skarels #include "../vax/mtpr.h"
47*26121Skarels #endif vax
48*26121Skarels 
49*26121Skarels /*
50*26121Skarels  * N.B.: SLMTU is now a hard limit on input packet size.  Some limit
51*26121Skarels  * is required, lest we use up all mbufs in the case of deleterious data
52*26121Skarels  * dribbling down the line.
53*26121Skarels  */
54*26121Skarels #define	SLMTU	1006
55*26121Skarels 
56*26121Skarels struct sl_softc {
57*26121Skarels 	struct	ifnet sc_if;	/* network-visible interface */
58*26121Skarels 	short	sc_flags;	/* see below */
59*26121Skarels 	short	sc_ilen;	/* length of input-packet-so-far */
60*26121Skarels 	struct	tty *sc_ttyp;	/* pointer to tty structure */
61*26121Skarels 	char	*sc_mp;		/* pointer to next available buf char */
62*26121Skarels 	char	sc_buf[SLMTU];	/* input buffer */
63*26121Skarels } sl_softc[NSL];
64*26121Skarels 
65*26121Skarels /* flags */
66*26121Skarels #define	SC_ESCAPED	0x0001	/* saw a FRAME_ESCAPE */
67*26121Skarels #define	SC_OACTIVE	0x0002	/* output tty is active */
68*26121Skarels 
69*26121Skarels #define FRAME_END	 	0300		/* Frame End */
70*26121Skarels #define FRAME_ESCAPE		0333		/* Frame Esc */
71*26121Skarels #define TRANS_FRAME_END	 	0334		/* transposed frame end */
72*26121Skarels #define TRANS_FRAME_ESCAPE 	0335		/* transposed frame esc */
73*26121Skarels 
74*26121Skarels #define t_sc T_LINEP
75*26121Skarels 
76*26121Skarels int sloutput(), slioctl(), ttrstrt();
77*26121Skarels 
78*26121Skarels /*
79*26121Skarels  * Called from boot code to establish sl interfaces.
80*26121Skarels  */
81*26121Skarels slattach()
82*26121Skarels {
83*26121Skarels 	register struct sl_softc *sc;
84*26121Skarels 	register int i = 0;
85*26121Skarels 
86*26121Skarels 	for (sc = sl_softc; i < NSL; sc++) {
87*26121Skarels 		sc->sc_if.if_name = "sl";
88*26121Skarels 		sc->sc_if.if_unit = i++;
89*26121Skarels 		sc->sc_if.if_mtu = SLMTU;
90*26121Skarels 		sc->sc_if.if_flags = IFF_POINTOPOINT;
91*26121Skarels 		sc->sc_if.if_ioctl = slioctl;
92*26121Skarels 		sc->sc_if.if_output = sloutput;
93*26121Skarels 		sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
94*26121Skarels 		if_attach(&sc->sc_if);
95*26121Skarels 	}
96*26121Skarels }
97*26121Skarels 
98*26121Skarels /*
99*26121Skarels  * Line specific open routine.
100*26121Skarels  * Attach the given tty to the first available sl unit.
101*26121Skarels  */
102*26121Skarels slopen(dev, tp)
103*26121Skarels 	dev_t dev;
104*26121Skarels 	register struct tty *tp;
105*26121Skarels {
106*26121Skarels 	register struct sl_softc *sc;
107*26121Skarels 	register int nsl;
108*26121Skarels 
109*26121Skarels 	if (tp->t_sc != NULL)
110*26121Skarels 		return (EBUSY);
111*26121Skarels 
112*26121Skarels 	for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++)
113*26121Skarels 		if (sc->sc_ttyp == NULL) {
114*26121Skarels 			sc->sc_flags = 0;
115*26121Skarels 			sc->sc_ilen = 0;
116*26121Skarels 			sc->sc_mp = sc->sc_buf;
117*26121Skarels 			tp->t_sc = (caddr_t)sc;
118*26121Skarels 			sc->sc_ttyp = tp;
119*26121Skarels 			return (0);
120*26121Skarels 		}
121*26121Skarels 
122*26121Skarels 	return (ENOSPC);
123*26121Skarels }
124*26121Skarels 
125*26121Skarels /*
126*26121Skarels  * Line specific close routine.
127*26121Skarels  * Detach the tty from the sl unit.
128*26121Skarels  * Mimics part of ttyclose().
129*26121Skarels  */
130*26121Skarels slclose(tp)
131*26121Skarels 	struct tty *tp;
132*26121Skarels {
133*26121Skarels 	register struct sl_softc *sc;
134*26121Skarels 	int s;
135*26121Skarels 
136*26121Skarels 	ttywflush(tp);
137*26121Skarels 	tp->t_line = 0;
138*26121Skarels 	s = splimp();		/* paranoid; splnet probably ok */
139*26121Skarels 	sc = (struct sl_softc *)tp->t_sc;
140*26121Skarels 	if (sc != NULL) {
141*26121Skarels 		if_down(&sc->sc_if);
142*26121Skarels 		sc->sc_ttyp = NULL;
143*26121Skarels 		tp->t_sc = NULL;
144*26121Skarels 	}
145*26121Skarels 	splx(s);
146*26121Skarels }
147*26121Skarels 
148*26121Skarels /*
149*26121Skarels  * Line specific (tty) ioctl routine.
150*26121Skarels  * Provide a way to get the sl unit number.
151*26121Skarels  */
152*26121Skarels sltioctl(tp, cmd, data, flag)
153*26121Skarels 	struct tty *tp;
154*26121Skarels 	caddr_t data;
155*26121Skarels {
156*26121Skarels 
157*26121Skarels 	if (cmd == TIOCGETD) {
158*26121Skarels 		*(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit;
159*26121Skarels 		return (0);
160*26121Skarels 	}
161*26121Skarels 	return (-1);
162*26121Skarels }
163*26121Skarels 
164*26121Skarels /*
165*26121Skarels  * Queue a packet.  Start transmission if not active.
166*26121Skarels  */
167*26121Skarels sloutput(ifp, m, dst)
168*26121Skarels 	register struct ifnet *ifp;
169*26121Skarels 	register struct mbuf *m;
170*26121Skarels 	struct sockaddr *dst;
171*26121Skarels {
172*26121Skarels 	register struct sl_softc *sc;
173*26121Skarels 	int s;
174*26121Skarels 
175*26121Skarels 	/*
176*26121Skarels 	 * `Cannot happen' (see slioctl).  Someday we will extend
177*26121Skarels 	 * the line protocol to support other address families.
178*26121Skarels 	 */
179*26121Skarels 	if (dst->sa_family != AF_INET) {
180*26121Skarels 		printf("sl%d: af%d not supported\n", ifp->if_unit,
181*26121Skarels 			dst->sa_family);
182*26121Skarels 		m_freem(m);
183*26121Skarels 		return (EAFNOSUPPORT);
184*26121Skarels 	}
185*26121Skarels 
186*26121Skarels 	sc = &sl_softc[ifp->if_unit];
187*26121Skarels 	if (sc->sc_ttyp == NULL) {
188*26121Skarels 		m_freem(m);
189*26121Skarels 		return (ENETDOWN);	/* sort of */
190*26121Skarels 	}
191*26121Skarels 	s = splimp();
192*26121Skarels 	if (IF_QFULL(&ifp->if_snd)) {
193*26121Skarels 		IF_DROP(&ifp->if_snd);
194*26121Skarels 		splx(s);
195*26121Skarels 		m_freem(m);
196*26121Skarels 		sc->sc_if.if_collisions++;
197*26121Skarels 		return (ENOBUFS);
198*26121Skarels 	}
199*26121Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
200*26121Skarels 	if ((sc->sc_flags & SC_OACTIVE) == 0) {
201*26121Skarels 		splx(s);
202*26121Skarels 		slstart(sc->sc_ttyp);
203*26121Skarels 	} else
204*26121Skarels 		splx(s);
205*26121Skarels 	return (0);
206*26121Skarels }
207*26121Skarels 
208*26121Skarels /*
209*26121Skarels  * Start output on interface.  Get another datagram
210*26121Skarels  * to send from the interface queue and map it to
211*26121Skarels  * the interface before starting output.
212*26121Skarels  */
213*26121Skarels slstart(tp)
214*26121Skarels 	register struct tty *tp;
215*26121Skarels {
216*26121Skarels 	register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
217*26121Skarels 	register struct mbuf *m;
218*26121Skarels 	register int c, len;
219*26121Skarels 	register u_char *mcp;
220*26121Skarels 	int flush;
221*26121Skarels 
222*26121Skarels 	/*
223*26121Skarels 	 * If there is more in the output queue, just send it now.
224*26121Skarels 	 * We are being called in lieu of ttstart and must do what
225*26121Skarels 	 * it would.
226*26121Skarels 	 */
227*26121Skarels 	if (tp->t_outq.c_cc > 0) {
228*26121Skarels 		ttstart(tp);
229*26121Skarels 		return;
230*26121Skarels 	}
231*26121Skarels 
232*26121Skarels 	/*
233*26121Skarels 	 * This happens briefly when the line shuts down.
234*26121Skarels 	 */
235*26121Skarels 	if (sc == NULL)
236*26121Skarels 		return;
237*26121Skarels 
238*26121Skarels 	/*
239*26121Skarels 	 * Get a packet and map it to the interface.
240*26121Skarels 	 */
241*26121Skarels 	c = splimp();
242*26121Skarels 	IF_DEQUEUE(&sc->sc_if.if_snd, m);
243*26121Skarels 	if (m == NULL) {
244*26121Skarels 		sc->sc_flags &= ~SC_OACTIVE;
245*26121Skarels 		splx(c);
246*26121Skarels 		return;
247*26121Skarels 	}
248*26121Skarels 	flush = !(sc->sc_flags & SC_OACTIVE);
249*26121Skarels 	sc->sc_flags |= SC_OACTIVE;
250*26121Skarels 	splx(c);
251*26121Skarels 
252*26121Skarels 	/*
253*26121Skarels 	 * The extra FRAME_END will start up a new packet, and thus
254*26121Skarels 	 * will flush any accumulated garbage.  We do this whenever
255*26121Skarels 	 * the line may have been idle for some time.
256*26121Skarels 	 */
257*26121Skarels 	if (flush)
258*26121Skarels 		(void) putc(FRAME_END, &tp->t_outq);
259*26121Skarels 
260*26121Skarels 	while (m != NULL) {
261*26121Skarels 		len = m->m_len;
262*26121Skarels 		mcp = mtod(m, u_char *);
263*26121Skarels 		while (--len >= 0) {
264*26121Skarels 			c = *mcp++;
265*26121Skarels 			if (c == FRAME_ESCAPE || c == FRAME_END) {
266*26121Skarels 				if (putc(FRAME_ESCAPE, &tp->t_outq))
267*26121Skarels 					goto full;
268*26121Skarels 				c = c == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE :
269*26121Skarels 							TRANS_FRAME_END;
270*26121Skarels 				if (putc(c, &tp->t_outq)) {
271*26121Skarels 					(void) unputc(&tp->t_outq);
272*26121Skarels 					goto full;
273*26121Skarels 				}
274*26121Skarels 			} else
275*26121Skarels 				if (putc(c, &tp->t_outq))
276*26121Skarels 					goto full;
277*26121Skarels 		}
278*26121Skarels 		m = m_free(m);
279*26121Skarels 	}
280*26121Skarels 
281*26121Skarels 	if (putc(FRAME_END, &tp->t_outq)) {
282*26121Skarels full:
283*26121Skarels 		/*
284*26121Skarels 		 * If you get many oerrors (more than one or two a day)
285*26121Skarels 		 * you probably do not have enough clists and you should
286*26121Skarels 		 * increase "nclist" in param.c.
287*26121Skarels 		 */
288*26121Skarels 		(void) unputc(&tp->t_outq);	/* make room */
289*26121Skarels 		putc(FRAME_END, &tp->t_outq);	/* end the packet */
290*26121Skarels 		sc->sc_if.if_oerrors++;
291*26121Skarels 	} else
292*26121Skarels 		sc->sc_if.if_opackets++;
293*26121Skarels 
294*26121Skarels 	/*
295*26121Skarels 	 * Start transmission.  Note that slstart, not ttstart, will be
296*26121Skarels 	 * called when the transmission completes, be that after a single
297*26121Skarels 	 * piece of what we have mapped, or be it after the entire thing
298*26121Skarels 	 * has been sent.  That is why we need to check the output queue
299*26121Skarels 	 * count at the top.
300*26121Skarels 	 */
301*26121Skarels 	ttstart(tp);
302*26121Skarels }
303*26121Skarels 
304*26121Skarels /*
305*26121Skarels  * Copy data buffer to mbuf chain; add ifnet pointer ifp.
306*26121Skarels  */
307*26121Skarels struct mbuf *
308*26121Skarels sl_btom(addr, len, ifp)
309*26121Skarels 	register caddr_t addr;
310*26121Skarels 	register int len;
311*26121Skarels 	struct ifnet *ifp;
312*26121Skarels {
313*26121Skarels 	register struct mbuf *m, **mp;
314*26121Skarels 	register int count;
315*26121Skarels 	struct mbuf *top = NULL;
316*26121Skarels 
317*26121Skarels 	mp = &top;
318*26121Skarels 	while (len > 0) {
319*26121Skarels 		MGET(m, M_DONTWAIT, MT_DATA);
320*26121Skarels 		if ((*mp = m) == NULL) {
321*26121Skarels 			m_freem(top);
322*26121Skarels 			return (NULL);
323*26121Skarels 		}
324*26121Skarels 		if (ifp) {
325*26121Skarels 			m->m_off += sizeof(ifp);
326*26121Skarels 			count = MIN(len, MLEN - sizeof(ifp));
327*26121Skarels 		} else {
328*26121Skarels 			if (len >= NBPG) {
329*26121Skarels 				struct mbuf *p;
330*26121Skarels 
331*26121Skarels 				MCLGET(p, 1);
332*26121Skarels 				if (p != NULL) {
333*26121Skarels 					count = MIN(len, CLBYTES);
334*26121Skarels 					m->m_off = (int)p - (int)m;
335*26121Skarels 				} else
336*26121Skarels 					count = MIN(len, MLEN);
337*26121Skarels 			} else
338*26121Skarels 				count = MIN(len, MLEN);
339*26121Skarels 		}
340*26121Skarels 		bcopy(addr, mtod(m, caddr_t), count);
341*26121Skarels 		m->m_len = count;
342*26121Skarels 		if (ifp) {
343*26121Skarels 			m->m_off -= sizeof(ifp);
344*26121Skarels 			m->m_len += sizeof(ifp);
345*26121Skarels 			*mtod(m, struct ifnet **) = ifp;
346*26121Skarels 			ifp = NULL;
347*26121Skarels 		}
348*26121Skarels 		addr += count;
349*26121Skarels 		len -= count;
350*26121Skarels 		mp = &m->m_next;
351*26121Skarels 	}
352*26121Skarels 	return (top);
353*26121Skarels }
354*26121Skarels 
355*26121Skarels /*
356*26121Skarels  * tty interface receiver interrupt.
357*26121Skarels  */
358*26121Skarels slinput(c, tp)
359*26121Skarels 	register int c;
360*26121Skarels 	register struct tty *tp;
361*26121Skarels {
362*26121Skarels 	register struct sl_softc *sc;
363*26121Skarels 	register struct mbuf *m;
364*26121Skarels 	int s;
365*26121Skarels 
366*26121Skarels 	sc = (struct sl_softc *)tp->t_sc;
367*26121Skarels 	if (sc == NULL)
368*26121Skarels 		return;
369*26121Skarels 
370*26121Skarels 	c &= 0xff;
371*26121Skarels 	if (sc->sc_flags & SC_ESCAPED) {
372*26121Skarels 		sc->sc_flags &= ~SC_ESCAPED;
373*26121Skarels 		switch (c) {
374*26121Skarels 
375*26121Skarels 		case TRANS_FRAME_ESCAPE:
376*26121Skarels 			c = FRAME_ESCAPE;
377*26121Skarels 			break;
378*26121Skarels 
379*26121Skarels 		case TRANS_FRAME_END:
380*26121Skarels 			c = FRAME_END;
381*26121Skarels 			break;
382*26121Skarels 
383*26121Skarels 		default:
384*26121Skarels 			sc->sc_if.if_ierrors++;
385*26121Skarels 			sc->sc_mp = sc->sc_buf;
386*26121Skarels 			sc->sc_ilen = 0;
387*26121Skarels 			return;
388*26121Skarels 		}
389*26121Skarels 	} else {
390*26121Skarels 		switch (c) {
391*26121Skarels 
392*26121Skarels 		case FRAME_END:
393*26121Skarels 			if (sc->sc_ilen == 0)	/* ignore */
394*26121Skarels 				return;
395*26121Skarels 			m = sl_btom(sc->sc_buf, sc->sc_ilen, &sc->sc_if);
396*26121Skarels 			if (m == NULL) {
397*26121Skarels 				sc->sc_if.if_ierrors++;
398*26121Skarels 				return;
399*26121Skarels 			}
400*26121Skarels 			sc->sc_mp = sc->sc_buf;
401*26121Skarels 			sc->sc_ilen = 0;
402*26121Skarels 			sc->sc_if.if_ipackets++;
403*26121Skarels 			s = splimp();
404*26121Skarels 			if (IF_QFULL(&ipintrq)) {
405*26121Skarels 				IF_DROP(&ipintrq);
406*26121Skarels 				sc->sc_if.if_ierrors++;
407*26121Skarels 				m_freem(m);
408*26121Skarels 			} else {
409*26121Skarels 				IF_ENQUEUE(&ipintrq, m);
410*26121Skarels 				schednetisr(NETISR_IP);
411*26121Skarels 			}
412*26121Skarels 			splx(s);
413*26121Skarels 			return;
414*26121Skarels 
415*26121Skarels 		case FRAME_ESCAPE:
416*26121Skarels 			sc->sc_flags |= SC_ESCAPED;
417*26121Skarels 			return;
418*26121Skarels 		}
419*26121Skarels 	}
420*26121Skarels 	if (++sc->sc_ilen >= SLMTU) {
421*26121Skarels 		sc->sc_if.if_ierrors++;
422*26121Skarels 		sc->sc_mp = sc->sc_buf;
423*26121Skarels 		sc->sc_ilen = 0;
424*26121Skarels 		return;
425*26121Skarels 	}
426*26121Skarels 	*sc->sc_mp++ = c;
427*26121Skarels }
428*26121Skarels 
429*26121Skarels /*
430*26121Skarels  * Process an ioctl request.
431*26121Skarels  */
432*26121Skarels slioctl(ifp, cmd, data)
433*26121Skarels 	register struct ifnet *ifp;
434*26121Skarels 	int cmd;
435*26121Skarels 	caddr_t data;
436*26121Skarels {
437*26121Skarels 	register struct ifaddr *ifa = (struct ifaddr *)data;
438*26121Skarels 	int s = splimp(), error = 0;
439*26121Skarels 
440*26121Skarels 	switch (cmd) {
441*26121Skarels 
442*26121Skarels 	case SIOCSIFADDR:
443*26121Skarels 		if (ifa->ifa_addr.sa_family == AF_INET)
444*26121Skarels 			ifp->if_flags |= IFF_UP;
445*26121Skarels 		else
446*26121Skarels 			error = EAFNOSUPPORT;
447*26121Skarels 		break;
448*26121Skarels 
449*26121Skarels 	case SIOCSIFDSTADDR:
450*26121Skarels 		if (ifa->ifa_addr.sa_family != AF_INET)
451*26121Skarels 			error = EAFNOSUPPORT;
452*26121Skarels 		break;
453*26121Skarels 
454*26121Skarels 	default:
455*26121Skarels 		error = EINVAL;
456*26121Skarels 	}
457*26121Skarels 	splx(s);
458*26121Skarels 	return (error);
459*26121Skarels }
460*26121Skarels #endif
461