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