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