Latest fixes from Nesheim@cornell
[unix-history] / usr / src / sys / vax / if / if_en.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)if_en.c 6.8 (Berkeley) %G%
7 */
11720282
BJ
8
9#include "en.h"
f1b2fa5b 10
11720282 11/*
f1b2fa5b 12 * Xerox prototype (3 Mb) Ethernet interface driver.
11720282 13 */
961945a8 14#include "../machine/pte.h"
11720282 15
a6e960e7
JB
16#include "param.h"
17#include "systm.h"
18#include "mbuf.h"
19#include "buf.h"
20#include "protosw.h"
21#include "socket.h"
22#include "vmmac.h"
23#include "errno.h"
24#include "ioctl.h"
eaa60542
BJ
25
26#include "../net/if.h"
27#include "../net/netisr.h"
28#include "../net/route.h"
d2cc167c
BJ
29#include "../netinet/in.h"
30#include "../netinet/in_systm.h"
7f0e1e06 31#include "../netinet/in_var.h"
d2cc167c
BJ
32#include "../netinet/ip.h"
33#include "../netinet/ip_var.h"
b1b3e868 34#ifdef PUP
d2cc167c 35#include "../netpup/pup.h"
3cb181be 36#include "../netpup/ether.h"
b1b3e868 37#endif
eaa60542
BJ
38
39#include "../vax/cpu.h"
40#include "../vax/mtpr.h"
a6e960e7
JB
41#include "if_en.h"
42#include "if_enreg.h"
43#include "if_uba.h"
eaa60542
BJ
44#include "../vaxuba/ubareg.h"
45#include "../vaxuba/ubavar.h"
8a13b737 46
a453e1b5 47#define ENMTU (1024+512)
dc39362e 48#define ENMRU (1024+512+16) /* 16 is enough to receive trailer */
11720282 49
11720282
BJ
50int enprobe(), enattach(), enrint(), enxint(), encollide();
51struct uba_device *eninfo[NEN];
52u_short enstd[] = { 0 };
53struct uba_driver endriver =
b454c3ea 54 { enprobe, 0, enattach, 0, enstd, "en", eninfo };
11720282
BJ
55#define ENUNIT(x) minor(x)
56
47695a10 57int eninit(),enoutput(),enreset(),enioctl();
f1b2fa5b 58
c1b082c5
SL
59#ifdef notdef
60/*
61 * If you need to byte swap IP's in the system, define
62 * this and do a SIOCSIFFLAGS at boot time.
63 */
7f0e1e06 64#define ENF_SWABIPS 0x1000
c1b082c5
SL
65#endif
66
f1b2fa5b
BJ
67/*
68 * Ethernet software status per interface.
69 *
70 * Each interface is referenced by a network interface structure,
71 * es_if, which the routing code uses to locate the interface.
72 * This structure contains the output queue for the interface, its address, ...
73 * We also have, for each interface, a UBA interface structure, which
74 * contains information about the UNIBUS resources held by the interface:
75 * map registers, buffered data paths, etc. Information is cached in this
76 * structure for use by the if_uba.c routines in running the interface
77 * efficiently.
78 */
8a13b737 79struct en_softc {
f1b2fa5b
BJ
80 struct ifnet es_if; /* network-visible interface */
81 struct ifuba es_ifuba; /* UNIBUS resources */
7fb445f3 82 short es_host; /* hardware host number */
f1b2fa5b
BJ
83 short es_delay; /* current output delay */
84 short es_mask; /* mask for current output delay */
0658a645 85 short es_lastx; /* host last transmitted to */
f1b2fa5b
BJ
86 short es_oactive; /* is output active? */
87 short es_olen; /* length of last output */
8a13b737 88} en_softc[NEN];
11720282 89
f1b2fa5b
BJ
90/*
91 * Do output DMA to determine interface presence and
92 * interrupt vector. DMA is too short to disturb other hosts.
93 */
11720282
BJ
94enprobe(reg)
95 caddr_t reg;
96{
b454c3ea 97 register int br, cvec; /* r11, r10 value-result */
11720282
BJ
98 register struct endevice *addr = (struct endevice *)reg;
99
100#ifdef lint
101 br = 0; cvec = br; br = cvec;
2b4b57cd 102 enrint(0); enxint(0); encollide(0);
11720282 103#endif
11720282 104 addr->en_istat = 0;
11720282
BJ
105 addr->en_owc = -1;
106 addr->en_oba = 0;
941ee7ef 107 addr->en_ostat = EN_IEN|EN_GO;
11720282
BJ
108 DELAY(100000);
109 addr->en_ostat = 0;
11720282
BJ
110 return (1);
111}
112
f1b2fa5b
BJ
113/*
114 * Interface exists: make available by filling in network interface
115 * record. System will initialize the interface when it is ready
116 * to accept packets.
117 */
11720282
BJ
118enattach(ui)
119 struct uba_device *ui;
120{
f1b2fa5b 121 register struct en_softc *es = &en_softc[ui->ui_unit];
f1b2fa5b
BJ
122
123 es->es_if.if_unit = ui->ui_unit;
b454c3ea 124 es->es_if.if_name = "en";
f1b2fa5b 125 es->es_if.if_mtu = ENMTU;
7f0e1e06 126 es->es_if.if_flags = IFF_BROADCAST;
f1b2fa5b 127 es->es_if.if_init = eninit;
b454c3ea 128 es->es_if.if_output = enoutput;
47695a10 129 es->es_if.if_ioctl = enioctl;
51595ca2 130 es->es_if.if_reset = enreset;
d9c0644f 131 es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
b4e3e570
SL
132#if defined(VAX750)
133 /* don't chew up 750 bdp's */
134 if (cpu == VAX_750 && ui->ui_unit > 0)
135 es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
136#endif
405c9168 137 if_attach(&es->es_if);
11720282
BJ
138}
139
f1b2fa5b
BJ
140/*
141 * Reset of interface after UNIBUS reset.
142 * If interface is on specified uba, reset its state.
143 */
144enreset(unit, uban)
145 int unit, uban;
8a13b737 146{
11720282 147 register struct uba_device *ui;
11720282 148
b454c3ea
BJ
149 if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
150 ui->ui_ubanum != uban)
f1b2fa5b 151 return;
b454c3ea 152 printf(" en%d", unit);
f1b2fa5b
BJ
153 eninit(unit);
154}
155
156/*
157 * Initialization of interface; clear recorded pending
158 * operations, and reinitialize UNIBUS usage.
159 */
160eninit(unit)
161 int unit;
162{
b454c3ea
BJ
163 register struct en_softc *es = &en_softc[unit];
164 register struct uba_device *ui = eninfo[unit];
f1b2fa5b 165 register struct endevice *addr;
47695a10 166 int s;
f1b2fa5b 167
7f0e1e06 168 if (es->es_if.if_addrlist == (struct ifaddr *)0)
732fb59b 169 return;
f1b2fa5b 170 if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
dc39362e 171 sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
b454c3ea 172 printf("en%d: can't initialize\n", unit);
ee787340 173 es->es_if.if_flags &= ~IFF_UP;
8a13b737 174 return;
11720282 175 }
11720282 176 addr = (struct endevice *)ui->ui_addr;
8a13b737 177 addr->en_istat = addr->en_ostat = 0;
11720282 178
f1b2fa5b 179 /*
b454c3ea
BJ
180 * Hang a receive and start any
181 * pending writes by faking a transmit complete.
f1b2fa5b
BJ
182 */
183 s = splimp();
b454c3ea 184 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
dc39362e 185 addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
b454c3ea
BJ
186 addr->en_istat = EN_IEN|EN_GO;
187 es->es_oactive = 1;
7f0e1e06 188 es->es_if.if_flags |= IFF_RUNNING;
f1b2fa5b
BJ
189 enxint(unit);
190 splx(s);
11720282
BJ
191}
192
0658a645 193int enalldelay = 0;
4c073c48 194int enlastdel = 50;
0658a645 195int enlastmask = (~0) << 5;
8a13b737 196
f1b2fa5b
BJ
197/*
198 * Start or restart output on interface.
199 * If interface is already active, then this is a retransmit
200 * after a collision, and just restuff registers and delay.
201 * If interface is not already active, get another datagram
202 * to send off of the interface queue, and map it to the interface
203 * before starting the output.
204 */
ae348eea 205enstart(dev)
11720282
BJ
206 dev_t dev;
207{
b454c3ea
BJ
208 int unit = ENUNIT(dev);
209 struct uba_device *ui = eninfo[unit];
210 register struct en_softc *es = &en_softc[unit];
8a13b737 211 register struct endevice *addr;
7fb445f3 212 register struct en_header *en;
8a13b737
BJ
213 struct mbuf *m;
214 int dest;
11720282 215
8a13b737
BJ
216 if (es->es_oactive)
217 goto restart;
f1b2fa5b
BJ
218
219 /*
220 * Not already active: dequeue another request
221 * and map it to the UNIBUS. If no more requests,
222 * just return.
223 */
224 IF_DEQUEUE(&es->es_if.if_snd, m);
8a13b737
BJ
225 if (m == 0) {
226 es->es_oactive = 0;
11720282
BJ
227 return;
228 }
7fb445f3
MK
229 en = mtod(m, struct en_header *);
230 dest = en->en_dhost;
231 en->en_shost = es->es_host;
8a13b737 232 es->es_olen = if_wubaput(&es->es_ifuba, m);
c1b082c5
SL
233#ifdef ENF_SWABIPS
234 /*
235 * The Xerox interface does word at a time DMA, so
236 * someone must do byte swapping of user data if high
237 * and low ender machines are to communicate. It doesn't
238 * belong here, but certain people depend on it, so...
239 *
240 * Should swab everybody, but this is a kludge anyway.
241 */
242 if (es->es_if.if_flags & ENF_SWABIPS) {
c1b082c5
SL
243 en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr;
244 if (en->en_type == ENTYPE_IP)
245 enswab((caddr_t)(en + 1), (caddr_t)(en + 1),
246 es->es_olen - sizeof (struct en_header) + 1);
247 }
248#endif
f1b2fa5b
BJ
249
250 /*
251 * Ethernet cannot take back-to-back packets (no
0658a645
BJ
252 * buffering in interface. To help avoid overrunning
253 * receivers, enforce a small delay (about 1ms) in interface:
254 * * between all packets when enalldelay
255 * * whenever last packet was broadcast
256 * * whenever this packet is to same host as last packet
f1b2fa5b 257 */
0658a645 258 if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
8a13b737 259 es->es_delay = enlastdel;
0658a645
BJ
260 es->es_mask = enlastmask;
261 }
262 es->es_lastx = dest;
f1b2fa5b 263
8a13b737 264restart:
f1b2fa5b
BJ
265 /*
266 * Have request mapped to UNIBUS for transmission.
267 * Purge any stale data from this BDP, and start the otput.
268 */
ee787340
SL
269 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
270 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
11720282 271 addr = (struct endevice *)ui->ui_addr;
405c9168 272 addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
8a13b737
BJ
273 addr->en_odelay = es->es_delay;
274 addr->en_owc = -((es->es_olen + 1) >> 1);
941ee7ef 275 addr->en_ostat = EN_IEN|EN_GO;
8a13b737 276 es->es_oactive = 1;
11720282
BJ
277}
278
f1b2fa5b
BJ
279/*
280 * Ethernet interface transmitter interrupt.
281 * Start another output if more data to send.
282 */
11720282
BJ
283enxint(unit)
284 int unit;
285{
b454c3ea
BJ
286 register struct uba_device *ui = eninfo[unit];
287 register struct en_softc *es = &en_softc[unit];
519a1ecf 288 register struct endevice *addr = (struct endevice *)ui->ui_addr;
11720282 289
8a13b737
BJ
290 if (es->es_oactive == 0)
291 return;
519a1ecf 292 if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
89413846 293 es->es_if.if_oerrors++;
519a1ecf
BJ
294 endocoll(unit);
295 return;
89413846 296 }
519a1ecf
BJ
297 es->es_if.if_opackets++;
298 es->es_oactive = 0;
299 es->es_delay = 0;
300 es->es_mask = ~0;
7a66118b
BJ
301 if (es->es_ifuba.ifu_xtofree) {
302 m_freem(es->es_ifuba.ifu_xtofree);
303 es->es_ifuba.ifu_xtofree = 0;
304 }
f1b2fa5b 305 if (es->es_if.if_snd.ifq_head == 0) {
0658a645 306 es->es_lastx = 256; /* putatively illegal */
11720282
BJ
307 return;
308 }
8a13b737 309 enstart(unit);
11720282
BJ
310}
311
f1b2fa5b
BJ
312/*
313 * Collision on ethernet interface. Do exponential
314 * backoff, and retransmit. If have backed off all
ee787340 315 * the way print warning diagnostic, and drop packet.
f1b2fa5b 316 */
11720282
BJ
317encollide(unit)
318 int unit;
319{
519a1ecf 320 struct en_softc *es = &en_softc[unit];
11720282 321
f1b2fa5b 322 es->es_if.if_collisions++;
8a13b737 323 if (es->es_oactive == 0)
11720282 324 return;
519a1ecf
BJ
325 endocoll(unit);
326}
327
328endocoll(unit)
329 int unit;
330{
331 register struct en_softc *es = &en_softc[unit];
332
b454c3ea
BJ
333 /*
334 * Es_mask is a 16 bit number with n low zero bits, with
335 * n the number of backoffs. When es_mask is 0 we have
336 * backed off 16 times, and give up.
337 */
8a13b737 338 if (es->es_mask == 0) {
a453e1b5 339 printf("en%d: send error\n", unit);
8a13b737 340 enxint(unit);
b454c3ea 341 return;
11720282 342 }
b454c3ea
BJ
343 /*
344 * Another backoff. Restart with delay based on n low bits
345 * of the interval timer.
346 */
347 es->es_mask <<= 1;
348 es->es_delay = mfpr(ICR) &~ es->es_mask;
349 enstart(unit);
11720282
BJ
350}
351
3cb181be
SL
352#ifdef notdef
353struct sockproto enproto = { AF_ETHERLINK };
354struct sockaddr_en endst = { AF_ETHERLINK };
355struct sockaddr_en ensrc = { AF_ETHERLINK };
356#endif
f1b2fa5b
BJ
357/*
358 * Ethernet interface receiver interrupt.
359 * If input error just drop packet.
360 * Otherwise purge input buffered data path and examine
361 * packet to determine type. If can't determine length
362 * from type, then have to drop packet. Othewise decapsulate
363 * packet based on type and pass to type specific higher-level
364 * input routine.
365 */
11720282
BJ
366enrint(unit)
367 int unit;
368{
b454c3ea
BJ
369 register struct en_softc *es = &en_softc[unit];
370 struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
371 register struct en_header *en;
8a13b737 372 struct mbuf *m;
038ee561 373 int len; short resid;
b454c3ea 374 register struct ifqueue *inq;
51c7d639 375 int off, s;
11720282 376
b454c3ea 377 es->es_if.if_ipackets++;
f1b2fa5b
BJ
378
379 /*
b454c3ea 380 * Purge BDP; drop if input error indicated.
f1b2fa5b 381 */
ee787340
SL
382 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
383 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
941ee7ef 384 if (addr->en_istat&EN_IERROR) {
f1b2fa5b 385 es->es_if.if_ierrors++;
8a13b737 386 goto setup;
11720282 387 }
f1b2fa5b
BJ
388
389 /*
0658a645 390 * Calculate input data length.
f1b2fa5b
BJ
391 * Get pointer to ethernet header (in input buffer).
392 * Deal with trailer protocol: if type is PUP trailer
393 * get true type from first 16-bit word past data.
394 * Remember that type was trailer by setting off.
395 */
0658a645
BJ
396 resid = addr->en_iwc;
397 if (resid)
398 resid |= 0176000;
dc39362e 399 len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
0658a645 400 len -= sizeof (struct en_header);
dc39362e 401 if (len > ENMRU)
0658a645 402 goto setup; /* sanity */
f1b2fa5b 403 en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
991f6240 404 en->en_type = ntohs(en->en_type);
8a13b737 405#define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
991f6240
SL
406 if (en->en_type >= ENTYPE_TRAIL &&
407 en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
408 off = (en->en_type - ENTYPE_TRAIL) * 512;
dc39362e 409 if (off > ENMTU)
b454c3ea 410 goto setup; /* sanity */
991f6240
SL
411 en->en_type = ntohs(*endataaddr(en, off, u_short *));
412 resid = ntohs(*(endataaddr(en, off+2, u_short *)));
0658a645
BJ
413 if (off + resid > len)
414 goto setup; /* sanity */
415 len = off + resid;
8a13b737
BJ
416 } else
417 off = 0;
8a13b737
BJ
418 if (len == 0)
419 goto setup;
c1b082c5
SL
420#ifdef ENF_SWABIPS
421 if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP)
422 enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);
423#endif
f1b2fa5b
BJ
424 /*
425 * Pull packet off interface. Off is nonzero if packet
426 * has trailing header; if_rubaget will then force this header
427 * information to be at the front, but we still have to drop
0658a645 428 * the type and length which are at the front of any trailer data.
f1b2fa5b
BJ
429 */
430 m = if_rubaget(&es->es_ifuba, len, off);
a453e1b5
BJ
431 if (m == 0)
432 goto setup;
f1b2fa5b 433 if (off) {
0658a645
BJ
434 m->m_off += 2 * sizeof (u_short);
435 m->m_len -= 2 * sizeof (u_short);
f1b2fa5b 436 }
31c2345c
SL
437 switch (en->en_type) {
438
439#ifdef INET
991f6240 440 case ENTYPE_IP:
9c8692e9 441 schednetisr(NETISR_IP);
31c2345c
SL
442 inq = &ipintrq;
443 break;
444#endif
ee787340 445#ifdef PUP
3cb181be
SL
446 case ENTYPE_PUP:
447 rpup_input(m);
31c2345c 448 goto setup;
ee787340 449#endif
c8f8184f 450 default:
3cb181be
SL
451#ifdef notdef
452 enproto.sp_protocol = en->en_type;
453 endst.sen_host = en->en_dhost;
454 endst.sen_net = ensrc.sen_net = es->es_if.if_net;
455 ensrc.sen_host = en->en_shost;
456 raw_input(m, &enproto,
457 (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);
458#else
c8f8184f 459 m_freem(m);
3cb181be 460#endif
c8f8184f 461 goto setup;
ee787340
SL
462 }
463
51c7d639 464 s = splimp();
1e977657
BJ
465 if (IF_QFULL(inq)) {
466 IF_DROP(inq);
ee787340 467 m_freem(m);
1e977657
BJ
468 } else
469 IF_ENQUEUE(inq, m);
51c7d639 470 splx(s);
f1b2fa5b 471
ae348eea 472setup:
f1b2fa5b
BJ
473 /*
474 * Reset for next packet.
475 */
476 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
dc39362e 477 addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
941ee7ef 478 addr->en_istat = EN_IEN|EN_GO;
ae348eea 479}
11720282 480
8a13b737
BJ
481/*
482 * Ethernet output routine.
483 * Encapsulate a packet of type family for the local net.
f1b2fa5b
BJ
484 * Use trailer local net encapsulation if enough data in first
485 * packet leaves a multiple of 512 bytes of data in remainder.
8a13b737 486 */
ee787340 487enoutput(ifp, m0, dst)
8a13b737
BJ
488 struct ifnet *ifp;
489 struct mbuf *m0;
ee787340 490 struct sockaddr *dst;
11720282 491{
8a2f82db 492 int type, dest, s, error;
f1b2fa5b 493 register struct mbuf *m = m0;
8a13b737 494 register struct en_header *en;
ee787340 495 register int off;
8a13b737 496
ee787340 497 switch (dst->sa_family) {
11720282 498
8a13b737 499#ifdef INET
ee787340 500 case AF_INET:
7f0e1e06
MK
501 {
502 struct in_addr in;
503
504 in = ((struct sockaddr_in *)dst)->sin_addr;
505 if (in_broadcast(in))
506 dest = EN_BROADCAST;
507 else
508 dest = in_lnaof(in);
509 }
510 if (dest >= 0x100) {
8a2f82db 511 error = EPERM; /* ??? */
3734056d 512 goto bad;
8a2f82db 513 }
ee787340 514 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
47695a10
SL
515 /* need per host negotiation */
516 if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
ee787340 517 if (off > 0 && (off & 0x1ff) == 0 &&
0658a645 518 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
991f6240 519 type = ENTYPE_TRAIL + (off>>9);
0658a645
BJ
520 m->m_off -= 2 * sizeof (u_short);
521 m->m_len += 2 * sizeof (u_short);
991f6240
SL
522 *mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
523 *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
f1b2fa5b 524 goto gottrailertype;
8a13b737 525 }
991f6240 526 type = ENTYPE_IP;
f1b2fa5b
BJ
527 off = 0;
528 goto gottype;
8a13b737 529#endif
31c2345c 530#ifdef PUP
ee787340 531 case AF_PUP:
1c1d4563 532 dest = ((struct sockaddr_pup *)dst)->spup_host;
991f6240 533 type = ENTYPE_PUP;
31c2345c
SL
534 off = 0;
535 goto gottype;
31c2345c 536#endif
8a13b737 537
3cb181be
SL
538#ifdef notdef
539 case AF_ETHERLINK:
540 goto gotheader;
541#endif
542
8a13b737 543 default:
ee787340
SL
544 printf("en%d: can't handle af%d\n", ifp->if_unit,
545 dst->sa_family);
8a2f82db
SL
546 error = EAFNOSUPPORT;
547 goto bad;
8a13b737 548 }
f1b2fa5b 549
b454c3ea 550gottrailertype:
f1b2fa5b
BJ
551 /*
552 * Packet to be sent as trailer: move first packet
553 * (control information) to end of chain.
554 */
f1b2fa5b
BJ
555 while (m->m_next)
556 m = m->m_next;
557 m->m_next = m0;
558 m = m0->m_next;
559 m0->m_next = 0;
b454c3ea 560 m0 = m;
f1b2fa5b 561
b454c3ea 562gottype:
f1b2fa5b
BJ
563 /*
564 * Add local net header. If no space in first mbuf,
565 * allocate another.
566 */
a453e1b5
BJ
567 if (m->m_off > MMAXOFF ||
568 MMINOFF + sizeof (struct en_header) > m->m_off) {
b994ed6a 569 MGET(m, M_DONTWAIT, MT_HEADER);
8a13b737 570 if (m == 0) {
8a2f82db
SL
571 error = ENOBUFS;
572 goto bad;
8a13b737
BJ
573 }
574 m->m_next = m0;
575 m->m_off = MMINOFF;
576 m->m_len = sizeof (struct en_header);
577 } else {
8a13b737
BJ
578 m->m_off -= sizeof (struct en_header);
579 m->m_len += sizeof (struct en_header);
11720282 580 }
8a13b737 581 en = mtod(m, struct en_header *);
7fb445f3 582 /* add en_shost later */
8a13b737 583 en->en_dhost = dest;
991f6240 584 en->en_type = htons((u_short)type);
f1b2fa5b 585
3cb181be 586gotheader:
f1b2fa5b
BJ
587 /*
588 * Queue message on interface, and start output if interface
589 * not yet active.
590 */
8a13b737 591 s = splimp();
1e977657
BJ
592 if (IF_QFULL(&ifp->if_snd)) {
593 IF_DROP(&ifp->if_snd);
8a2f82db
SL
594 error = ENOBUFS;
595 goto qfull;
1e977657 596 }
8a13b737 597 IF_ENQUEUE(&ifp->if_snd, m);
8a13b737
BJ
598 if (en_softc[ifp->if_unit].es_oactive == 0)
599 enstart(ifp->if_unit);
89413846 600 splx(s);
4e818526 601 return (0);
8a2f82db
SL
602qfull:
603 m0 = m;
604 splx(s);
605bad:
606 m_freem(m0);
607 return (error);
11720282 608}
47695a10
SL
609
610/*
611 * Process an ioctl request.
612 */
613enioctl(ifp, cmd, data)
614 register struct ifnet *ifp;
615 int cmd;
616 caddr_t data;
617{
7f0e1e06
MK
618 register struct en_softc *es = ((struct en_softc *)ifp);
619 struct ifaddr *ifa = (struct ifaddr *) data;
47695a10 620 int s = splimp(), error = 0;
7f0e1e06 621 struct endevice *enaddr;
47695a10
SL
622
623 switch (cmd) {
624
625 case SIOCSIFADDR:
7f0e1e06
MK
626 enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr;
627 es->es_host = (~enaddr->en_addr) & 0xff;
628 /*
629 * Attempt to check agreement of protocol address
630 * and board address.
631 */
632 switch (ifa->ifa_addr.sa_family) {
633 case AF_INET:
634 if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host)
635 return (EADDRNOTAVAIL);
636 break;
637 }
638 ifp->if_flags |= IFF_UP;
639 if ((ifp->if_flags & IFF_RUNNING) == 0)
47695a10
SL
640 eninit(ifp->if_unit);
641 break;
642
643 default:
644 error = EINVAL;
645 }
646 splx(s);
647 return (error);
648}
649
c1b082c5
SL
650#ifdef ENF_SWABIPS
651/*
652 * Swab bytes
653 * Jeffrey Mogul, Stanford
654 */
655enswab(from, to, n)
7f0e1e06 656 register unsigned char *from, *to;
c1b082c5
SL
657 register int n;
658{
659 register unsigned long temp;
7f0e1e06
MK
660
661 if ((n <= 0) || (n > 0xFFFF)) {
662 printf("enswab: bad len %d\n", n);
663 return;
664 }
c1b082c5
SL
665
666 n >>= 1; n++;
7f0e1e06 667#define STEP {temp = *from++;*to++ = *from++;*to++ = temp;}
c1b082c5
SL
668 /* round to multiple of 8 */
669 while ((--n) & 07)
670 STEP;
671 n >>= 3;
672 while (--n >= 0) {
673 STEP; STEP; STEP; STEP;
674 STEP; STEP; STEP; STEP;
675 }
676}
677#endif