|
|
1.1 root 1: /*
2: * Copyright IBM Corporation 1987,1990
3: *
4: * All Rights Reserved
5: *
6: * Permission to use, copy, modify, and distribute this software and its
7: * documentation for any purpose and without fee is hereby granted,
8: * provided that the above copyright notice appear in all copies and that
9: * both that copyright notice and this permission notice appear in
10: * supporting documentation, and that the name of IBM not be
11: * used in advertising or publicity pertaining to distribution of the
12: * software without specific, written prior permission.
13: *
14: * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR USE.
16: * IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19: * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
20: * THIS SOFTWARE.
21: *
22: * @(#)if_un.eg 7.1 (Berkeley) 10/29/90
23: */
24:
25: /*
26: * Ungermann-Bass PC-NIC (Ethernet) Adapter (4.3 driver)
27: */
28:
29: #include "un.h"
30: #if NUN > 0
31:
32: #include "../machine/pte.h"
33:
34: #include "param.h"
35: #include "systm.h"
36: #include "mbuf.h"
37: #include "buf.h"
38: #include "protosw.h"
39: #include "socket.h"
40: #include "vmmac.h"
41: #include "ioctl.h"
42: #include "errno.h"
43:
44: #include "../net/if.h"
45: #include "../net/netisr.h"
46: #include "../net/route.h"
47:
48: #ifdef INET
49: #include "../netinet/in.h"
50: #include "../netinet/in_systm.h"
51: #include "../netinet/in_var.h"
52: #include "../netinet/ip.h"
53: #include "../netinet/if_ether.h"
54: #endif INET
55:
56: #ifdef NS
57: #include "../netns/ns.h"
58: #include "../netns/ns_if.h"
59: #endif NS
60:
61: #ifdef ISO
62: #include "../netargo/if_clnp.h"
63: #include "../netargo/iso.h"
64: #include "../netargo/iso_var.h"
65: #include "../netargo/argo_debug.h"
66: #endif ISO
67:
68: #include "../machine/io.h"
69: #include "if_unreg.h"
70: #ifdef IEEELLC
71: #include "if_llc.h"
72: #endif IEEELLC
73: #include "../machineio/ioccvar.h"
74: #include "../machine/debug.h"
75:
76: int unprobe(), unattach();
77:
78: #ifdef AT
79: caddr_t unstd[] = { (caddr_t) 0xa0000, (caddr_t) 0xa8000,
80: (caddr_t) 0xb0000, (caddr_t) 0xb8000, 0 };
81: #else
82: caddr_t unstd[] = { (caddr_t) 0xf4080000, (caddr_t) 0xf4088000,
83: (caddr_t) 0xf4090000, (caddr_t) 0xf4098000, 0 };
84: #endif AT
85:
86: struct iocc_device *uninfo[NUN];
87:
88: int unint(), uninit(), unioctl(), unoutput(), unreset();
89:
90: struct iocc_driver undriver =
91: { unprobe, 0, unattach, 0, unstd, "un", uninfo,
92: 0, 0, unint, UN_EADDROFF };
93:
94: struct mbuf *unget();
95:
96: /*
97: * Ethernet software status per adapter.
98: */
99: struct un_softc {
100: struct arpcom us_ac; /* generic network interface stuff */
101: #define us_if us_ac.ac_if /* ifnet struct */
102: #define us_addr us_ac.ac_enaddr /* hardware (i.e. ethernet) address */
103: short us_oactive; /* 1 => output active */
104: short us_nextpage; /* next receive buffer page */
105: short us_xbuf; /* in-use xmt buf (if output active) */
106: short us_xfull[2]; /* 1 => a full xmt buf */
107: short us_xstart[2]; /* start address used in unstart */
108: } un_softc[NUN];
109:
110: #ifdef DEBUG
111: char undebug = 0;
112: #endif DEBUG
113:
114: #ifdef ATR
115: #define move_window(window, addr) {\
116: int real_addr;\
117: int new_window;\
118: \
119: window = get_128_window();\
120: real_addr = 0xfffff & (int) addr;\
121: new_window = real_addr & 0xe0000;\
122: set_128_window(new_window);\
123: addr = (struct undevice *) (real_addr - new_window);\
124: }
125:
126: #define restore_window(window) set_128_window(window)
127: #define bcopyin(from,to,len) bcopy((from)+pcif_128_fw,to,len)
128: #define bcopyout(from,to,len) bcopy(from,(to)+pcif_128_fw,len)
129: #endif ATR
130:
131: #ifdef IBMRTPC
132: #define bcopyin bcopy
133: #define bcopyout bcopy
134: #endif IBMRTPC
135: /*
136: * unprobe - try to generate an interrupt (to see if the board is there)
137: */
138: unprobe(p)
139: register caddr_t p;
140: {
141: register struct undevice *addr = (struct undevice *) p;
142: #ifdef ATR
143: register int old_window;
144: move_window(old_window, addr);
145: #endif ATR
146: (void) unzap(addr);
147: UN_GLOBIENB(0); /* global interrrupt enable */
148: MM_OUT(&addr->un_csr, UN_GSFTINT); /* generate software interrupt */
149: PROBE_DELAY(100000);
150: MM_OUT(&addr->un_csr, 0);
151: #ifdef ATR
152: restore_window(old_window);
153: #endif ATR
154: return(PROBE_OK);
155: }
156:
157: /*
158: * unattach - make the interface available to the network software
159: * (if the auto-configuration software determines that the interface
160: * exists). The system will initialize the interface when it is
161: * ready to accept packets.
162: */
163: unattach(iod)
164: register struct iocc_device *iod;
165: {
166: register struct un_softc *us = &un_softc[iod->iod_unit];
167: register struct ifnet *ifp = &us->us_if;
168: register struct undevice *addr = (struct undevice *) iod->iod_addr;
169: register int i;
170: #ifdef ATR
171: register int old_window;
172:
173: move_window(old_window, addr);
174: #endif ATR
175: ifp->if_unit = iod->iod_unit;
176: ifp->if_name = "un";
177:
178: #ifdef IEEELLC
179: ifp->if_mtu = ETHERMTU - 3; /* 3 bytes for UI LLC frame */
180: #else
181: ifp->if_mtu = ETHERMTU;
182: #endif IEEELCC
183:
184: /*
185: * Read the ethernet address off the board.
186: * Save it and also write it to the edlc chip.
187: */
188: for (i = 0; i < ETH_ADDR_SIZE; i++){
189: us->us_addr[i] = MM_IN(&addr->un_eprom[UN_EADDROFF+i]);
190: MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]);
191: }
192: printf("un%d: ethernet address ", ifp->if_unit);
193: unprintethaddr(us->us_addr);
194: printf("\n");
195: ifp->if_init = uninit;
196: ifp->if_ioctl = unioctl;
197: ifp->if_output = unoutput;
198: ifp->if_reset = unreset;
199: ifp->if_flags = IFF_BROADCAST;
200: #ifdef ISO
201: ifp->if_flags |= IFF_EAVESDROP;
202: #endif ISO
203: if_attach(ifp);
204: DEBUGF(undebug, printf("un%d: attached\n", iod->iod_unit);)
205: #ifdef ATR
206: restore_window(old_window);
207: #endif ATR
208: }
209:
210: /*
211: * unreset - reset interface
212: */
213: unreset(unit)
214: register unsigned int unit;
215: {
216: register struct iocc_device *iod;
217:
218: if (unit < NUN && (iod = uninfo[unit]) != 0 && iod->iod_alive != 0){
219: un_softc[unit].us_if.if_flags &= ~IFF_RUNNING;
220: DEBUGF(undebug, printf("un%d: reset\n", unit);)
221: uninit(unit);
222: }
223: }
224:
225: /*
226: * uninit - initialize interface, enable packet reception, start any
227: * pending writes
228: */
229: uninit(unit)
230: register int unit;
231: {
232: register struct un_softc *us = &un_softc[unit];
233: register struct ifnet *ifp = &us->us_if;
234: register int s;
235: register struct undevice *addr;
236: register int i;
237:
238: if (ifp->if_addrlist == (struct ifaddr *) 0){
239: /* no address */
240: return;
241: }
242: if ((ifp->if_flags & IFF_RUNNING) == 0){
243: int old_window;
244:
245: addr = (struct undevice *) (uninfo[unit]->iod_addr);
246: #ifdef ATR
247: move_window(old_window, addr);
248: #endif ATR
249: s = splimp();
250: us->us_nextpage = unzap(addr); /* initialize hardware */
251: /* unzap returns next receive page to be used */
252: for (i = 0; i < ETH_ADDR_SIZE; i++){
253: MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]);
254: }
255: us->us_oactive = 0; /* output not active */
256: /* turn adapter on */
257: ifp->if_flags |= IFF_RUNNING;
258: MM_OUT(&addr->un_csr, UN_PAVIENB);
259: /* Allow packet available interrupts */
260: UN_GLOBIENB(us->us_nextpage); /* global interrrupt enable */
261: if (ifp->if_snd.ifq_head){ /* anything on send queue */
262: struct mbuf *m;
263:
264: IF_DEQUEUE(&ifp->if_snd, m);
265: unput(us, addr, m, 0);
266: unstart(us, addr, 0);
267: if (ifp->if_snd.ifq_head){
268: IF_DEQUEUE(&ifp->if_snd, m);
269: unput(us, addr, m, 1);
270: }
271: }
272: splx(s);
273: #ifdef ATR
274: restore_window(old_window);
275: #endif ATR
276: }
277: DEBUGF(undebug, printf("un%d: init'ed\n", unit);)
278: }
279:
280: /*
281: * unstart - start output from one of the adapter's 2 transmit buffers
282: */
283: unstart(us, addr, xbuf)
284: register struct un_softc *us;
285: register struct undevice *addr;
286: register int xbuf;
287: {
288: us->us_oactive = 1;
289: us->us_xbuf = xbuf;
290: UN_XMIT(addr, us->us_xstart[xbuf]);
291: MM_OUT(&addr->un_csr, UN_IENABLE); /* enable transmit done interrupt */
292: }
293:
294: /*
295: * unint - interrupt handler. find the cause of the interrupt and
296: * dispatch an appropriate handler routine.
297: */
298: unint(unit)
299: register int unit;
300: {
301: register struct un_softc *us = &un_softc[unit];
302: register struct undevice *addr =
303: (struct undevice *) uninfo[unit]->iod_addr;
304: register char status;
305: register int rc = 1;
306: #ifdef ATR
307: register int old_window;
308:
309: move_window(old_window, addr);
310: #endif ATR
311:
312: UN_DISABLE(us->us_nextpage);
313: while ((status = ~MM_IN(&addr->un_csr)) & UN_PAVINT){
314: DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b",
315: unit, status & 0xff, UN_CSRBITS);)
316: unrint(unit, us, addr);
317: rc = 0;
318: }
319: if (status & UN_TXRINT){
320: DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b",
321: unit, status & 0xff, UN_CSRBITS);)
322: unxint(unit, us, addr);
323: rc = 0;
324: }
325: UN_ENABLE(us->us_nextpage);
326: #ifdef ATR
327: restore_window(old_window);
328: #endif ATR
329: return(rc);
330: }
331:
332: /*
333: * unrint - interrupt handler for packet reception.
334: *
335: * log error if error bits are latched, examine packet to determine
336: * type, if can't determine packet length from type, drop packet.
337: * otherwise decapsulate packet based on type and pass to an appropriate
338: * higher-level input routine.
339: */
340: unrint(unit, us, addr)
341: int unit;
342: register struct un_softc *us;
343: register struct undevice *addr;
344: {
345: register struct ether_header *eh;
346: register struct mbuf *m;
347: register int len;
348: register int off;
349: int resid;
350: struct ifqueue *inq;
351: char status = MM_IN(&addr->un_edlc.rstat);
352: u_short type;
353: u_short ungetushortatoff();
354: #ifdef IEEELLC
355: struct ether_header ehbuf;
356: #endif IEEELLC
357:
358: MM_OUT(&addr->un_edlc.rstat, status); /* clear status */
359: /* (the hardware xor's in the value of status setting rstat to 0) */
360: DEBUGF(undebug & 0x2, printf(" rstat = %b", status, RS_BITS);)
361: /*
362: * Latch errors. (Errors found correspond to packets
363: * that were received prior to the current packet
364: * since packet available interrupts are generated
365: * for good packets only.)
366: */
367: if (status & RS_ERR){
368: DEBUGF(undebug, printf("unrint: input error\n");)
369: us->us_if.if_ierrors++;
370: }
371: us->us_if.if_ipackets++;
372:
373: /*
374: * determine the length of the received packet.
375: */
376: len = 0;
377: off = us->us_nextpage;
378:
379: #define BUMP(page) if (++(page) == UN_NUMRBUFS) page = 0
380: while ((MM_IN(&addr->un_pram[us->us_nextpage]) & UN_LAST_PAGE) == 0){
381: len += UN_RBUFSIZE;
382: BUMP(us->us_nextpage);
383: }
384: len += (MM_IN(&addr->un_pram[us->us_nextpage]) &
385: UN_PAGE_LENGTH_MASK) + 1;
386: BUMP(us->us_nextpage);
387: #undef BUMP
388: DEBUGF(undebug & 0x2, printf(" len = %d ", len);)
389: if (len > UN_XBSIZE){
390: printf("un%d: huge packet!\n",unit);
391: goto chuckit;
392: }
393: /*
394: * Process the packet
395: */
396: eh = (struct ether_header *) &addr->un_rcvbuf[off][0];
397: DEBUGF(undebug & 0x2,
398: { char cbuf[6];
399: printf(" from = ");
400: bcopyin(eh->ether_shost, cbuf, sizeof(cbuf));
401: unprintethaddr(cbuf);
402: printf(" to = ");
403: bcopyin(eh->ether_dhost, cbuf, sizeof(cbuf));
404: unprintethaddr(cbuf);
405: printf(" "); }
406: )
407: len -= sizeof(struct ether_header);
408: type = ntohs((u_short) MM_INW(&eh->ether_type));
409: /*
410: * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL
411: * have (type - ETHERTYPE_TRAIL) * 512 bytes of data followed by
412: * a type field and then a (variable length) header
413: */
414: if (type >= ETHERTYPE_TRAIL &&
415: type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER){
416: off = (type - ETHERTYPE_TRAIL) * 512;
417: if (off >= ETHERMTU){
418: goto chuckit;
419: }
420: type = ungetushortatoff(addr, eh, off);
421: resid = ungetushortatoff(addr, eh, off + 2);
422: if (off + resid > len){
423: goto chuckit;
424: }
425: len = off + resid;
426: } else {
427: off = 0;
428: }
429: if (len == 0){
430: goto chuckit;
431: }
432:
433: #ifdef IEEELLC
434: if (type <= ETHERMTU) {
435: /* may need ether_header for XID, TEST LLC functions */
436: ehbuf = *eh;
437: }
438: #endif IEEELLC
439:
440: /*
441: * pull packet off interface. if off is non-zero, the
442: * packet has a trailing "header". unget will move this
443: * header to the front, but we still have to remove the
444: * type and length fields from the front of the data.
445: */
446: m = unget(addr, (char *) eh, len, off, &us->us_if);
447: /*
448: * update the full page pointer and clear the packet available
449: * flag if necessary. update the fpp here to free the on-board
450: * receive pages as soon as possible.
451: */
452: unupdatefpp(addr, us->us_nextpage);
453: if (m != 0){
454: if (off){
455: #ifdef ISO
456: /*
457: * Move snpa header over by 4 bytes to skip
458: * the trailer Type and Header length fields.
459: */
460: struct snpa_hdr sh;
461:
462: bcopy(mtod(m, char *), (caddr_t)&sh, sizeof(struct snpa_hdr));
463: m->m_off += 2 * sizeof(u_short);
464: m->m_len -= 2 * sizeof(u_short);
465: bcopy((caddr_t)&sh, mtod(m, char *), sizeof(struct snpa_hdr));
466: #else ISO
467: struct ifnet *ifp;
468: /*
469: * bcopy is used since word moves must be on 4 byte
470: * boundaries on the RT PC
471: */
472: bcopy(mtod(m, char *), (char *) &ifp, sizeof(ifp));
473: m->m_off += 2 * sizeof(u_short);
474: m->m_len -= 2 * sizeof(u_short);
475: bcopy((char *) &ifp, mtod(m, char *), sizeof(ifp));
476: #endif ISO
477: }
478: switch (type){
479: #ifdef INET
480: case ETHERTYPE_IP:
481: {
482: int s;
483:
484: DEBUGF(undebug & 0x2, printf("ip packet\n");)
485: schednetisr(NETISR_IP);
486: s = splimp();
487: inq = &ipintrq;
488: if (IF_QFULL(inq)){
489: DEBUGF(undebug & 0x2, printf(" qfull\n");)
490: IF_DROP(inq);
491: m_freem(m);
492: } else {
493: IF_ENQUEUE(inq, m);
494: DEBUGF(undebug & 0x2, printf(" queued\n");)
495: }
496: splx(s);
497: break;
498: }
499:
500: case ETHERTYPE_ARP:
501: DEBUGF(undebug & 0x2, printf("arp packet\n");)
502: arpinput(&us->us_ac, m); /* arpinput frees m */
503: break;
504: #endif INET
505: #ifdef NS
506: case ETHERTYPE_NS:
507: DEBUGF(undebug & 0x2, printf("ns packet\n");)
508: schednetisr(NETISR_NS);
509: inq = &nsintrq;
510: break;
511: #endif NS
512: #ifndef IEEELLC
513: #ifdef ISO
514: case ETHERTYPE_CLNP: /* should be CLNL */
515: DEBUGF(undebug & 0x2, printf("clnl packet\n");)
516:
517: /* IFF_EAVESDROP can not be turned off for Ethernet */
518:
519: schednetisr(NETISR_CLNP);
520: inq = &clnlintrq;
521: if (IF_QFULL(inq)){
522: DEBUGF(undebug & 0x2, printf(" qfull\n");)
523: IF_DROP(inq);
524: m_freem(m);
525: } else {
526: IF_ENQUEUE(inq, m);
527: DEBUGF(undebug & 0x2, printf(" queued\n");)
528: }
529: break;
530: #endif ISO
531: default:
532: DEBUGF(undebug & 0x2, printf("unknown packet\n");)
533: m_freem(m);
534: break;
535: #else
536: default: {
537: struct llc *l;
538: caddr_t pkt_start;
539: #ifdef ISO
540: #define PREPENDED_SIZE sizeof(struct snpa_hdr)
541: #else
542: #define PREPENDED_SIZE sizeof(struct ifnet *)
543: #endif ISO
544: if (type > ETHERMTU)
545: goto not802;
546:
547: /*
548: * This assumes that the snpa header is in the same mbuf
549: * as the llc header. Currently this is ok, but if
550: * unget allocates a cluster, this will not be the case
551: */
552: pkt_start = mtod(m, caddr_t);
553: l = (struct llc *) (pkt_start + PREPENDED_SIZE);
554:
555: IFDEBUG(D_ETHER)
556: printf("unrint: llc: length %d, control x%x:\n", type,
557: l->llc_control);
558: ENDDEBUG
559:
560: switch (l->llc_control) {
561: case LLC_UI:
562: /* LLC_UI_P forbidden in class 1 service */
563: #ifdef ISO
564: if (l->llc_dsap == LLC_ISO_LSAP) {
565: if ((IS_MULTICAST(ehbuf.ether_dhost)) &&
566: ((us->us_if.if_flags & IFF_EAVESDROP) == 0) &&
567: (!snpac_ownmulti(ehbuf.ether_dhost, 6))) {
568: m_freem(m);
569: return;
570: }
571:
572: /* move struct snpa_header over the llc header */
573: clnp_ypocb(pkt_start, pkt_start + 3,
574: PREPENDED_SIZE);
575: m->m_off += 3;
576: m->m_len -= 3;
577:
578: DEBUGF(undebug & 0x2, printf("clnp packet\n");)
579: schednetisr(NETISR_CLNP);
580: inq = &clnlintrq;
581: if (IF_QFULL(inq)){
582: DEBUGF(undebug & 0x2, printf(" qfull\n");)
583: IF_DROP(inq);
584: m_freem(m);
585: } else {
586: IF_ENQUEUE(inq, m);
587: DEBUGF(undebug & 0x2, printf(" queued\n");)
588: }
589: return;
590: } else {
591: IFDEBUG(D_ETHER)
592: printf("unrint: unknown llc sap\n");
593: ENDDEBUG
594: m_freem(m);
595: return;
596: }
597: #endif ISO
598: break;
599: /* LLC_XID, LLC_XID_P, LLC_TEST, and LLC_TEST_P are untested */
600: case LLC_XID:
601: case LLC_XID_P: /* control field is untouched for resp */
602: if(m->m_len < 6)
603: goto not802;
604: l->llc_fid = LLC_IEEE_basic_format;
605: l->llc_class = LLC_CLASS1;
606: l->llc_window = 0;
607: l->llc_dsap = l->llc_ssap = 0;
608: /* FALL THROUGH */
609: case LLC_TEST:
610: case LLC_TEST_P: {
611: struct ifnet *ifp = &us->us_if;
612: struct sockaddr_iso siso;
613: u_char c = l->llc_dsap;
614: l->llc_dsap = l->llc_ssap;
615: l->llc_ssap = c;
616:
617: /* Do not TEST or XID to multicasts */
618: if (IS_MULTICAST(ehbuf.ether_dhost)) {
619: m_freem(m);
620: break;
621: }
622:
623: siso.siso_family = AF_ISO;
624: bcopy(ehbuf.ether_shost, siso.siso_addr.sna_idi, 6);
625: siso.siso_addr.isoa_afi = AFI_SNA;
626: siso.siso_addr.isoa_len = 7;
627:
628: /* trim off prepended snpa_hdr or ifp */
629: m->m_off += PREPENDED_SIZE;
630: m->m_len -= PREPENDED_SIZE;
631:
632: unoutput(ifp, m, &siso);
633: return;
634: }
635: not802:
636: default:
637: DEBUGF(undebug & 0x2, printf("unknown packet\n");)
638: m_freem(m);
639: break;
640: }
641: }
642: #endif IEEELLC
643: }
644: }
645: return;
646: chuckit:
647: DEBUGF(undebug, printf("unrint: packet dropped\n");)
648: unupdatefpp(addr, us->us_nextpage);
649: }
650:
651: /*
652: * unxint - interrupt handler for transmit ready
653: */
654: unxint(unit, us, addr)
655: register int unit;
656: register struct un_softc *us;
657: register struct undevice *addr;
658: {
659: register char status;
660: register int next_buf;
661:
662: /*
663: * collect stats on last packet
664: */
665: status = MM_IN(&addr->un_edlc.xstat);
666: MM_OUT(&addr->un_edlc.xstat, status); /* clear status bits */
667: DEBUGF(undebug & 0x2, printf(" unxint: xstat = %b\n",
668: status & 0xff, XS_BITS);)
669: if (status & XS_16CL){
670: us->us_if.if_collisions += 16;
671: us->us_if.if_oerrors++;
672: printf("un%d: ethernet jammed\n", unit);
673: }
674: else if (status & XS_SHRT){
675: us->us_if.if_oerrors++;
676: printf( "un%d: ethernet not responding (is it connected?)\n",
677: unit);
678: }
679: else {
680: us->us_if.if_opackets++;
681: us->us_if.if_collisions += UN_NCOLL(addr);
682: }
683: DEBUGF(undebug & 0x2,
684: printf(" ipkt = %d ierr = %d okt = %d oerr = %d coll = %d\n",
685: us->us_if.if_ipackets, us->us_if.if_ierrors,
686: us->us_if.if_opackets, us->us_if.if_oerrors,
687: us->us_if.if_collisions);)
688: /* mark the current transmit buffer empty */
689: us->us_xfull[us->us_xbuf] = 0;
690: /* switch to the other transmit buffer */
691: next_buf = 1 - us->us_xbuf;
692: if (us->us_xfull[next_buf]){ /* if it's full */
693: unstart(us, addr, next_buf); /* start output from it */
694: if (us->us_if.if_snd.ifq_head){ /* if more on out queue */
695: struct mbuf *m;
696:
697: IF_DEQUEUE(&us->us_if.if_snd, m); /* fill empty buf */
698: unput(us, addr, m, 1 - next_buf);
699: }
700: }
701: else { /* the other transmit buffer is empty */
702: us->us_oactive = 0;
703: MM_OUT(&addr->un_csr, UN_PAVIENB); /* Turn off TxRIENB */
704: }
705: }
706:
707: /*
708: * unoutput - ethernet output routine. encapsulate a packet of type
709: * family for the local net. use trailer local net encapsulation if
710: * the number of bytes in the mbufs after the first is a multiple of
711: * 512.
712: */
713: unoutput(ifp, m0, dst)
714: register struct ifnet *ifp;
715: register struct mbuf *m0;
716: register struct sockaddr *dst;
717: {
718: u_short type;
719: int s;
720: int error;
721: char edst[ETH_ADDR_SIZE];
722: struct in_addr idst;
723: register struct un_softc *us = &un_softc[ifp->if_unit];
724: register struct mbuf *m = m0;
725: register struct ether_header *eh;
726: int off;
727: struct mbuf *m_get();
728: int usetrailers;
729:
730: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)){
731: error = ENETDOWN;
732: goto bad;
733: }
734: switch (dst->sa_family){
735:
736: #ifdef INET
737: case AF_INET:
738: idst = ((struct sockaddr_in *)dst)->sin_addr;
739: if (!arpresolve(&us->us_ac, m, &idst, edst, &usetrailers)){
740: /* not resolved */
741: return(0);
742: }
743: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
744: if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
745: m->m_off >= MMINOFF + 2 * sizeof(u_short)){
746: type = ETHERTYPE_TRAIL + (off>>9);
747: m->m_off -= 2 * sizeof(u_short);
748: m->m_len += 2 * sizeof(u_short);
749: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
750: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
751: /*
752: * Packet to be sent with trailer, move first packet
753: * (control information) to end of chain.
754: */
755: while (m->m_next)
756: m = m->m_next;
757: m->m_next = m0;
758: m = m0->m_next;
759: m0->m_next = 0;
760: m0 = m;
761: }
762: else {
763: type = ETHERTYPE_IP;
764: }
765: break;
766: #endif INET
767: #ifdef NS
768: case AF_NS:
769: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
770: (caddr_t)edst, sizeof(edst));
771: type = ETHERTYPE_NS;
772: off = 0;
773: break;
774: #endif NS
775: #ifdef ISO
776: case AF_ISO: {
777: int ret;
778: int len;
779: struct iso_addr *dst_nsap = &((struct sockaddr_iso *)dst)->siso_addr;
780:
781: if ((ret = iso_tryloopback(m, dst)) >= 0)
782: return (ret);
783: else if (ret = iso_snparesolve(&us->us_ac.ac_if, dst_nsap, edst, &len)){
784: /* not resolved */
785: IFDEBUG(D_ETHER)
786: printf("unoutput: clnp packet dropped\n");
787: ENDDEBUG
788: m_freem(m);
789: return(ret);
790: } else if (len != 6) {
791: printf("unoutput: snpa len is not 6 (%d)\n", len);
792: m_freem(m);
793: return(ENETUNREACH);
794: }
795:
796: #ifndef IEEELLC
797: type = ETHERTYPE_CLNP;
798: #else
799: /* check for enough space for LLC header */
800: {
801: struct mbuf *llcm;
802: char *cp;
803: if (m->m_off >= MMAXOFF || m->m_off < MMINOFF + 3) {
804: MGET(llcm, M_DONTWAIT, MT_DATA);
805: if (llcm == NULL) {
806: m_freem(m);
807: return(0);
808: }
809: llcm->m_off = MMAXOFF - 3;
810: llcm->m_len = 3;
811: llcm->m_next = m;
812: m = llcm;
813: } else {
814: m->m_off -= 3;
815: m->m_len += 3;
816: }
817: type = m_datalen(m);
818:
819: cp = mtod(m, u_char *);
820: cp[0] = cp[1] = LLC_ISO_LSAP; cp[2] = LLC_UI;
821: off = 0;
822: }
823: #endif IEEELLC
824: off = 0;
825: IFDEBUG(D_ETHER)
826: int i;
827: printf("unoutput: sending pkt to: ");
828: for (i=0; i<6; i++)
829: printf("%x ", edst[i] & 0xff);
830: #ifdef IEEELLC
831: printf(" llc len %d", type);
832: #endif IEEELLC
833: printf("\n");
834: ENDDEBUG
835: } break;
836: #endif ISO
837: case AF_UNSPEC:
838: eh = (struct ether_header *)dst->sa_data;
839: bcopy((char *)eh->ether_dhost, (caddr_t)edst, sizeof(edst));
840: type = eh->ether_type;
841: break;
842: default:
843: printf("un%d: can't handle af%d\n", ifp->if_unit,
844: dst->sa_family);
845: error = EAFNOSUPPORT;
846: goto bad;
847: }
848: /*
849: * Add local net header. If no space in first mbuf,
850: * allocate another.
851: */
852: if (m->m_off > MMAXOFF ||
853: MMINOFF + sizeof(struct ether_header) > m->m_off){
854: m = m_get(M_DONTWAIT, MT_HEADER);
855: /*
856: * Note: m_get, m_freem etc. guard against concurrent
857: * updates to the list of free mbufs.
858: */
859: if (m == 0){
860: error = ENOBUFS;
861: goto bad;
862: }
863: m->m_next = m0;
864: m->m_off = MMINOFF;
865: m->m_len = sizeof(struct ether_header);
866: } else {
867: m->m_off -= sizeof(struct ether_header);
868: m->m_len += sizeof(struct ether_header);
869: }
870: eh = mtod(m, struct ether_header *);
871: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof(edst));
872: bcopy((caddr_t)us->us_addr, (caddr_t)eh->ether_shost,
873: sizeof(eh->ether_shost));
874: bcopy((caddr_t)&type, (caddr_t)&eh->ether_type, sizeof(u_short));
875:
876: /*
877: * queue packet for transmission. if there is an empty
878: * transmit buffer on the adapter, use it.
879: */
880: s = splimp();
881: if (IF_QFULL(&ifp->if_snd)){
882: IF_DROP(&ifp->if_snd);
883: error = ENOBUFS;
884: goto qfull;
885: }
886: if (us->us_xfull[0] == 0 || us->us_xfull[1] == 0){ /* empty xmt buf */
887: struct undevice *addr = (struct undevice *)
888: uninfo[ifp->if_unit]->iod_addr;
889: int next_buf;
890: #ifdef ATR
891: int old_window;
892: move_window(old_window, addr);
893: #endif ATR
894: if (us->us_xfull[0] == 0){
895: next_buf = 0;
896: }
897: else {
898: next_buf = 1;
899: }
900: unput(us, addr, m, next_buf);
901: if (us->us_oactive == 0){
902: unstart(us, addr, next_buf);
903: }
904: #ifdef ATR
905: restore_window(old_window);
906: #endif ATR
907: }
908: else {
909: IF_ENQUEUE(&ifp->if_snd, m);
910: }
911: splx(s);
912: return(0);
913: qfull:
914: m0 = m;
915: splx(s);
916: bad:
917: m_freem(m0);
918: return(error);
919: }
920:
921: /*
922: * unput - copy packet from an mbuf chain to one of the adapter's
923: * transmit buffers. the packet is extended to the minimum legal
924: * size if necessary. the extra bytes could be zeroed out to improve
925: * security but are not to maximize performance.
926: */
927: unput(us, addr, m, xbuf)
928: struct un_softc *us;
929: struct undevice *addr;
930: register struct mbuf *m;
931: register int xbuf;
932: {
933: register unsigned off;
934: register struct mbuf *mp;
935: register char *bp;
936:
937: /*
938: * compute starting address in transmit buffer. packets must be
939: * "end_aligned".
940: */
941: for (off = UN_XBSIZE, mp = m; mp; mp = mp->m_next){
942: off -= mp->m_len;
943: }
944: if (UN_XBSIZE - off < ETHERMIN + sizeof(struct ether_header)){
945: /* packet too short => extend it */
946: off = UN_XBSIZE - ETHERMIN - sizeof(struct ether_header);
947: }
948: if (xbuf == 1){ /* use the second buffer */
949: off += UN_XBSIZE; /* the 2 buffers are adjacent */
950: }
951: bp = ((char *)(addr->un_xmtbuf)) + off;
952: for (mp = m; mp; mp = mp->m_next){
953: register unsigned len = mp->m_len;
954:
955: bcopyout(mtod(mp, char *), bp, len);
956: bp += len;
957: }
958: /* save starting address so interrupt handler can find it */
959: us->us_xstart[xbuf] = off; /* start address to be passed to adapter */
960: us->us_xfull[xbuf] = 1; /* mark buffer full */
961: m_freem(m);
962: }
963:
964: /*
965: * unget - copy packet from adapter's receive buffers into a chain of mbufs
966: *
967: */
968: struct mbuf *
969: unget(addr, unbuf, totlen, off0, ifp)
970: struct undevice *addr;
971: char *unbuf;
972: register int totlen;
973: int off0;
974: struct ifnet *ifp;
975: {
976: register struct mbuf *m;
977: struct mbuf *top = 0;
978: register struct mbuf **mp = ⊤
979: register int off = off0;
980: register int len;
981: register char *cp;
982: #ifdef ISO
983: int copied_snpa = 0;
984: #endif ISO
985:
986: cp = unbuf + sizeof(struct ether_header);
987: while (totlen > 0){
988: char *mcp;
989:
990: MGET(m, M_DONTWAIT, MT_DATA);
991: if (m == 0)
992: goto bad;
993: if (off){ /* trailer exists */
994: len = totlen - off;
995: cp = unbuf + sizeof(struct ether_header) + off;
996: } else
997: len = totlen;
998: #ifdef ISO
999: if (!copied_snpa)
1000: len += sizeof(struct snpa_hdr);
1001: #else ISO
1002: if (ifp)
1003: len += sizeof(ifp);
1004: #endif ISO
1005: if (len >= NBPG){
1006: MCLGET(m);
1007: if (m->m_len == CLBYTES)
1008: m->m_len = len = MIN(len, CLBYTES);
1009: else
1010: m->m_len = len = MIN(MLEN, len);
1011: } else {
1012: m->m_len = len = MIN(MLEN, len);
1013: m->m_off = MMINOFF;
1014: }
1015: mcp = mtod(m, char *);
1016: #ifdef ISO
1017: if (!copied_snpa) {
1018: /*
1019: * Prepend snpa_hdr to first mbuf
1020: * The hardcoded 12 below refers to the length of the dhost
1021: * and shost fields. We recklessly assume
1022: * the order of dhost,shost in the snpa_hdr is the same
1023: * as the order in the ether_header.
1024: */
1025: struct snpa_hdr *sh = (struct snpa_hdr *)mcp;
1026: struct ether_header *eh = (struct ether_header *)unbuf;
1027:
1028: bcopy((char *) &ifp, (caddr_t)&sh->snh_ifp, sizeof(ifp));
1029: bcopy((caddr_t)eh, (caddr_t)sh->snh_dhost, 12);
1030: mcp += sizeof(struct snpa_hdr);
1031: len -= sizeof(struct snpa_hdr);
1032: copied_snpa = 1;
1033: }
1034: #else ISO
1035: if (ifp){
1036: /* prepend ifp to first mbuf */
1037: /*
1038: * bcopy is used since since word moves must
1039: * be on 4 byte boundaries on the RT PC
1040: */
1041: bcopy((char *) &ifp, mcp, sizeof(ifp));
1042: mcp += sizeof(ifp);
1043: len -= sizeof(ifp);
1044: ifp = (struct ifnet *) 0;
1045: }
1046: #endif ISO
1047: unbcopy(addr, cp, mcp, len);
1048: cp += len;
1049: *mp = m;
1050: mp = &m->m_next;
1051: if (off == 0){
1052: totlen -= len;
1053: continue;
1054: }
1055: off += len;
1056: if (off == totlen){
1057: cp = unbuf + sizeof(struct ether_header);
1058: off = 0;
1059: totlen = off0;
1060: }
1061: }
1062: return(top);
1063: bad:
1064: m_freem(top);
1065: return(0);
1066: }
1067:
1068:
1069: /*
1070: * ioctl - process an ioctl request.
1071: */
1072: unioctl(ifp, cmd, data)
1073: register struct ifnet *ifp;
1074: register int cmd;
1075: register caddr_t data;
1076: {
1077: register struct ifaddr *ifa = (struct ifaddr *)data;
1078: register int s = splimp();
1079: register int error = 0;
1080:
1081: switch (cmd){
1082: case SIOCSIFADDR:
1083: ifp->if_flags |= IFF_UP;
1084:
1085: switch (ifa->ifa_addr.sa_family){
1086: #ifdef INET
1087: case AF_INET:
1088: uninit(ifp->if_unit); /* before arpwhohas */
1089: ((struct arpcom *) ifp)->ac_ipaddr =
1090: IA_SIN(ifa)->sin_addr;
1091: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1092: break;
1093: #endif INET
1094: #ifdef NS
1095: case AF_NS:
1096: {
1097: struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1098: struct un_softc *us = &un_softc[ifp->if_unit];
1099:
1100: if (ns_nullhost(*ina))
1101: ina->x_host = *(union ns_host *)(us->us_addr);
1102: else {
1103: ifp->if_flags &= ~IFF_RUNNING;
1104: bcopy((caddr_t) ina->x_host.c_host,
1105: (caddr_t) us->us_addr, sizeof(us->us_addr));
1106: /*
1107: * the uninit will set the hardware address
1108: * since the IFF_RUNNING flag is off
1109: */
1110: }
1111: uninit(ifp->if_unit);
1112: break;
1113: }
1114: #endif NS
1115: default:
1116: uninit(ifp->if_unit);
1117: break;
1118: }
1119: break;
1120: case SIOCSIFFLAGS:
1121: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags &
1122: IFF_RUNNING){
1123: #ifdef ATR
1124: int old_window;
1125: #endif ATR
1126: struct undevice *addr;
1127:
1128: addr = (struct undevice *) uninfo[ifp->if_unit]->
1129: iod_addr;
1130: #ifdef ATR
1131: move_window(old_window, addr);
1132: #endif ATR
1133: (void) unzap((struct undevice *) addr);
1134: ifp->if_flags &= ~IFF_RUNNING;
1135: #ifdef ATR
1136: restore_window(old_window);
1137: #endif ATR
1138: } else if (ifp->if_flags & IFF_UP && (ifp->if_flags &
1139: IFF_RUNNING) == 0)
1140: uninit(ifp->if_unit);
1141: break;
1142: default:
1143: error = EINVAL;
1144: }
1145: splx(s);
1146: return(error);
1147: }
1148:
1149: /*
1150: * unzap - initialize adapter but don't enable it.
1151: * returns page number of next receive page to be used.
1152: */
1153: unzap(addr)
1154: register struct undevice *addr;
1155: {
1156: register int next;
1157:
1158: MM_OUT(&addr->un_csr, 0); /* disable interrupts */
1159: MM_OUT(&addr->un_edlc.reset, RESET_ON);
1160: /* set reset bit while init'ing */
1161: MM_OUT(&addr->un_edlc.rstat, RS_CLEAR);
1162: MM_OUT(&addr->un_edlc.xstat, XS_CLEAR);
1163: MM_OUT(&addr->un_edlc.rmask, 0);
1164: MM_OUT(&addr->un_edlc.xmask, 0);
1165: MM_OUT(&addr->un_edlc.rmode, RM_NORMAL);
1166: /*
1167: * the next line puts the transmitter in loopback mode so
1168: * that a spurious packet is not sent when the reset bit is
1169: * cleared.
1170: */
1171: MM_OUT(&addr->un_edlc.tmode, TM_NORMAL - TM_LBC);
1172: MM_OUT(&addr->un_edlc.reset, RESET_OFF); /* clear reset bit */
1173: /*
1174: * clear the receive buffers. assign the value in the empty
1175: * page pointer to the full page pointer and clear the packet
1176: * available flag.
1177: */
1178: next = MM_IN(&addr->un_fppepp) & UN_PAGE_MASK;
1179: /* clears the IKSYDK flag */
1180: MM_OUT(&addr->un_fppepp, next); /* fpp = epp */
1181: UN_CLRPAV(addr); /* clear the PAV flag */
1182: MM_OUT(&addr->un_edlc.tmode, TM_NORMAL);
1183: /* put transmitter in normal mode */
1184: DEBUGF(undebug & 0x2, printf("unzap: zzzzapped!\n");)
1185: return(next);
1186: }
1187:
1188: /*
1189: * unupdatefpp - update adapter's full page pointer and clear packet available
1190: * flag if appropriate
1191: */
1192: unupdatefpp(addr, nextpage)
1193: register struct undevice *addr;
1194: register int nextpage;
1195: {
1196: if (nextpage == /* EPP */ (MM_IN(&addr->un_fppepp) & UN_PAGE_MASK))
1197: UN_CLRPAV(addr);
1198: MM_OUT(&addr->un_fppepp, nextpage); /* set FPP */
1199: }
1200:
1201: /*
1202: * unbcopy - similar to bcopy but can deal with packets that wrap
1203: * around from the high end of the adapter's receive buffer to the
1204: * low end
1205: */
1206: unbcopy(addr, from, to, len)
1207: register struct undevice *addr;
1208: register char *from;
1209: register char *to;
1210: register int len;
1211: {
1212: register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE];
1213: register int n;
1214:
1215: if (from + len <= high_end){
1216: bcopyin(from, to, len);
1217: }
1218: else if (from >= high_end){
1219: from -= sizeof(addr->un_rcvbuf);
1220: bcopyin(from, to, len);
1221: } else {
1222: n = high_end - from;
1223: bcopyin(from, to, n);
1224: to += n;
1225: bcopyin((char *)addr->un_rcvbuf, to, len - n);
1226: }
1227: }
1228:
1229: /*
1230: * ungetushortatoff - return the u_short at offset in the received packet,
1231: * handling wrap-around in the receive buffer and conversion between network
1232: * and host formats as necessary.
1233: */
1234: u_short ungetushortatoff(addr, eh, off)
1235: register struct undevice *addr;
1236: register struct ether_header *eh;
1237: register int off;
1238: {
1239: register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE];
1240: register char *p;
1241:
1242: p = (caddr_t)(eh + 1) + off;
1243: if (p >= high_end){
1244: p -= sizeof(addr->un_rcvbuf);
1245: }
1246: return(ntohs((u_short) MM_INW(p)));
1247: }
1248:
1249: /*
1250: * unprintethaddr - print an ethernet address
1251: */
1252: unprintethaddr(p)
1253: register char *p;
1254: {
1255: register int i;
1256:
1257: for (i = 0; i < ETH_ADDR_SIZE; i++){
1258: if (i != 0) printf(":");
1259: printf("%x", *p++);
1260: }
1261: }
1262:
1263: #endif NUN > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.