|
|
1.1 root 1: /*
2: * Serial Line interface
3: * Modified for Power 6/32. 10/05/84
4: *
5: * Rick Adams
6: * Center for Seismic Studies
7: * 1300 N 17th Street, Suite 1450
8: * Arlington, Virginia 22209
9: * (703)276-7900
10: * [email protected]
11: * seismo!rick
12: *
13: * Some things done here could obviously be done in a better way,
14: * but they were done this way to minimize the number of files
15: * that had to be changed to accomodate this device.
16: * A lot of this code belongs in the tty driver.
17: */
18:
19: #include "vx.h"
20: #if NVX > 0
21: long vxstart();
22: long vxparam();
23: #endif NVX
24:
25: #include "sl.h"
26: #if NSL > 0
27:
28: #include "../h/param.h"
29: #include "../h/systm.h"
30: #include "../h/mbuf.h"
31: #include "../h/buf.h"
32: #include "../h/protosw.h"
33: /*#include "../h/socket.h"*/
34: #include "../h/vmmac.h"
35: #include "../h/errno.h"
36: #include "../h/ioctl.h"
37: #include "../h/tty.h"
38:
39: #include "../net/netisr.h"
40: #include "../net/route.h"
41: #include "../netinet/in.h"
42: #include "../netinet/in_systm.h"
43: #include "../netinet/ip.h"
44: #include "../netinet/ip_var.h"
45:
46: #include "../tahoe/mtpr.h"
47:
48: #define SLINES (NSL*8)
49: struct sl_softc sl_softc[SLINES];
50:
51: #define FRAME_END 0300 /* Frame End */
52: #define FRAME_ESCAPE 0333 /* Frame Esc */
53: #define TRANS_FRAME_END 0334 /* transposed frame end */
54: #define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */
55:
56: #define SLTU 1500
57:
58: int sloutput(), slioctl();
59:
60: /*------------- debugging tools -------------*/
61: #ifdef SL_DEBUG
62: int slprintfs;
63: #define SLOPEN 1
64: #define SLOUTPUT 2
65: #define SLINPUT 4
66: #define SLSTART 8
67: #define SLALL (SLOPEN | SLOUTPUT | SLINPUT | SLSTART)
68: #define SL_TRACE(X,Y) {if (slprintfs & X) Y}
69: #else SL_DEBUG
70: #define SL_TRACE(X,Y)
71: #endif SL_DEBUG
72: /*
73: * Changes:
74: * . reset sc_m when enqueueing messages to IP input queue.
75: * . reset sc_m when deallocating sc_m if cannot allocate
76: * more mbufs.
77: * . restore ipl() before returning from slstart() when
78: * sc_ttyp is NULL.
79: * . fix the window in slstart() by changing sc_oactive
80: * with high ipl() so that slstart() would not be re-entered
81: * when tcp time-out occurs.
82: * . slstart() transmits another packet when done with one.
83: *
84: * . when putc() fails, slstart() "backspaces" in such
85: * a way that the FRAME_END is never preceeded by
86: * FRAME_ESCAPE. Otherwise, FRAME_ESCAPE could preceed
87: * FRAME_END and causes the receiver to concatenate two
88: * packets when packetizing input stream.
89: */
90: /*
91: * Routine called when the serial line IP line discipline is entered.
92: * In effect, this also acts as "slattach", except it's not called at
93: * autoconfigure time but when the serial line is enabled for networking.
94: */
95: slopen(dev, tp)
96: dev_t dev;
97: register struct tty *tp;
98: {
99: register struct sl_softc *sc = sl_softc;
100: register struct sockaddr_in *sin;
101: register int nsl;
102: extern int ifqmaxlen;
103: int addloop = 0;
104:
105: if (tp->t_slsoftc)
106: return EBUSY;
107:
108: for (nsl = 0; sc->sc_ttyp;) {
109: if (++nsl >= SLINES)
110: return(ENOSPC);
111: sc++;
112: }
113:
114: /* This is a real kludge. Since we do the attach in the rc file,
115: the loopback driver gets configured first. Now Berkeley, in its
116: infinite wisdom, when connecting to a machine through a gateway,
117: chooses the FIRST interface on its list. Guess what that is when you
118: don't have an ethernet? That's right! It's the loopback driver!
119: The following crock is an attempt to get around that.
120: */
121:
122: if ( ifnet && ifnet->if_name[0] == 'l' && ifnet->if_name[1] == 'o'
123: && ifnet->if_name[2] == '\0') {
124: /* the loopback device is configured in first */
125: ifnet = ifnet->if_next;
126: addloop++;
127: }
128: SL_TRACE(SLOPEN,
129: printf("sl%lx open:tty(%lx):softc(%lx)\n",
130: nsl,(long)tp,(long)sc);)
131: tp->t_slsoftc = (struct sl_softc *)sc;
132: sc->sc_ttyp = tp;
133: sc->sc_if.if_unit = nsl;
134: sc->sc_if.if_name = "sl";
135: sc->sc_if.if_mtu = SLTU;
136: sc->sc_if.if_output = sloutput;
137: sc->sc_if.if_ioctl = slioctl;
138: sc->sc_if.if_flags = IFF_POINTOPOINT;
139: sc->sc_if.if_oerrors = sc->sc_if.if_ierrors = 0;
140: sc->sc_if.if_opackets = sc->sc_if.if_ipackets = 0;
141: sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
142: if_attach(&sc->sc_if);
143:
144: if (addloop)
145: loattach();
146:
147: return 0;
148: }
149:
150: /*ARGSUSED*/
151: sltioctl(tp, cmd, data, flag)
152: struct tty *tp;
153: caddr_t data;
154: {
155: register struct sl_softc *sc = (struct sl_softc *)tp->t_slsoftc;
156:
157: /*
158: * This is done this way, because we want these attributes to
159: * be present AFTER the user program closes the line.
160: */
161: if (cmd == TIOCGETD) {
162: *(int *)data = (int)sc->sc_if.if_unit;
163: tp->t_state &= ~TS_HUPCLS;
164: tp->t_flags |= NOHANG;
165: sc->sc_ttyspeed = tp->t_ispeed;
166: return 0;
167: }
168: return EINVAL;
169: }
170:
171: sloutput(ifp, m, dst)
172: register struct ifnet *ifp;
173: register struct mbuf *m;
174: struct sockaddr *dst;
175: {
176: int s;
177:
178: SL_TRACE(SLOUTPUT, printf("sl%lx: output\n",ifp->if_unit);)
179: if (dst->sa_family != AF_INET) {
180: printf("sl%d: af%d not supported\n", ifp->if_unit,
181: dst->sa_family);
182: m_freem(m);
183: return (EAFNOSUPPORT);
184: }
185: s = splimp();
186: if (IF_QFULL(&ifp->if_snd)) {
187: IF_DROP(&ifp->if_snd);
188: m_freem(m);
189: splx(s);
190: sl_softc[ifp->if_unit].sc_if.if_collisions++;
191: return (ENOBUFS);
192: }
193: IF_ENQUEUE(&ifp->if_snd, m);
194: if (sl_softc[ifp->if_unit].sc_oactive == 0)
195: slstart(ifp->if_unit, s); /* slstart does an splx(s) */
196: else
197: splx(s);
198: return (0);
199: }
200:
201: /*
202: * Start output on interface. Get another datagram
203: * to send from the interface queue and map it to
204: * the interface before starting output.
205: */
206: slstart(n, s)
207: int n, s;
208: {
209: register struct sl_softc *sc = &sl_softc[n];
210: register struct tty *tp;
211: struct mbuf *m, *mp;
212:
213: tp = sc->sc_ttyp;
214: if (tp == NULL) {
215: printf("sl%d: sc_ttyp is NULL\n", n);
216: splx(s);
217: return;
218: }
219: next:
220: sc->sc_oactive = 1;
221: IF_DEQUEUE(&sc->sc_if.if_snd, m);
222: if (m == 0) {
223: sc->sc_oactive = 0;
224: splx(s);
225: return;
226: }
227: splx(s);
228:
229: SL_TRACE(SLSTART,printf("slstart %lx\n", tp);)
230: for (mp = m; mp; mp = mp->m_next) {
231: register unsigned len = mp->m_len;
232: register u_char *mcp;
233: u_char c;
234:
235: mcp = mtod(mp, u_char *);
236: while (len--) {
237: c = *mcp++;
238: if (c == FRAME_ESCAPE || c == FRAME_END) {
239: if (putc(FRAME_ESCAPE, &tp->t_outq))
240: goto full;
241: c = c == FRAME_ESCAPE ?
242: TRANS_FRAME_ESCAPE : TRANS_FRAME_END;
243: }
244: if (putc(c, &tp->t_outq))
245: goto full;
246: }
247: }
248: if (putc(FRAME_END, &tp->t_outq)) {
249: full:
250: SL_TRACE(SLSTART,printf("slstart: line is full\n");)
251: /*
252: * If you get many oerrors (more than 1 or two a day),
253: * you probably do not have enough clists and you should
254: * increase the number of them.
255: */
256: m_freem(m);
257: (void) unputc(&tp->t_outq); /* make some space */
258: (void) unputc(&tp->t_outq); /* make some space */
259: putc('\0', &tp->t_outq); /* end the packet */
260: putc(FRAME_END, &tp->t_outq); /* end the packet */
261: sc->sc_if.if_oerrors++;
262: sc->sc_oactive = 0;
263: ttstart(tp);
264: return EIO;
265: }
266: m_freem(m);
267: ttstart(tp);
268: sc->sc_if.if_opackets++;
269:
270: s = splimp();
271: sc->sc_oactive = 0;
272: splx(s);
273:
274: /* s = splimp();
275: /* goto next;
276: /**/
277: }
278:
279: /*
280: * tty interface receiver interrupt.
281: */
282: slinput(c, tp)
283: register c;
284: register struct tty *tp;
285: {
286: register struct sl_softc *sc;
287: register struct mbuf *m;
288: register struct ifqueue *inq;
289: register int s;
290:
291: SL_TRACE(SLINPUT, printf("slinput %x,", c & 0xff);)
292: sc = (struct sl_softc *)tp->t_slsoftc;
293: if (sc == NULL) {
294: printf("sl: t_slsoftc is NULL,tty %lx\n",(long)tp);
295: return;
296: }
297: c &= 0xff;
298: if (sc->sc_escaped) {
299: sc->sc_escaped = 0;
300: switch(c) {
301: case TRANS_FRAME_ESCAPE:
302: c = FRAME_ESCAPE;
303: break;
304: case TRANS_FRAME_END:
305: c = FRAME_END;
306: break;
307: default:
308: sc->sc_if.if_ierrors++;
309: return;
310: }
311: } else {
312: switch(c) {
313: case FRAME_END:
314: if (sc->sc_mt == 0) {
315: sc->sc_if.if_ierrors++;
316: return;
317: }
318: sc->sc_if.if_ipackets++;
319: sc->sc_mt->m_len -= sc->sc_len;
320: schednetisr(NETISR_IP);
321: inq = &ipintrq;
322:
323: s = splimp();
324: if (IF_QFULL(inq)) {
325: IF_DROP(inq);
326: sc->sc_if.if_ierrors++;
327: m_freem(sc->sc_m);
328: } else
329: IF_ENQUEUE(inq, sc->sc_m);
330: splx(s);
331: sc->sc_m = sc->sc_mt = 0;
332: sc->sc_len = 0;
333: return;
334: case FRAME_ESCAPE:
335: sc->sc_escaped = 1;
336: return;
337: }
338: }
339: if (sc->sc_len <= 0) { /* have to get more buffer space */
340: struct mbuf *mm;
341: MGET(mm, M_DONTWAIT, MT_DATA);
342: MBUFNULL(34, mm); /* for debugging */
343: if (mm == 0) {
344: m_freem(sc->sc_m);
345: sc->sc_m = sc->sc_mt = 0;
346: sc->sc_len = 0;
347: sc->sc_if.if_collisions++;
348: return;
349: }
350: if (sc->sc_mt == 0) {
351: sc->sc_mt = sc->sc_m = mm;
352: } else {
353: sc->sc_mt->m_next = mm;
354: sc->sc_mt = mm;
355: }
356: sc->sc_len = mm->m_len = MLEN;
357: sc->sc_mp = mtod(mm, u_char *);
358: }
359:
360: *sc->sc_mp++ = c;
361: sc->sc_len--;
362: }
363:
364: /*
365: * Process an ioctl request.
366: */
367: slioctl(ifp, cmd, data)
368: register struct ifnet *ifp;
369: int cmd;
370: caddr_t data;
371: {
372: struct tty *tp;
373: struct sockaddr_in *sin;
374: struct sl_softc *sc;
375: struct rtentry route;
376: int s = splimp(), error = 0;
377: register struct ifreq *ifr = (struct ifreq *)data;
378:
379:
380:
381: switch (cmd) {
382:
383: case SIOCSIFADDR:
384: if (ifp->if_flags & IFF_RUNNING)
385: if_rtinit(ifp, -1); /* delete previous route */
386: sin = (struct sockaddr_in *)&ifr->ifr_addr;
387: ifp->if_addr = *(struct sockaddr *)sin;
388: sin = (struct sockaddr_in *)&ifp->if_dstaddr;
389: ifp->if_net = in_netof(sin->sin_addr);
390: ifp->if_flags |= IFF_UP | IFF_RUNNING;
391: /* set up routing table entry */
392: if ((ifp->if_flags & IFF_ROUTE) == 0) {
393: rtinit(&ifp->if_dstaddr, &ifp->if_addr, RTF_HOST|RTF_UP);
394: ifp->if_flags |= IFF_ROUTE;
395: }
396: /*
397: * Since the way a tty line is attached as a network interface
398: * is to open it, do an "ioctl" to attach it, and close it,
399: * and since the close will reset the line discipline, we
400: * must set the line discipline here.
401: */
402: sc = &sl_softc[ifp->if_unit];
403: tp = sc->sc_ttyp;
404: tp->t_line = SLIPDISC;
405: tp->t_flags = RAW|EVENP|ODDP;
406: tp->t_ispeed = tp->t_ospeed = sc->sc_ttyspeed;
407:
408: /* Unfortunately, the tty driver does not have any
409: * way of jumping directly to the correct param routine
410: * so, to get the line set to the correct baudrate
411: * we are forced to use the following kludge
412: * (Fortunately, it is only called once per line)
413: * THIS CAN BE FIXED WITH THE SYSTEM V RELEASE 2
414: * TTY DRIVER, WHICH DOES HAVE A t_proc ARGUMENT FOR
415: * DO A "param".
416: */
417: #if NVX > 0
418: if (tp->t_oproc == vxstart)
419: vxparam(tp->t_dev);
420: else
421: #endif NVX
422: {
423: printf("Serial line attach: Unknown device\n");
424: error = ENODEV;
425: }
426: break;
427:
428: case SIOCSIFDSTADDR:
429: sin = (struct sockaddr_in *)&ifr->ifr_dstaddr;
430: ifp->if_dstaddr = *(struct sockaddr *)sin;
431: break;
432:
433: case SIOCIFDETACH:
434: bzero((caddr_t)&route, sizeof (route));
435: route.rt_dst = ifp->if_dstaddr;
436: route.rt_gateway = ifp->if_addr;
437: route.rt_flags = RTF_HOST | RTF_UP;
438: (void) rtrequest(SIOCDELRT, &route);
439: if_detach(ifp);
440: sc = &sl_softc[ifp->if_unit];
441: tp = sc->sc_ttyp;
442: tp->t_slsoftc = 0;
443: sc->sc_ttyp = 0;
444: ttyclose(tp);
445: break;
446:
447: default:
448: error = EINVAL;
449: }
450: splx(s);
451: return (error);
452: }
453: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.