trailing comment after #else or #endif
[unix-history] / usr / src / sys / netiso / if_un.eg
CommitLineData
8b1363a5
KB
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) %G%
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
76int unprobe(), unattach();
77
78#ifdef AT
79caddr_t unstd[] = { (caddr_t) 0xa0000, (caddr_t) 0xa8000,
80 (caddr_t) 0xb0000, (caddr_t) 0xb8000, 0 };
81#else
82caddr_t unstd[] = { (caddr_t) 0xf4080000, (caddr_t) 0xf4088000,
83 (caddr_t) 0xf4090000, (caddr_t) 0xf4098000, 0 };
84#endif AT
85
86struct iocc_device *uninfo[NUN];
87
88int unint(), uninit(), unioctl(), unoutput(), unreset();
89
90struct iocc_driver undriver =
91 { unprobe, 0, unattach, 0, unstd, "un", uninfo,
92 0, 0, unint, UN_EADDROFF };
93
94struct mbuf *unget();
95
96/*
97 * Ethernet software status per adapter.
98 */
99struct 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
111char 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 */
138unprobe(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 */
163unattach(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 */
213unreset(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 */
229uninit(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 */
283unstart(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 */
298unint(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 */
340unrint(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;
646chuckit:
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 */
654unxint(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 */
713unoutput(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);
913qfull:
914 m0 = m;
915 splx(s);
916bad:
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 */
927unput(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 */
968struct mbuf *
969unget(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 = &top;
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);
1063bad:
1064 m_freem(top);
1065 return(0);
1066}
1067
1068
1069/*
1070 * ioctl - process an ioctl request.
1071 */
1072unioctl(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 */
1153unzap(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 */
1192unupdatefpp(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 */
1206unbcopy(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 */
1234u_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 */
1252unprintethaddr(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