|
|
1.1 root 1: /* if_un.c 6.1 83/07/29 */
2:
3: #include "un.h"
4: #if NUN > 0
5: /*
6: * Ungermann-Bass network/DR11-W interface driver
7: */
8: #include "../machine/pte.h"
9:
10: #include "../h/param.h"
11: #include "../h/systm.h"
12: #include "../h/mbuf.h"
13: #include "../h/buf.h"
14: #include "../h/protosw.h"
15: #include "../h/socket.h"
16: #include "../h/vmmac.h"
17: #include "../h/errno.h"
18: #include "../h/time.h"
19: #include "../h/kernel.h"
20: #include "../h/ioctl.h"
21:
22: #include "../net/if.h"
23: #include "../net/netisr.h"
24: #include "../net/route.h"
25: #include "../netinet/in.h"
26: #include "../netinet/in_systm.h"
27: #include "../netinet/ip.h"
28: #include "../netinet/ip_var.h"
29:
30: #include "../vax/cpu.h"
31: #include "../vax/mtpr.h"
32: #include "../vaxif/if_un.h"
33: #include "../vaxif/if_unreg.h"
34: #include "../vaxif/if_uba.h"
35: #include "../vaxuba/ubareg.h"
36: #include "../vaxuba/ubavar.h"
37:
38: #define UNMTU (600-sizeof (struct un_header))
39:
40: #define US_NULL 0 /* not doing anything state */
41: #define US_IDLE 1 /* waiting to transfer state */
42: #define US_READ 2 /* reading state */
43: #define US_WRITE 3 /* writing state */
44: #define US_RESET 4 /* waiting for reset state */
45:
46: int unprobe(), unattach(), unintr();
47: struct uba_device *uninfo[NUN];
48: u_short unstd[] = { 0 };
49: struct uba_driver undriver =
50: { unprobe, 0, unattach, 0, unstd, "un", uninfo };
51: #define UNUNIT(dev) (minor(dev))
52:
53: int uninit(), unioctl(), unoutput(), unreset();
54: int unrestart();
55:
56: /*
57: * Ungermann-Bass software status per interface.
58: *
59: * Each interface is referenced by a network interface structure,
60: * us_if, which the routing code uses to locate the interface.
61: * This structure contains the output queue for the interface, its address,
62: * etc. We also have, for each interface, a UBA interface structure, which
63: * contains information about the UNIBUS resources held by the interface:
64: * map registers, buffered data paths, etc. Information is cached in this
65: * structure for use by the if_uba.c routines in running the interface
66: * efficiently.
67: */
68: struct un_softc {
69: struct ifnet us_if; /* network-visible interface */
70: struct ifuba us_ifuba; /* UNIBUS resources */
71: short us_state; /* device state */
72: short us_errcnt; /* number of errors since time set */
73: short us_restart; /* restart interval */
74: u_char us_maxtime; /* interval for error counting */
75: u_char us_maxerr; /* errors allowed in interval */
76: time_t us_errtime; /* time for error counting */
77: } un_softc[NUN];
78:
79: /*
80: * Cause an interrupt to determine interface presence and
81: * interrupt vector.
82: */
83: unprobe(reg)
84: caddr_t reg;
85: {
86: register int br, cvec; /* r11, r10 value-result */
87: register struct undevice *addr = (struct undevice *)reg;
88:
89: #ifdef lint
90: br = 0; cvec = br; br = cvec;
91: unintr(0);
92: #endif
93: addr->csr = IE|UNRESET;
94: addr->csr = IE|UNRESET|GO;
95: DELAY(100000);
96: addr->csr = 0;
97: return (1);
98: }
99:
100: /*
101: * Interface exists: make available by filling in network interface
102: * record. System will initialize the interface when it is ready
103: * to accept packets.
104: */
105: unattach(ui)
106: struct uba_device *ui;
107: {
108: register struct un_softc *us = &un_softc[ui->ui_unit];
109:
110: us->us_if.if_unit = ui->ui_unit;
111: us->us_if.if_name = "un";
112: us->us_if.if_mtu = UNMTU;
113: us->us_if.if_init = uninit;
114: us->us_if.if_ioctl = unioctl;
115: us->us_if.if_output = unoutput;
116: us->us_if.if_reset = unreset;
117: us->us_if.if_watchdog = unrestart;
118: us->us_maxtime = 3;
119: us->us_maxerr = 10;
120: us->us_restart = 5 * 60;
121: us->us_ifuba.ifu_flags = UBA_CANTWAIT;
122: #ifdef notdef
123: us->us_ifuba.ifu_flags |= UBA_NEEDBDP;
124: #endif
125: if_attach(&us->us_if);
126: }
127:
128: /*
129: * Reset of interface after UNIBUS reset.
130: * If interface is on specified uba, reset its state.
131: */
132: unreset(unit, uban)
133: int unit, uban;
134: {
135: register struct uba_device *ui;
136:
137: if (unit >= NUN || (ui = uninfo[unit]) == 0 || ui->ui_alive == 0 ||
138: ui->ui_ubanum != uban)
139: return;
140: printf(" un%d", unit);
141: uninit(unit);
142: }
143:
144: /*
145: * Initialization of interface; clear recorded pending
146: * operations, and reinitialize UNIBUS usage.
147: */
148: uninit(unit)
149: int unit;
150: {
151: register struct un_softc *us = &un_softc[unit];
152: register struct uba_device *ui = uninfo[unit];
153: register struct undevice *addr;
154: struct sockaddr_in *sin;
155: int s;
156:
157: sin = (struct sockaddr_in *)&us->us_if.if_addr;
158: if (in_netof(sin->sin_addr) == 0)
159: return;
160: if (if_ubainit(&us->us_ifuba, ui->ui_ubanum,
161: sizeof (struct un_header), (int)btoc(UNMTU)) == 0) {
162: printf("un%d: can't initialize\n", unit);
163: us->us_if.if_flags &= ~IFF_UP;
164: return;
165: }
166: us->us_if.if_flags |= IFF_RUNNING;
167: us->us_errcnt = 0;
168: us->us_errtime = time.tv_sec;
169: unwhoami(unit);
170:
171: /*
172: * Reset U-B interface, thus causing an interrupt which
173: * will start things going.
174: */
175: addr = (struct undevice *)ui->ui_addr;
176: s = splimp();
177: addr->csr = IE|UNRESET;
178: addr->csr = IE|UNRESET|GO;
179: us->us_state = US_RESET;
180: splx(s);
181: }
182:
183: /*
184: * Try to start a write operation.
185: * If interface is busy, it must be in idle state, so issue a reset.
186: * Otherwise, get the datagram from the output queue, map it onto
187: * the UNIBUS, and start the write. This routine should not be
188: * called if the output queue is empty.
189: */
190: unstart(dev)
191: dev_t dev;
192: {
193: int unit = UNUNIT(dev);
194: struct uba_device *ui = uninfo[unit];
195: register struct un_softc *us = &un_softc[unit];
196: register struct undevice *addr = (struct undevice *)ui->ui_addr;
197: struct mbuf *m;
198: int dataaddr, datalen;
199: register short cmdcsr;
200:
201: if (us->us_state != US_NULL) {
202: addr->csr = IE|UNRESET;
203: addr->csr = IE|UNRESET|GO;
204: us->us_state = US_RESET;
205: } else {
206: IF_DEQUEUE(&us->us_if.if_snd, m);
207: if (m == 0)
208: return;
209: us->us_state = US_WRITE;
210: datalen = if_wubaput(&us->us_ifuba, m);
211: if (us->us_ifuba.ifu_flags & UBA_NEEDBDP)
212: UBAPURGE(us->us_ifuba.ifu_uba,
213: us->us_ifuba.ifu_w.ifrw_bdp);
214: dataaddr = us->us_ifuba.ifu_w.ifrw_info;
215: addr->bar = dataaddr & 0xffff;
216: addr->wcr = -(((datalen + 1) >> 1) + 1);
217: cmdcsr = ((dataaddr >> 12) & 0x30) | IE | UNOUT;
218: addr->csr = cmdcsr;
219: addr->csr = cmdcsr | GO;
220: }
221: }
222:
223: /*
224: * Ungermann-Bass interface interrupt handler.
225: * Determines reason for interrupt and acts accordingly.
226: */
227: unintr(unit)
228: int unit;
229: {
230: register struct un_softc *us = &un_softc[unit];
231: struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
232: register struct un_header *un;
233: struct mbuf *m;
234: int len;
235: register struct ifqueue *inq;
236: int cmdcsr;
237:
238: if ((addr->dar & RESETACK) && us->us_state != US_RESET) {
239: if ((us->us_if.if_flags & IFF_UP) == 0)
240: return;
241: printf("un%d: unexpected reset\n", unit);
242: unerror(unit);
243: }
244:
245: switch (us->us_state) {
246:
247: case US_NULL:
248: printf("un%d: stray interrupt\n", unit);
249: break;
250:
251: case US_RESET:
252: if (!(addr->dar & RESETACK)) {
253: addr->csr = IE|UNRESET;
254: addr->csr = IE|UNRESET|GO;
255: return;
256: }
257: break;
258:
259: case US_IDLE:
260: break;
261:
262: case US_READ:
263: us->us_if.if_ipackets++;
264: if (us->us_ifuba.ifu_flags & UBA_NEEDBDP)
265: UBAPURGE(us->us_ifuba.ifu_uba,
266: us->us_ifuba.ifu_r.ifrw_bdp);
267: if (addr->csr & STATA) {
268: if ((us->us_if.if_flags & IFF_UP) == 0)
269: return;
270: printf("un%d: input error csr=%b\n", unit,
271: addr->csr&0xffff, UNBITS);
272: us->us_if.if_ierrors++;
273: unerror(unit);
274: break;
275: }
276: un = (struct un_header *)(us->us_ifuba.ifu_r.ifrw_addr);
277: switch (un->un_ptype) {
278: #ifdef INET
279: case UNTYPE_IP:
280: len = htons((u_short)((struct ip *) (un+1))->ip_len);
281: schednetisr(NETISR_IP);
282: inq = &ipintrq;
283: break;
284: #endif
285: case UNTYPE_INQUIRE: {
286: struct sockaddr_in *sin;
287:
288: us->us_if.if_host[0] =
289: un->un_dport << 16 | htons(un->un_dniu);
290: sin = (struct sockaddr_in *)&us->us_if.if_addr;
291: sin->sin_addr = if_makeaddr(us->us_if.if_net,
292: us->us_if.if_host[0]);
293: us->us_if.if_flags |= IFF_UP;
294: if_rtinit(&us->us_if, RTF_UP);
295: goto setup;
296: }
297:
298: default:
299: printf("un%d: bad packet type %d\n", un->un_ptype);
300: goto setup;
301: }
302:
303: m = if_rubaget(&us->us_ifuba, len, 0);
304: if (m != 0)
305: if (IF_QFULL(inq)) {
306: IF_DROP(inq);
307: m_freem(m);
308: } else
309: IF_ENQUEUE(inq, m);
310: break;
311:
312: case US_WRITE:
313: us->us_if.if_opackets++;
314: if (addr->csr & STATA) {
315: if ((us->us_if.if_flags & IFF_UP) == 0)
316: return;
317: printf("un%d: output error csr=%b\n",
318: unit, addr->csr, UNBITS);
319: us->us_if.if_oerrors++;
320: unerror(unit);
321: }
322: if (us->us_ifuba.ifu_xtofree) {
323: m_freem(us->us_ifuba.ifu_xtofree);
324: us->us_ifuba.ifu_xtofree = 0;
325: }
326: break;
327:
328: default:
329: printf("un%d: invalid state %d csr=%b\n",
330: us->us_state, addr->csr, UNBITS);
331: }
332:
333: setup:
334: us->us_state = US_NULL;
335: if (addr->csr & STATB) {
336: us->us_state = US_READ;
337: addr->wcr = -((sizeof (struct un_header) + UNMTU + 1)/2+1);
338: addr->bar = us->us_ifuba.ifu_r.ifrw_info & 0xffff;
339: cmdcsr = ((us->us_ifuba.ifu_r.ifrw_info >> 12) & 0x30);
340: cmdcsr |= IE|UNRDDG;
341: addr->csr = cmdcsr;
342: addr->csr = cmdcsr | GO;
343: } else if (us->us_if.if_snd.ifq_head != 0 && (addr->csr & STATC))
344: unstart(unit);
345:
346: if (us->us_state == US_NULL) {
347: us->us_state = US_IDLE;
348: addr->csr = IE|UNIDLE;
349: addr->csr = IE|UNIDLE|GO;
350: }
351: }
352:
353: /*
354: * Ungermann-Bass output routine.
355: * Encapsulate a packet destined for dst for the local net.
356: */
357: unoutput(ifp, m0, dst)
358: struct ifnet *ifp;
359: struct mbuf *m0;
360: struct sockaddr *dst;
361: {
362: int type, destniu, destport, len;
363: register struct mbuf *m = m0;
364: register struct un_header *un;
365: register struct un_softc *us = &un_softc[ifp->if_unit];
366: int s;
367:
368: if ((us->us_if.if_flags & IFF_UP) == 0)
369: return (ENETDOWN);
370: switch (dst->sa_family) {
371:
372: #ifdef INET
373: case AF_INET: {
374: struct sockaddr_in *sin = (struct sockaddr_in *)dst;
375: struct ip *ip = mtod(m, struct ip *);
376:
377: if (sin->sin_addr.s_addr & 0xffffff00) {
378: destniu = sin->sin_addr.s_addr >> 24;
379: destport = (sin->sin_addr.s_addr >> 8) & 0xff;
380: } else {
381: destniu = 0xffff;
382: destport = 0xff;
383: }
384: len = htons((u_short) ip->ip_len);
385: type = UNTYPE_IP;
386: break;
387: }
388: #endif
389: default:
390: printf("un%d: can't handle af%d\n", ifp->if_unit,
391: dst->sa_family);
392: m_freem(m0);
393: return (EAFNOSUPPORT);
394: }
395:
396: /*
397: * Add local net header. If no space in first mbuf,
398: * allocate another.
399: */
400: if (m->m_off > MMAXOFF ||
401: MMINOFF + sizeof (struct un_header) > m->m_off) {
402: m = m_get(M_DONTWAIT, MT_HEADER);
403: if (m == 0) {
404: m_freem(m0);
405: return (ENOBUFS);
406: }
407: m->m_next = m0;
408: m->m_off = MMINOFF;
409: m->m_len = sizeof (struct un_header);
410: } else {
411: m->m_off -= sizeof (struct un_header);
412: m->m_len += sizeof (struct un_header);
413: }
414: un = mtod(m, struct un_header *);
415: bzero((caddr_t)un, sizeof (struct un_header));
416: un->un_length = htons((u_short)(len + sizeof (struct un_header)));
417: un->un_dniu = htons((u_short)destniu);
418: un->un_dport = destport;
419: un->un_dtype = 5;
420: un->un_sniu = htons((u_short)(ifp->if_host[0] >> 24));
421: un->un_sport = (ifp->if_host[0] >> 8) & 0xff;
422: un->un_stype = 5;
423: un->un_ptype = type;
424:
425: /*
426: * Queue message on interface, and start output if interface
427: * not yet active.
428: */
429: s = splimp();
430: if (IF_QFULL(&ifp->if_snd)) {
431: IF_DROP(&ifp->if_snd);
432: m_freem(m);
433: splx(s);
434: return (ENOBUFS);
435: }
436: IF_ENQUEUE(&ifp->if_snd, m);
437: if (us->us_state == US_IDLE)
438: unstart(ifp->if_unit);
439: splx(s);
440: return (0);
441: }
442:
443: /*
444: * U-B error handler, if maxerr errors have occured
445: * in maxtime seconds, disable the interface.
446: */
447: unerror(unit)
448: int unit;
449: {
450: register struct un_softc *us = &un_softc[unit];
451: struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
452:
453: if (time.tv_sec - us->us_errtime > us->us_maxtime) {
454: us->us_errtime = time.tv_sec;
455: us->us_errcnt = 1;
456: } else if (++us->us_errcnt >= us->us_maxerr) {
457: printf("un%d: error limit exceeded\n", unit);
458: us->us_if.if_flags &= ~IFF_UP;
459: addr->csr = 0;
460: us->us_if.if_timer = us->us_restart;
461: }
462: }
463:
464: unrestart(unit)
465: int unit;
466: {
467: register struct un_softc *us = &un_softc[unit];
468: struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
469: int s;
470:
471: us->us_if.if_flags |= IFF_UP;
472: printf("un%d: restarting\n", unit);
473: unwhoami(unit);
474: s = splimp();
475: addr->csr = IE|UNRESET;
476: addr->csr = IE|UNRESET|GO;
477: us->us_state = US_RESET;
478: splx(s);
479: }
480:
481: /*
482: * Send a "Who am I?" message to the interface.
483: * Interface should respond with an copy of the
484: * packet with its real address filled in. The
485: * message is placed at the head of the output queue.
486: * An interface reset should be done next to start
487: * things rolling.
488: */
489: unwhoami(unit)
490: int unit;
491: {
492: register struct mbuf *m;
493: register struct un_softc *us = &un_softc[unit];
494: register struct un_header *un;
495: int s;
496:
497: if ((m = m_get(M_DONTWAIT, MT_HEADER)) == 0)
498: return;
499: m->m_off = MMINOFF;
500: m->m_len = sizeof(struct un_header);
501: un = mtod(m, struct un_header *);
502: bzero((caddr_t)un, sizeof (struct un_header));
503: un->un_length = htons(sizeof (struct un_header));
504: un->un_dtype = un->un_stype = 5;
505: un->un_ptype = UNTYPE_INQUIRE;
506: s = splimp();
507: IF_PREPEND(&us->us_if.if_snd, m);
508: splx(s);
509: }
510:
511: /*
512: * Process an ioctl request.
513: */
514: unioctl(ifp, cmd, data)
515: register struct ifnet *ifp;
516: int cmd;
517: caddr_t data;
518: {
519: struct ifreq *ifr = (struct ifreq *)data;
520: int s = splimp(), error = 0;
521:
522: switch (cmd) {
523:
524: case SIOCSIFADDR:
525: if (ifp->if_flags & IFF_RUNNING)
526: if_rtinit(ifp, -1); /* delete previous route */
527: unsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
528: if (ifp->if_flags & IFF_RUNNING)
529: if_rtinit(ifp, RTF_UP);
530: else
531: uninit(ifp->if_unit);
532: break;
533:
534: default:
535: error = EINVAL;
536: }
537: splx(s);
538: return (error);
539: }
540:
541: unsetaddr(ifp, sin)
542: register struct ifnet *ifp;
543: register struct sockaddr_in *sin;
544: {
545:
546: ifp->if_net = in_netof(sin->sin_addr);
547: sin = (struct sockaddr_in *)&ifp->if_addr;
548: sin->sin_family = AF_INET;
549: /* host number filled in already, or filled in later */
550: sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
551: sin = (struct sockaddr_in *)&ifp->if_broadaddr;
552: sin->sin_family = AF_INET;
553: sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
554: ifp->if_flags |= IFF_BROADCAST;
555: }
556: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.