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