1st working version
[unix-history] / usr / src / sys / i386 / isa / if_we.c
CommitLineData
11dcaca6
WN
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Tim L. Tucker
7 *
8 * %sccs.include.noredist.c%
9 *
4ad9a99e 10 * @(#)if_we.c 5.2 (Berkeley) %G%
11dcaca6
WN
11 */
12
13/*
14 * Modification history
15 *
4ad9a99e 16 * 8/28/89 - Initial version(if_wd.c), Tim L Tucker
11dcaca6
WN
17 */
18
4ad9a99e
BJ
19#include "we.h"
20#if NWE > 0
11dcaca6
WN
21/*
22 * Western Digital 8003 ethernet/starlan adapter
23 *
24 * Supports the following interface cards:
25 * WD8003E, WD8003EBT, WD8003S, WD8003SBT
26 *
27 * The Western Digital card is one of many AT/MCA ethernet interfaces
28 * based on the National N8390/NS32490 Network Interface chip set.
29 */
30#include "param.h"
31#include "mbuf.h"
32#include "socket.h"
33#include "ioctl.h"
34#include "errno.h"
35#include "syslog.h"
36
37#include "../net/if.h"
38#include "../net/netisr.h"
39
40#ifdef INET
41#include "../netinet/in.h"
42#include "../netinet/in_systm.h"
43#include "../netinet/in_var.h"
44#include "../netinet/ip.h"
45#include "../netinet/if_ether.h"
46#endif
47
48#ifdef NS
49#include "../netns/ns.h"
50#include "../netns/ns_if.h"
51#endif
52
4ad9a99e
BJ
53#include "machine/isa/if_wereg.h"
54#include "machine/isa/device.h"
11dcaca6
WN
55
56/*
4ad9a99e 57 * This constant should really be 60 because the we adds 4 bytes of crc.
11dcaca6
WN
58 * However when set to 60 our packets are ignored by deuna's , 3coms are
59 * okay ??????????????????????????????????????????
60 */
61#define ETHER_MIN_LEN 64
62#define ETHER_ADDR_LEN 6
63#define ETHER_HDR_SIZE 14
64
65/*
66 * Ethernet software status per interface.
67 *
68 * Each interface is referenced by a network interface structure,
69 * qe_if, which the routing code uses to locate the interface.
70 * This structure contains the output queue for the interface, its address, ...
71 */
4ad9a99e
BJ
72struct we_softc {
73 struct arpcom we_ac; /* Ethernet common part */
74#define we_if we_ac.ac_if /* network-visible interface */
75#define we_addr we_ac.ac_enaddr /* hardware Ethernet address */
11dcaca6 76
4ad9a99e 77 u_char we_flags; /* software state */
11dcaca6
WN
78#define WDF_RUNNING 0x01
79#define WDF_TXBUSY 0x02
80
4ad9a99e
BJ
81 u_char we_type; /* interface type code */
82 u_short we_vector; /* interrupt vector */
83 caddr_t we_io_ctl_addr; /* i/o bus address, control */
84 caddr_t we_io_nic_addr; /* i/o bus address, NS32490 */
11dcaca6 85
4ad9a99e
BJ
86 caddr_t we_vmem_addr; /* card RAM virtual memory base */
87 u_long we_vmem_size; /* card RAM bytes */
88 caddr_t we_vmem_ring; /* receive ring RAM vaddress */
89} we_softc[NWE];
11dcaca6 90
4ad9a99e
BJ
91int weprobe(), weattach(), weintr();
92int weinit(), weoutput(), weioctl(), wereset();
93
94struct isa_driver wedriver = {
95 weprobe, weattach, "we",
96};
11dcaca6
WN
97
98/*
99 * Probe the WD8003 to see if it's there
100 */
4ad9a99e 101weprobe(is)
11dcaca6
WN
102 struct isa_device *is;
103{
104 register int i;
4ad9a99e
BJ
105 register struct we_softc *sc = &we_softc[is->id_unit];
106 union we_mem_sel wem;
11dcaca6
WN
107 u_char sum;
108
109 /*
110 * Here we check the card ROM, if the checksum passes, and the
111 * type code and ethernet address check out, then we know we have
112 * a wd8003 card.
113 *
114 * Autoconfiguration: No warning message is printed on error.
115 */
116 for (sum = 0, i = 0; i < 8; ++i)
4ad9a99e 117 sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
11dcaca6
WN
118 if (sum != WD_CHECKSUM)
119 return (0);
4ad9a99e
BJ
120 sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
121 if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN)
122 && (sc->we_type != WD_ETHER2))
11dcaca6
WN
123 return (0);
124
125 /*
126 * Setup card RAM area and i/o addresses
127 * Kernel Virtual to segment C0000-DFFFF?????
128 */
4ad9a99e
BJ
129 sc->we_io_ctl_addr = is->id_iobase;
130 sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
131 sc->we_vector = is->id_irq;
132 sc->we_vmem_addr = (caddr_t)is->id_maddr;
133 sc->we_vmem_size = is->id_msize;
134 sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
11dcaca6
WN
135
136 /*
137 * Save board ROM station address
138 */
139 for (i = 0; i < ETHER_ADDR_LEN; ++i)
4ad9a99e 140 sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
11dcaca6
WN
141
142 /*
143 * Mapin interface memory, setup memory select register
144 */
4ad9a99e
BJ
145 /* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */
146 wem.ms_addr = (u_long)(0xd0000)>> 13;
147 wem.ms_enable = 1;
148 wem.ms_reset = 0;
149 outb(sc->we_io_ctl_addr, wem.ms_byte);
11dcaca6
WN
150
151 /*
152 * clear interface memory, then sum to make sure its valid
153 */
4ad9a99e
BJ
154 for (i = 0; i < sc->we_vmem_size; ++i)
155 sc->we_vmem_addr[i] = 0x0;
156 for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
157 sum += sc->we_vmem_addr[i];
11dcaca6 158 if (sum != 0x0) {
4ad9a99e 159 printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
11dcaca6
WN
160 return (0);
161 }
162
163 return (WD_IO_PORTS);
164}
165
166/*
167 * Interface exists: make available by filling in network interface
168 * record. System will initialize the interface when it is ready
169 * to accept packets.
170 */
4ad9a99e 171weattach(is)
11dcaca6
WN
172 struct isa_device *is;
173{
4ad9a99e
BJ
174 register struct we_softc *sc = &we_softc[is->id_unit];
175 register struct ifnet *ifp = &sc->we_if;
11dcaca6
WN
176
177 /*
178 * Initialize ifnet structure
179 */
4ad9a99e
BJ
180 ifp->if_unit = is->id_unit;
181 ifp->if_name = "we";
11dcaca6
WN
182 ifp->if_mtu = ETHERMTU;
183 ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS;
4ad9a99e
BJ
184 ifp->if_init = weinit;
185 ifp->if_output = weoutput;
186 ifp->if_ioctl = weioctl;
187 ifp->if_reset = wereset;
11dcaca6
WN
188 ifp->if_watchdog = 0;
189 if_attach(ifp);
190
191 /*
192 * Banner...
193 */
4ad9a99e
BJ
194 printf(" %s address %s",
195 ((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"),
196 ether_sprintf(sc->we_addr));
11dcaca6
WN
197}
198
199/*
200 * Reset of interface.
201 */
4ad9a99e 202wereset(unit, uban)
11dcaca6
WN
203 int unit, uban;
204{
4ad9a99e 205 if (unit >= NWE)
11dcaca6 206 return;
4ad9a99e
BJ
207 printf("we%d: reset\n", unit);
208 we_softc[unit].we_flags &= ~WDF_RUNNING;
209 weinit(unit);
11dcaca6
WN
210}
211
212/*
213 * Take interface offline.
214 */
4ad9a99e 215westop(unit)
11dcaca6
WN
216 int unit;
217{
4ad9a99e
BJ
218 register struct we_softc *sc = &we_softc[unit];
219 union we_command wecmd;
11dcaca6
WN
220 int s;
221
222 /*
223 * Shutdown NS32490
224 */
225 s = splimp();
4ad9a99e
BJ
226 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
227 wecmd.cs_stp = 1;
228 wecmd.cs_sta = 0;
229 wecmd.cs_ps = 0;
230 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
11dcaca6
WN
231 (void) splx(s);
232}
233
234/*
235 * Initialization of interface (really just NS32490).
236 */
4ad9a99e 237weinit(unit)
11dcaca6
WN
238 int unit;
239{
4ad9a99e
BJ
240 register struct we_softc *sc = &we_softc[unit];
241 register struct ifnet *ifp = &sc->we_if;
242 union we_command wecmd;
11dcaca6
WN
243 int i, s;
244
245 /* address not known */
246 if (ifp->if_addrlist == (struct ifaddr *)0)
247 return;
248
249 /* already running */
4ad9a99e 250 if (sc->we_flags & WDF_RUNNING)
11dcaca6
WN
251 return;
252
253 /*
254 * Initialize NS32490 in order given in NSC NIC manual.
255 * this is stock code...please see the National manual for details.
256 */
4ad9a99e
BJ
257 s = splhigh();
258 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
259 wecmd.cs_stp = 1;
260 wecmd.cs_sta = 0;
261 wecmd.cs_ps = 0;
262 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
263 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
264 outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
265 outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
266 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
267 outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
268 outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
269 outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
270 outb(sc->we_io_nic_addr + WD_P0_PSTOP,
271 sc->we_vmem_size / WD_PAGE_SIZE);
272 outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
273 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
274#define WD_I_CONFIG 0xff
275 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
276 wecmd.cs_ps = 1;
277 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
11dcaca6 278 for (i = 0; i < ETHER_ADDR_LEN; ++i)
4ad9a99e 279 outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
11dcaca6 280 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */
4ad9a99e
BJ
281 outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
282 outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
283 wecmd.cs_ps = 0;
284 wecmd.cs_stp = 0;
285 wecmd.cs_sta = 1;
286 wecmd.cs_rd = 0x4;
287 outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
288 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
11dcaca6
WN
289
290 /*
291 * Take the interface out of reset, program the vector,
292 * enable interrupts, and tell the world we are up.
293 */
294 ifp->if_flags |= IFF_UP | IFF_RUNNING;
4ad9a99e
BJ
295 sc->we_flags |= WDF_RUNNING;
296 sc->we_flags &= ~WDF_TXBUSY;
11dcaca6 297 (void) splx(s);
4ad9a99e 298 westart(unit);
11dcaca6
WN
299}
300
301/*
302 * Start output on interface.
303 */
4ad9a99e 304westart(unit)
11dcaca6
WN
305 int unit;
306{
4ad9a99e 307 register struct we_softc *sc = &we_softc[unit];
11dcaca6
WN
308 struct mbuf *m0, *m;
309 register caddr_t buffer;
310 int len = 0, s;
4ad9a99e 311 union we_command wecmd;
11dcaca6
WN
312
313 /*
314 * The NS32490 has only one transmit buffer, if it is busy we
315 * must wait until the transmit interrupt completes.
316 */
4ad9a99e
BJ
317 s = splhigh();
318 if (sc->we_flags & WDF_TXBUSY) {
11dcaca6
WN
319 (void) splx(s);
320 return;
321 }
4ad9a99e 322 IF_DEQUEUE(&sc->we_if.if_snd, m);
11dcaca6
WN
323 if (m == 0) {
324 (void) splx(s);
325 return;
326 }
4ad9a99e 327 sc->we_flags |= WDF_TXBUSY;
11dcaca6
WN
328 (void) splx(s);
329
330 /*
331 * Copy the mbuf chain into the transmit buffer
332 */
4ad9a99e 333 buffer = sc->we_vmem_addr;
11dcaca6
WN
334 for (m0 = m; m != 0; m = m->m_next) {
335 bcopy(mtod(m, caddr_t), buffer, m->m_len);
336 buffer += m->m_len;
337 len += m->m_len;
338 }
339
340 /*
341 * If this was a broadcast packet loop it
342 * back because the hardware can't hear its own
343 * transmits.
344 */
4ad9a99e 345#ifdef notyet
11dcaca6
WN
346 if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
347 (caddr_t)etherbroadcastaddr,
348 sizeof(etherbroadcastaddr)) == 0) {
4ad9a99e 349 weread(sc, m0);
11dcaca6 350 } else {
4ad9a99e 351#endif
11dcaca6 352 m_freem(m0);
4ad9a99e 353#ifdef notyet
11dcaca6 354 }
4ad9a99e 355#endif
11dcaca6
WN
356
357 /*
358 * Init transmit length registers, and set transmit start flag.
359 */
4ad9a99e 360 s = splhigh();
11dcaca6 361 len = MAX(len, ETHER_MIN_LEN);
4ad9a99e
BJ
362 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
363 wecmd.cs_ps = 0;
364 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
365 outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
366 outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
367 wecmd.cs_txp = 1;
368 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
11dcaca6
WN
369 (void) splx(s);
370}
371
372/*
373 * Ethernet interface interrupt processor
374 */
4ad9a99e 375weintr(unit)
11dcaca6
WN
376 int unit;
377{
4ad9a99e
BJ
378 register struct we_softc *sc = &we_softc[0];
379 union we_command wecmd;
380 union we_interrupt weisr;
11dcaca6 381 int s;
4ad9a99e 382 unit =0;
11dcaca6
WN
383
384 /* disable onboard interrupts, then get interrupt status */
4ad9a99e
BJ
385 s = splhigh();
386 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
387 wecmd.cs_ps = 0;
388 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
389 /* outb(sc->we_io_nic_addr + WD_P0_IMR, 0); */
390 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
391#ifdef notdef
392printf("weintr %x ", inb(sc->we_io_nic_addr + WD_P0_ISR));
393outb(sc->we_io_nic_addr+WD_P0_IMR,0xff);
394#endif
395 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
11dcaca6
WN
396 (void) splx(s);
397
398 /* transmit error */
4ad9a99e
BJ
399 if (weisr.is_txe) {
400printf("txe\n");
11dcaca6 401 /* need to read these registers to clear status */
4ad9a99e
BJ
402 sc->we_if.if_collisions +=
403 inb(sc->we_io_nic_addr + WD_P0_TBCR0);
404 ++sc->we_if.if_oerrors;
11dcaca6
WN
405 }
406
407 /* receiver error */
4ad9a99e
BJ
408 if (weisr.is_rxe) {
409printf("rxe\n");
11dcaca6 410 /* need to read these registers to clear status */
4ad9a99e
BJ
411 (void) inb(sc->we_io_nic_addr + 0xD);
412 (void) inb(sc->we_io_nic_addr + 0xE);
413 (void) inb(sc->we_io_nic_addr + 0xF);
414 ++sc->we_if.if_ierrors;
11dcaca6
WN
415 }
416
417 /* normal transmit complete */
4ad9a99e
BJ
418 if (weisr.is_ptx)
419 wetint (unit);
11dcaca6
WN
420
421 /* normal receive notification */
4ad9a99e
BJ
422 if (weisr.is_prx)
423 werint (unit);
11dcaca6
WN
424
425 /* try to start transmit */
4ad9a99e 426 westart(unit);
11dcaca6
WN
427
428 /* re-enable onboard interrupts */
4ad9a99e
BJ
429 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
430 wecmd.cs_ps = 0;
431 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
432 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
11dcaca6
WN
433}
434
435/*
436 * Ethernet interface transmit interrupt.
437 */
4ad9a99e 438wetint(unit)
11dcaca6
WN
439 int unit;
440{
4ad9a99e 441 register struct we_softc *sc = &we_softc[unit];
11dcaca6
WN
442
443 /*
444 * Do some statistics (assume page zero of NIC mapped in)
445 */
4ad9a99e
BJ
446 sc->we_flags &= ~WDF_TXBUSY;
447 sc->we_if.if_timer = 0;
448 ++sc->we_if.if_opackets;
449 sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
11dcaca6
WN
450}
451
452/*
453 * Ethernet interface receiver interrupt.
454 */
4ad9a99e 455werint(unit)
11dcaca6
WN
456 int unit;
457{
4ad9a99e 458 register struct we_softc *sc = &we_softc[unit];
11dcaca6
WN
459 register struct mbuf **m;
460 int mlen, len, count;
461 u_char bnry, curr;
4ad9a99e
BJ
462 union we_command wecmd;
463 struct we_ring *wer;
11dcaca6
WN
464 struct mbuf *m0;
465 caddr_t pkt, endp;
4ad9a99e 466static Bdry;
11dcaca6
WN
467
468 /*
469 * Traverse the receive ring looking for packets to pass back.
470 * The search is complete when we find a descriptor not in use.
471 */
4ad9a99e
BJ
472 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
473 wecmd.cs_ps = 0;
474 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
475 bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
476 wecmd.cs_ps = 1;
477 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
478 curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
479printf("Bd %x cur %x ", bnry, curr);
480if(Bdry && Bdry > bnry){
481 bnry =Bdry;
482printf("bd %x! ", bnry);
483}
11dcaca6
WN
484 while (bnry != curr)
485 {
486 /* get pointer to this buffer header structure */
4ad9a99e
BJ
487 wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
488 len = wer->we_count - 4; /* count includes CRC */
489printf("l %d", len);
490 pkt = (caddr_t)(wer + 1) /*- 2*/; /* 2 - word align pkt data */
491 count = len /*+ 2*/; /* copy two extra bytes */
492 endp = (caddr_t)(sc->we_vmem_addr + sc->we_vmem_size);
493 ++sc->we_if.if_ipackets;
11dcaca6
WN
494
495 /* pull packet out of dual ported RAM */
496 m = &m0; m0 = 0;
497 while (count > 0)
498 {
499 /* drop chain if can't get another buffer */
500 MGET(*m, M_DONTWAIT, MT_DATA);
501 if (*m == 0)
502 {
503 m_freem(m0);
504 goto outofbufs;
505 }
506
507 /* fill mbuf and attach to packet list */
508 mlen = MIN(MLEN, count);
509 mlen = MIN(mlen, endp - pkt);
510 bcopy(pkt, mtod(*m, caddr_t), mlen);
511 (*m)->m_len = mlen;
512 m = &((*m)->m_next);
513 pkt += mlen;
514 count -= mlen;
515
516 /* wrap memory pointer around circ buffer */
517 if (pkt == endp)
4ad9a99e 518 pkt = (caddr_t)sc->we_vmem_ring;
11dcaca6
WN
519 }
520
521 /* skip aligment bytes, send packet up to higher levels */
522 if (m0 != 0)
523 {
4ad9a99e
BJ
524/* m0->m_off += 2*/;
525 weread(sc, m0);
11dcaca6
WN
526 }
527
528outofbufs:
529 /* advance on chip Boundry register */
4ad9a99e
BJ
530printf("nx %x ", wer->we_next_packet);
531 bnry = wer->we_next_packet;
532 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
533 wecmd.cs_ps = 0;
534 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
11dcaca6
WN
535
536 /* watch out for NIC overflow, reset Boundry if invalid */
537 if ((bnry - 1) < WD_TXBUF_SIZE) {
538#ifdef notdef
4ad9a99e 539 wereset(unit, 0);
11dcaca6
WN
540 break;
541#else
4ad9a99e
BJ
542 outb(sc->we_io_nic_addr + WD_P0_BNRY,
543 (sc->we_vmem_size / WD_PAGE_SIZE) - 1);
11dcaca6
WN
544#endif
545 }
4ad9a99e 546 outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
11dcaca6
WN
547
548 /* refresh our copy of CURR */
4ad9a99e
BJ
549 wecmd.cs_ps = 1;
550 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
551 curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
552printf("bd %x cur %x ", bnry-1, curr);
11dcaca6 553 }
4ad9a99e
BJ
554printf("bD %x\n", bnry);
555Bdry = bnry;
11dcaca6
WN
556}
557
558/*
559 * Ethernet output routine.
560 * Encapsulate a packet of type family for the local net.
561 */
4ad9a99e 562weoutput(ifp, m0, dst)
11dcaca6
WN
563 struct ifnet *ifp;
564 struct mbuf *m0;
565 struct sockaddr *dst;
566{
567 int type, s, error;
568 u_char edst[6];
569 struct in_addr idst;
4ad9a99e 570 register struct we_softc *sc = &we_softc[ifp->if_unit];
11dcaca6
WN
571 register struct mbuf *m = m0;
572 register struct ether_header *eh;
573 int usetrailers;
574
575 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
576 error = ENETDOWN;
577 goto bad;
578 }
579
580 switch (dst->sa_family) {
581
582#ifdef INET
583 case AF_INET:
584 /* Note: we ignore usetrailers */
585 idst = ((struct sockaddr_in *)dst)->sin_addr;
4ad9a99e 586 if (!arpresolve(&sc->we_ac, m, &idst, edst, &usetrailers))
11dcaca6
WN
587 return (0); /* if not yet resolved */
588 type = ETHERTYPE_IP;
589 break;
590#endif
591#ifdef NS
592 case AF_NS:
593 type = ETHERTYPE_NS;
594 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
595 (caddr_t)edst, sizeof (edst));
596 break;
597#endif
598
599
600 case AF_UNSPEC:
601 eh = (struct ether_header *)dst->sa_data;
602 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
603 type = eh->ether_type;
604 break;
605
606 default:
4ad9a99e 607 printf("we%d: can't handle af%d\n", ifp->if_unit,
11dcaca6
WN
608 dst->sa_family);
609 error = EAFNOSUPPORT;
610 goto bad;
611 }
612
613 /*
614 * Add local net header. If no space in first mbuf,
615 * allocate another.
616 */
617 if (m->m_off > MMAXOFF || MMINOFF + ETHER_HDR_SIZE > m->m_off) {
618 m = m_get(M_DONTWAIT, MT_HEADER);
619 if (m == 0) {
620 error = ENOBUFS;
621 goto bad;
622 }
623 m->m_next = m0;
624 m->m_off = MMINOFF;
625 m->m_len = ETHER_HDR_SIZE;
626 } else {
627 m->m_off -= ETHER_HDR_SIZE;
628 m->m_len += ETHER_HDR_SIZE;
629 }
630 eh = mtod(m, struct ether_header *);
631 eh->ether_type = htons((u_short)type);
632 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
4ad9a99e
BJ
633 bcopy((caddr_t)sc->we_addr, (caddr_t)eh->ether_shost,
634 sizeof (sc->we_addr));
11dcaca6
WN
635
636 /*
637 * Queue message on interface, and start output if interface
638 * not yet active.
639 */
640 s = splimp();
641 if (IF_QFULL(&ifp->if_snd)) {
642 IF_DROP(&ifp->if_snd);
643 (void) splx(s);
644 m_freem(m);
645 return (ENOBUFS);
646 }
647 IF_ENQUEUE(&ifp->if_snd, m);
648 (void) splx(s);
4ad9a99e 649 westart(ifp->if_unit);
11dcaca6
WN
650 return (0);
651
652bad:
653 m_freem(m0);
654 return (error);
655}
656
657/*
658 * Process an ioctl request.
659 */
4ad9a99e 660weioctl(ifp, cmd, data)
11dcaca6
WN
661 register struct ifnet *ifp;
662 int cmd;
663 caddr_t data;
664{
4ad9a99e 665 struct we_softc *sc = &we_softc[ifp->if_unit];
11dcaca6
WN
666 struct ifaddr *ifa = (struct ifaddr *)data;
667 int s = splimp(), error = 0;
668
669 switch (cmd) {
670
671 case SIOCSIFADDR:
672 ifp->if_flags |= IFF_UP;
4ad9a99e 673 weinit(ifp->if_unit);
11dcaca6
WN
674 switch(ifa->ifa_addr.sa_family) {
675#ifdef INET
676 case AF_INET:
677 ((struct arpcom *)ifp)->ac_ipaddr =
678 IA_SIN(ifa)->sin_addr;
679 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
680 break;
681#endif
682#ifdef NS
683 case AF_NS:
684 {
685 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
686
687 if (ns_nullhost(*ina))
4ad9a99e 688 ina->x_host = *(union ns_host *)(sc->we_addr);
11dcaca6 689 else
4ad9a99e 690 wesetaddr(ina->x_host.c_host, ifp->if_unit);
11dcaca6
WN
691 break;
692 }
693#endif
694 }
695 break;
696
697 case SIOCSIFFLAGS:
698 if (((ifp->if_flags & IFF_UP) == 0) &&
4ad9a99e
BJ
699 (sc->we_flags & WDF_RUNNING)) {
700 westop(ifp->if_unit);
11dcaca6 701 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
4ad9a99e
BJ
702 ((sc->we_flags & WDF_RUNNING) == 0))
703 weinit(ifp->if_unit);
11dcaca6
WN
704 break;
705
706 default:
707 error = EINVAL;
708
709 }
710 (void) splx(s);
711 return (error);
712}
713
714/*
715 * set ethernet address for unit
716 */
4ad9a99e 717wesetaddr(physaddr, unit)
11dcaca6
WN
718 u_char *physaddr;
719 int unit;
720{
4ad9a99e 721 register struct we_softc *sc = &we_softc[unit];
11dcaca6
WN
722 register int i;
723
724 /*
725 * Rewrite ethernet address, and then force restart of NIC
726 */
727 for (i = 0; i < ETHER_ADDR_LEN; i++)
4ad9a99e
BJ
728 sc->we_addr[i] = physaddr[i];
729 sc->we_flags &= ~WDF_RUNNING;
730 weinit(unit);
11dcaca6
WN
731}
732
733/*
734 * Pass a packet to the higher levels.
735 * NO TRAILER PROTOCOL!
736 */
4ad9a99e
BJ
737weread(sc, m)
738 register struct we_softc *sc;
11dcaca6
WN
739 struct mbuf *m;
740{
741 struct ether_header *eh;
742 int scn, type, s;
743 struct ifqueue *inq;
744
745 /*
746 * Get ethernet protocol type out of ether header
747 */
748 eh = mtod(m, struct ether_header *);
749 type = ntohs((u_short)eh->ether_type);
750
751 /*
752 * Drop ethernet header
753 */
754 m->m_off += ETHER_HDR_SIZE;
755 m->m_len -= ETHER_HDR_SIZE;
756
757 /*
758 * Insert ifp pointer at start of packet
759 */
760 m->m_off -= sizeof (struct ifnet *);
761 m->m_len += sizeof (struct ifnet *);
4ad9a99e 762 *(mtod(m, struct ifnet **)) = &sc->we_if;
11dcaca6 763
4ad9a99e 764printf("ty %x ", type);
11dcaca6
WN
765 switch (type) {
766
767#ifdef INET
768 case ETHERTYPE_IP:
4ad9a99e 769printf("ip ");
11dcaca6
WN
770 scn = NETISR_IP;
771 inq = &ipintrq;
772 break;
773
774 case ETHERTYPE_ARP:
4ad9a99e
BJ
775printf("arp ");
776 arpinput(&sc->we_ac, m);
11dcaca6
WN
777 return;
778#endif
779#ifdef NS
780 case ETHERTYPE_NS:
781 scn = NETISR_NS;
782 inq = &nsintrq;
783 break;
784
785#endif
786
787 default:
788 m_freem(m);
789 return;
790 }
791
792 s = splimp();
793 if (IF_QFULL(inq)) {
794 IF_DROP(inq);
795 m_freem(m);
796 } else
797 IF_ENQUEUE(inq, m);
798 schednetisr(scn);
799 (void) splx(s);
800}
801
802#endif