|
|
1.1 root 1: /* @(#)if_sl.c 7.1 (Berkeley) 6/4/86 */
2:
3: /*
4: * Serial Line interface
5: *
6: * Rick Adams
7: * Center for Seismic Studies
8: * 1300 N 17th Street, Suite 1450
9: * Arlington, Virginia 22209
10: * (703)276-7900
11: * [email protected]
12: * seismo!rick
13: *
14: * Pounded on heavily by Chris Torek ([email protected], umcp-cs!chris).
15: * N.B.: this belongs in netinet, not net, the way it stands now.
16: * Should have a link-layer type designation, but wouldn't be
17: * backwards-compatible.
18: *
19: * Converted to 4.3BSD Beta by Chris Torek.
20: * Other changes made at Berkeley, based in part on code by Kirk Smith.
21: */
22:
23: /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
24: /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
25:
26: #include "sl.h"
27: #if NSL > 0
28:
29: #include "param.h"
30: #include "mbuf.h"
31: #include "buf.h"
32: #include "dk.h"
33: #include "socket.h"
34: #include "ioctl.h"
35: #include "file.h"
36: #include "tty.h"
37: #include "errno.h"
38:
39: #include "if.h"
40: #include "netisr.h"
41: #include "route.h"
42: #if INET
43: #include "../netinet/in.h"
44: #include "../netinet/in_systm.h"
45: #include "../netinet/in_var.h"
46: #include "../netinet/ip.h"
47: #endif
48:
49: #ifdef vax
50: #include "../vax/mtpr.h"
51: #endif vax
52:
53: /*
54: * N.B.: SLMTU is now a hard limit on input packet size.
55: * SLMTU must be <= CLBYTES - sizeof(struct ifnet *).
56: */
57: #define SLMTU 1006
58: #define SLIP_HIWAT 1000 /* don't start a new packet if HIWAT on queue */
59: #define CLISTRESERVE 1000 /* Can't let clists get too low */
60:
61: struct sl_softc {
62: struct ifnet sc_if; /* network-visible interface */
63: short sc_flags; /* see below */
64: short sc_ilen; /* length of input-packet-so-far */
65: struct tty *sc_ttyp; /* pointer to tty structure */
66: char *sc_mp; /* pointer to next available buf char */
67: char *sc_buf; /* input buffer */
68: } sl_softc[NSL];
69:
70: /* flags */
71: #define SC_ESCAPED 0x0001 /* saw a FRAME_ESCAPE */
72: #define SC_OACTIVE 0x0002 /* output tty is active */
73:
74: #define FRAME_END 0300 /* Frame End */
75: #define FRAME_ESCAPE 0333 /* Frame Esc */
76: #define TRANS_FRAME_END 0334 /* transposed frame end */
77: #define TRANS_FRAME_ESCAPE 0335 /* transposed frame esc */
78:
79: #define t_sc T_LINEP
80:
81: int sloutput(), slioctl(), ttrstrt();
82:
83: /*
84: * Called from boot code to establish sl interfaces.
85: */
86: slattach()
87: {
88: register struct sl_softc *sc;
89: register int i = 0;
90:
91: for (sc = sl_softc; i < NSL; sc++) {
92: sc->sc_if.if_name = "sl";
93: sc->sc_if.if_unit = i++;
94: sc->sc_if.if_mtu = SLMTU;
95: sc->sc_if.if_flags = IFF_POINTOPOINT;
96: sc->sc_if.if_ioctl = slioctl;
97: sc->sc_if.if_output = sloutput;
98: sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
99: if_attach(&sc->sc_if);
100: }
101: }
102:
103: /*
104: * Line specific open routine.
105: * Attach the given tty to the first available sl unit.
106: */
107: /* ARGSUSED */
108: slopen(dev, tp)
109: dev_t dev;
110: register struct tty *tp;
111: {
112: register struct sl_softc *sc;
113: register int nsl;
114:
115: if (!suser())
116: return (EPERM);
117: if (tp->t_line == SLIPDISC)
118: return (EBUSY);
119:
120: for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++)
121: if (sc->sc_ttyp == NULL) {
122: sc->sc_flags = 0;
123: sc->sc_ilen = 0;
124: if (slinit(sc) == 0)
125: return (ENOBUFS);
126: tp->t_sc = (caddr_t)sc;
127: sc->sc_ttyp = tp;
128: ttyflush(tp, FREAD | FWRITE);
129: return (0);
130: }
131:
132: return (ENXIO);
133: }
134:
135: /*
136: * Line specific close routine.
137: * Detach the tty from the sl unit.
138: * Mimics part of ttyclose().
139: */
140: slclose(tp)
141: struct tty *tp;
142: {
143: register struct sl_softc *sc;
144: int s;
145:
146: ttywflush(tp);
147: tp->t_line = 0;
148: s = splimp(); /* paranoid; splnet probably ok */
149: sc = (struct sl_softc *)tp->t_sc;
150: if (sc != NULL) {
151: if_down(&sc->sc_if);
152: sc->sc_ttyp = NULL;
153: tp->t_sc = NULL;
154: MCLFREE((struct mbuf *)sc->sc_buf);
155: sc->sc_buf = 0;
156: }
157: splx(s);
158: }
159:
160: /*
161: * Line specific (tty) ioctl routine.
162: * Provide a way to get the sl unit number.
163: */
164: /* ARGSUSED */
165: sltioctl(tp, cmd, data, flag)
166: struct tty *tp;
167: caddr_t data;
168: {
169:
170: if (cmd == TIOCGETD) {
171: *(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit;
172: return (0);
173: }
174: return (-1);
175: }
176:
177: /*
178: * Queue a packet. Start transmission if not active.
179: */
180: sloutput(ifp, m, dst)
181: register struct ifnet *ifp;
182: register struct mbuf *m;
183: struct sockaddr *dst;
184: {
185: register struct sl_softc *sc;
186: int s;
187:
188: /*
189: * `Cannot happen' (see slioctl). Someday we will extend
190: * the line protocol to support other address families.
191: */
192: if (dst->sa_family != AF_INET) {
193: printf("sl%d: af%d not supported\n", ifp->if_unit,
194: dst->sa_family);
195: m_freem(m);
196: return (EAFNOSUPPORT);
197: }
198:
199: sc = &sl_softc[ifp->if_unit];
200: if (sc->sc_ttyp == NULL) {
201: m_freem(m);
202: return (ENETDOWN); /* sort of */
203: }
204: if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
205: m_freem(m);
206: return (EHOSTUNREACH);
207: }
208: s = splimp();
209: if (IF_QFULL(&ifp->if_snd)) {
210: IF_DROP(&ifp->if_snd);
211: splx(s);
212: m_freem(m);
213: sc->sc_if.if_oerrors++;
214: return (ENOBUFS);
215: }
216: IF_ENQUEUE(&ifp->if_snd, m);
217: if ((sc->sc_flags & SC_OACTIVE) == 0) {
218: splx(s);
219: slstart(sc->sc_ttyp);
220: } else
221: splx(s);
222: return (0);
223: }
224:
225: /*
226: * Start output on interface. Get another datagram
227: * to send from the interface queue and map it to
228: * the interface before starting output.
229: */
230: slstart(tp)
231: register struct tty *tp;
232: {
233: register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
234: register struct mbuf *m;
235: register int len;
236: register u_char *cp;
237: int flush, nd, np, n, s;
238: struct mbuf *m2;
239: extern int cfreecount;
240:
241: for (;;) {
242: /*
243: * If there is more in the output queue, just send it now.
244: * We are being called in lieu of ttstart and must do what
245: * it would.
246: */
247: if (tp->t_outq.c_cc > 0)
248: ttstart(tp);
249: if (tp->t_outq.c_cc > SLIP_HIWAT)
250: return;
251:
252: /*
253: * This happens briefly when the line shuts down.
254: */
255: if (sc == NULL)
256: return;
257:
258: /*
259: * If system is getting low on clists
260: * and we have something running already, stop here.
261: */
262: if (cfreecount < CLISTRESERVE + SLMTU &&
263: sc->sc_flags & SC_OACTIVE)
264: return;
265:
266: /*
267: * Get a packet and send it to the interface.
268: */
269: s = splimp();
270: IF_DEQUEUE(&sc->sc_if.if_snd, m);
271: if (m == NULL) {
272: if (tp->t_outq.c_cc == 0)
273: sc->sc_flags &= ~SC_OACTIVE;
274: splx(s);
275: return;
276: }
277: flush = !(sc->sc_flags & SC_OACTIVE);
278: sc->sc_flags |= SC_OACTIVE;
279: splx(s);
280:
281: /*
282: * The extra FRAME_END will start up a new packet, and thus
283: * will flush any accumulated garbage. We do this whenever
284: * the line may have been idle for some time.
285: */
286: if (flush)
287: (void) putc(FRAME_END, &tp->t_outq);
288:
289: while (m) {
290: cp = mtod(m, u_char *);
291: len = m->m_len;
292: while (len > 0) {
293: /*
294: * Find out how many bytes in the string we can
295: * handle without doing something special.
296: */
297: nd = locc(FRAME_ESCAPE, len, cp);
298: np = locc(FRAME_END, len, cp);
299: n = len - MAX(nd, np);
300: if (n) {
301: /*
302: * Put n characters at once
303: * into the tty output queue.
304: */
305: if (b_to_q((char *)cp, n, &tp->t_outq))
306: break;
307: len -= n;
308: cp += n;
309: }
310: /*
311: * If there are characters left in the mbuf,
312: * the first one must be special..
313: * Put it out in a different form.
314: */
315: if (len) {
316: if (putc(FRAME_ESCAPE, &tp->t_outq))
317: break;
318: if (putc(*cp == FRAME_ESCAPE ?
319: TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
320: &tp->t_outq)) {
321: (void) unputc(&tp->t_outq);
322: break;
323: }
324: cp++;
325: len--;
326: }
327: }
328: MFREE(m, m2);
329: m = m2;
330: }
331:
332: if (putc(FRAME_END, &tp->t_outq)) {
333: /*
334: * Not enough room. Remove a char to make room
335: * and end the packet normally.
336: * If you get many collisions (more than one or two
337: * a day) you probably do not have enough clists
338: * and you should increase "nclist" in param.c.
339: */
340: (void) unputc(&tp->t_outq);
341: (void) putc(FRAME_END, &tp->t_outq);
342: sc->sc_if.if_collisions++;
343: } else
344: sc->sc_if.if_opackets++;
345: }
346: }
347:
348: slinit(sc)
349: register struct sl_softc *sc;
350: {
351: struct mbuf *p;
352:
353: if (sc->sc_buf == (char *) 0) {
354: MCLALLOC(p, 1);
355: if (p) {
356: sc->sc_buf = (char *)p;
357: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
358: } else {
359: printf("sl%d: can't allocate buffer\n", sc - sl_softc);
360: sc->sc_if.if_flags &= ~IFF_UP;
361: return (0);
362: }
363: }
364: return (1);
365: }
366:
367: /*
368: * Copy data buffer to mbuf chain; add ifnet pointer ifp.
369: */
370: struct mbuf *
371: sl_btom(sc, len, ifp)
372: struct sl_softc *sc;
373: register int len;
374: struct ifnet *ifp;
375: {
376: register caddr_t cp;
377: register struct mbuf *m, **mp;
378: register unsigned count;
379: struct mbuf *top = NULL;
380:
381: cp = sc->sc_buf + sizeof(struct ifnet *);
382: mp = ⊤
383: while (len > 0) {
384: MGET(m, M_DONTWAIT, MT_DATA);
385: if ((*mp = m) == NULL) {
386: m_freem(top);
387: return (NULL);
388: }
389: if (ifp)
390: m->m_off += sizeof(ifp);
391: /*
392: * If we have at least NBPG bytes,
393: * allocate a new page. Swap the current buffer page
394: * with the new one. We depend on having a space
395: * left at the beginning of the buffer
396: * for the interface pointer.
397: */
398: if (len >= NBPG) {
399: MCLGET(m);
400: if (m->m_len == CLBYTES) {
401: cp = mtod(m, char *);
402: m->m_off = (int)sc->sc_buf - (int)m;
403: sc->sc_buf = cp;
404: if (ifp) {
405: m->m_off += sizeof(ifp);
406: count = MIN(len,
407: CLBYTES - sizeof(struct ifnet *));
408: } else
409: count = MIN(len, CLBYTES);
410: goto nocopy;
411: }
412: }
413: if (ifp)
414: count = MIN(len, MLEN - sizeof(ifp));
415: else
416: count = MIN(len, MLEN);
417: bcopy(cp, mtod(m, caddr_t), count);
418: nocopy:
419: m->m_len = count;
420: if (ifp) {
421: m->m_off -= sizeof(ifp);
422: m->m_len += sizeof(ifp);
423: *mtod(m, struct ifnet **) = ifp;
424: ifp = NULL;
425: }
426: cp += count;
427: len -= count;
428: mp = &m->m_next;
429: }
430: return (top);
431: }
432:
433: /*
434: * tty interface receiver interrupt.
435: */
436: slinput(c, tp)
437: register int c;
438: register struct tty *tp;
439: {
440: register struct sl_softc *sc;
441: register struct mbuf *m;
442: int s;
443:
444: tk_nin++;
445: sc = (struct sl_softc *)tp->t_sc;
446: if (sc == NULL)
447: return;
448:
449: c &= 0xff;
450: if (sc->sc_flags & SC_ESCAPED) {
451: sc->sc_flags &= ~SC_ESCAPED;
452: switch (c) {
453:
454: case TRANS_FRAME_ESCAPE:
455: c = FRAME_ESCAPE;
456: break;
457:
458: case TRANS_FRAME_END:
459: c = FRAME_END;
460: break;
461:
462: default:
463: sc->sc_if.if_ierrors++;
464: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
465: sc->sc_ilen = 0;
466: return;
467: }
468: } else {
469: switch (c) {
470:
471: case FRAME_END:
472: if (sc->sc_ilen == 0) /* ignore */
473: return;
474: m = sl_btom(sc, sc->sc_ilen, &sc->sc_if);
475: if (m == NULL) {
476: sc->sc_if.if_ierrors++;
477: return;
478: }
479: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
480: sc->sc_ilen = 0;
481: sc->sc_if.if_ipackets++;
482: s = splimp();
483: if (IF_QFULL(&ipintrq)) {
484: IF_DROP(&ipintrq);
485: sc->sc_if.if_ierrors++;
486: m_freem(m);
487: } else {
488: IF_ENQUEUE(&ipintrq, m);
489: schednetisr(NETISR_IP);
490: }
491: splx(s);
492: return;
493:
494: case FRAME_ESCAPE:
495: sc->sc_flags |= SC_ESCAPED;
496: return;
497: }
498: }
499: if (++sc->sc_ilen > SLMTU) {
500: sc->sc_if.if_ierrors++;
501: sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
502: sc->sc_ilen = 0;
503: return;
504: }
505: *sc->sc_mp++ = c;
506: }
507:
508: /*
509: * Process an ioctl request.
510: */
511: slioctl(ifp, cmd, data)
512: register struct ifnet *ifp;
513: int cmd;
514: caddr_t data;
515: {
516: register struct ifaddr *ifa = (struct ifaddr *)data;
517: int s = splimp(), error = 0;
518:
519: switch (cmd) {
520:
521: case SIOCSIFADDR:
522: if (ifa->ifa_addr.sa_family == AF_INET)
523: ifp->if_flags |= IFF_UP;
524: else
525: error = EAFNOSUPPORT;
526: break;
527:
528: case SIOCSIFDSTADDR:
529: if (ifa->ifa_addr.sa_family != AF_INET)
530: error = EAFNOSUPPORT;
531: break;
532:
533: default:
534: error = EINVAL;
535: }
536: splx(s);
537: return (error);
538: }
539: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.