xref: /original-bsd/sys/vax/if/if_en.c (revision 96ad03bc)
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.13 (Berkeley) 12/19/85
7  */
8 
9 #include "en.h"
10 #if NEN > 0
11 
12 /*
13  * Xerox prototype (3 Mb) Ethernet interface driver.
14  */
15 #include "../machine/pte.h"
16 
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"
26 
27 #include "../net/if.h"
28 #include "../net/netisr.h"
29 #include "../net/route.h"
30 
31 #ifdef	INET
32 #include "../netinet/in.h"
33 #include "../netinet/in_systm.h"
34 #include "../netinet/in_var.h"
35 #include "../netinet/ip.h"
36 #endif
37 
38 #ifdef PUP
39 #include "../netpup/pup.h"
40 #include "../netpup/ether.h"
41 #endif
42 
43 #ifdef NS
44 #include "../netns/ns.h"
45 #include "../netns/ns_if.h"
46 #endif
47 
48 #include "../vax/cpu.h"
49 #include "../vax/mtpr.h"
50 #include "if_en.h"
51 #include "if_enreg.h"
52 #include "if_uba.h"
53 #include "../vaxuba/ubareg.h"
54 #include "../vaxuba/ubavar.h"
55 
56 #define	ENMTU	(1024+512)
57 #define	ENMRU	(1024+512+16)		/* 16 is enough to receive trailer */
58 
59 int	enprobe(), enattach(), enrint(), enxint(), encollide();
60 struct	uba_device *eninfo[NEN];
61 u_short enstd[] = { 0 };
62 struct	uba_driver endriver =
63 	{ enprobe, 0, enattach, 0, enstd, "en", eninfo };
64 #define	ENUNIT(x)	minor(x)
65 
66 int	eninit(),enoutput(),enreset(),enioctl();
67 
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  */
73 #define	ENF_SWABIPS	0x1000
74 #endif
75 
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  */
88 struct	en_softc {
89 	struct	ifnet es_if;		/* network-visible interface */
90 	struct	ifuba es_ifuba;		/* UNIBUS resources */
91 	short	es_host;		/* hardware host number */
92 	short	es_delay;		/* current output delay */
93 	short	es_mask;		/* mask for current output delay */
94 	short	es_lastx;		/* host last transmitted to */
95 	short	es_oactive;		/* is output active? */
96 	short	es_olen;		/* length of last output */
97 	short	es_nsactive;		/* is interface enabled for ns? */
98 } en_softc[NEN];
99 
100 /*
101  * Do output DMA to determine interface presence and
102  * interrupt vector.  DMA is too short to disturb other hosts.
103  */
104 enprobe(reg)
105 	caddr_t reg;
106 {
107 	register int br, cvec;		/* r11, r10 value-result */
108 	register struct endevice *addr = (struct endevice *)reg;
109 
110 #ifdef lint
111 	br = 0; cvec = br; br = cvec;
112 	enrint(0); enxint(0); encollide(0);
113 #endif
114 	addr->en_istat = 0;
115 	addr->en_owc = -1;
116 	addr->en_oba = 0;
117 	addr->en_ostat = EN_IEN|EN_GO;
118 	DELAY(100000);
119 	addr->en_ostat = 0;
120 	return (1);
121 }
122 
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  */
128 enattach(ui)
129 	struct uba_device *ui;
130 {
131 	register struct en_softc *es = &en_softc[ui->ui_unit];
132 
133 	es->es_if.if_unit = ui->ui_unit;
134 	es->es_if.if_name = "en";
135 	es->es_if.if_mtu = ENMTU;
136 	es->es_if.if_flags = IFF_BROADCAST;
137 	es->es_if.if_init = eninit;
138 	es->es_if.if_output = enoutput;
139 	es->es_if.if_ioctl = enioctl;
140 	es->es_if.if_reset = enreset;
141 	es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
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
147 	if_attach(&es->es_if);
148 }
149 
150 /*
151  * Reset of interface after UNIBUS reset.
152  * If interface is on specified uba, reset its state.
153  */
154 enreset(unit, uban)
155 	int unit, uban;
156 {
157 	register struct uba_device *ui;
158 
159 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
160 	    ui->ui_ubanum != uban)
161 		return;
162 	printf(" en%d", unit);
163 	eninit(unit);
164 }
165 
166 /*
167  * Initialization of interface; clear recorded pending
168  * operations, and reinitialize UNIBUS usage.
169  */
170 eninit(unit)
171 	int unit;
172 {
173 	register struct en_softc *es = &en_softc[unit];
174 	register struct uba_device *ui = eninfo[unit];
175 	register struct endevice *addr;
176 	int s;
177 
178 	if (es->es_if.if_addrlist == (struct ifaddr *)0)
179 		return;
180 	if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
181 	    sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
182 		printf("en%d: can't initialize\n", unit);
183 		es->es_if.if_flags &= ~IFF_UP;
184 		return;
185 	}
186 	addr = (struct endevice *)ui->ui_addr;
187 	addr->en_istat = addr->en_ostat = 0;
188 
189 	/*
190 	 * Hang a receive and start any
191 	 * pending writes by faking a transmit complete.
192 	 */
193 	s = splimp();
194 	addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
195 	addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
196 	addr->en_istat = EN_IEN|EN_GO;
197 	es->es_oactive = 1;
198 	es->es_if.if_flags |= IFF_RUNNING;
199 	enxint(unit);
200 	splx(s);
201 }
202 
203 int	enalldelay = 0;
204 int	enlastdel = 50;
205 int	enlastmask = (~0) << 5;
206 
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  */
215 enstart(dev)
216 	dev_t dev;
217 {
218         int unit = ENUNIT(dev);
219 	struct uba_device *ui = eninfo[unit];
220 	register struct en_softc *es = &en_softc[unit];
221 	register struct endevice *addr;
222 	register struct en_header *en;
223 	struct mbuf *m;
224 	int dest;
225 
226 	if (es->es_oactive)
227 		goto restart;
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);
235 	if (m == 0) {
236 		es->es_oactive = 0;
237 		return;
238 	}
239 	en = mtod(m, struct en_header *);
240 	dest = en->en_dhost;
241 	en->en_shost = es->es_host;
242 	es->es_olen = if_wubaput(&es->es_ifuba, m);
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) {
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
259 
260 	/*
261 	 * Ethernet cannot take back-to-back packets (no
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
267 	 */
268 	if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
269 		es->es_delay = enlastdel;
270 		es->es_mask = enlastmask;
271 	}
272 	es->es_lastx = dest;
273 
274 restart:
275 	/*
276 	 * Have request mapped to UNIBUS for transmission.
277 	 * Purge any stale data from this BDP, and start the otput.
278 	 */
279 	if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
280 		UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
281 	addr = (struct endevice *)ui->ui_addr;
282 	addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
283 	addr->en_odelay = es->es_delay;
284 	addr->en_owc = -((es->es_olen + 1) >> 1);
285 	addr->en_ostat = EN_IEN|EN_GO;
286 	es->es_oactive = 1;
287 }
288 
289 /*
290  * Ethernet interface transmitter interrupt.
291  * Start another output if more data to send.
292  */
293 enxint(unit)
294 	int unit;
295 {
296 	register struct uba_device *ui = eninfo[unit];
297 	register struct en_softc *es = &en_softc[unit];
298 	register struct endevice *addr = (struct endevice *)ui->ui_addr;
299 
300 	if (es->es_oactive == 0)
301 		return;
302 	if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
303 		es->es_if.if_oerrors++;
304 		endocoll(unit);
305 		return;
306 	}
307 	es->es_if.if_opackets++;
308 	es->es_oactive = 0;
309 	es->es_delay = 0;
310 	es->es_mask = ~0;
311 	if (es->es_ifuba.ifu_xtofree) {
312 		m_freem(es->es_ifuba.ifu_xtofree);
313 		es->es_ifuba.ifu_xtofree = 0;
314 	}
315 	if (es->es_if.if_snd.ifq_head == 0) {
316 		es->es_lastx = 256;		/* putatively illegal */
317 		return;
318 	}
319 	enstart(unit);
320 }
321 
322 /*
323  * Collision on ethernet interface.  Do exponential
324  * backoff, and retransmit.  If have backed off all
325  * the way print warning diagnostic, and drop packet.
326  */
327 encollide(unit)
328 	int unit;
329 {
330 	struct en_softc *es = &en_softc[unit];
331 
332 	es->es_if.if_collisions++;
333 	if (es->es_oactive == 0)
334 		return;
335 	endocoll(unit);
336 }
337 
338 endocoll(unit)
339 	int unit;
340 {
341 	register struct en_softc *es = &en_softc[unit];
342 
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 	 */
348 	if (es->es_mask == 0) {
349 		printf("en%d: send error\n", unit);
350 		enxint(unit);
351 		return;
352 	}
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);
360 }
361 
362 #ifdef notdef
363 struct	sockproto enproto = { AF_ETHERLINK };
364 struct	sockaddr_en endst = { AF_ETHERLINK };
365 struct	sockaddr_en ensrc = { AF_ETHERLINK };
366 #endif
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  */
376 enrint(unit)
377 	int unit;
378 {
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;
382     	struct mbuf *m;
383 	int len; short resid;
384 	register struct ifqueue *inq;
385 	int off, s;
386 
387 	es->es_if.if_ipackets++;
388 
389 	/*
390 	 * Purge BDP; drop if input error indicated.
391 	 */
392 	if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
393 		UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
394 	if (addr->en_istat&EN_IERROR) {
395 		es->es_if.if_ierrors++;
396 		goto setup;
397 	}
398 
399 	/*
400 	 * Calculate input data length.
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 	 */
406 	resid = addr->en_iwc;
407 	if (resid)
408 		resid |= 0176000;
409 	len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
410 	len -= sizeof (struct en_header);
411 	if (len > ENMRU)
412 		goto setup;			/* sanity */
413 	en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
414 	en->en_type = ntohs(en->en_type);
415 #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
416 	if (en->en_type >= ENTYPE_TRAIL &&
417 	    en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
418 		off = (en->en_type - ENTYPE_TRAIL) * 512;
419 		if (off > ENMTU)
420 			goto setup;		/* sanity */
421 		en->en_type = ntohs(*endataaddr(en, off, u_short *));
422 		resid = ntohs(*(endataaddr(en, off+2, u_short *)));
423 		if (off + resid > len)
424 			goto setup;		/* sanity */
425 		len = off + resid;
426 	} else
427 		off = 0;
428 	if (len == 0)
429 		goto setup;
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
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
438 	 * the type and length which are at the front of any trailer data.
439 	 */
440 	m = if_rubaget(&es->es_ifuba, len, off, &es->es_if);
441 	if (m == 0)
442 		goto setup;
443 	if (off) {
444 		struct ifnet *ifp;
445 
446 		ifp = *(mtod(m, struct ifnet **));
447 		m->m_off += 2 * sizeof (u_short);
448 		m->m_len -= 2 * sizeof (u_short);
449 		*(mtod(m, struct ifnet **)) = ifp;
450 	}
451 	switch (en->en_type) {
452 
453 #ifdef INET
454 	case ENTYPE_IP:
455 		schednetisr(NETISR_IP);
456 		inq = &ipintrq;
457 		break;
458 #endif
459 #ifdef PUP
460 	case ENTYPE_PUP:
461 		rpup_input(m);
462 		goto setup;
463 #endif
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 
476 	default:
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
485 		m_freem(m);
486 #endif
487 		goto setup;
488 	}
489 
490 	s = splimp();
491 	if (IF_QFULL(inq)) {
492 		IF_DROP(inq);
493 		m_freem(m);
494 	} else
495 		IF_ENQUEUE(inq, m);
496 	splx(s);
497 
498 setup:
499 	/*
500 	 * Reset for next packet.
501 	 */
502 	addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
503 	addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
504 	addr->en_istat = EN_IEN|EN_GO;
505 }
506 
507 /*
508  * Ethernet output routine.
509  * Encapsulate a packet of type family for the local net.
510  * Use trailer local net encapsulation if enough data in first
511  * packet leaves a multiple of 512 bytes of data in remainder.
512  */
513 enoutput(ifp, m0, dst)
514 	struct ifnet *ifp;
515 	struct mbuf *m0;
516 	struct sockaddr *dst;
517 {
518 	int type, dest, s, error;
519 	register struct mbuf *m = m0;
520 	register struct en_header *en;
521 	register int off;
522 
523 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
524 		error = ENETDOWN;
525 		goto bad;
526 	}
527 	switch (dst->sa_family) {
528 
529 #ifdef INET
530 	case AF_INET:
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) {
541 			error = EPERM;		/* ??? */
542 			goto bad;
543 		}
544 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
545 		/* need per host negotiation */
546 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
547 		if (off > 0 && (off & 0x1ff) == 0 &&
548 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
549 			type = ENTYPE_TRAIL + (off>>9);
550 			m->m_off -= 2 * sizeof (u_short);
551 			m->m_len += 2 * sizeof (u_short);
552 			*mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
553 			*(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
554 			goto gottrailertype;
555 		}
556 		type = ENTYPE_IP;
557 		off = 0;
558 		goto gottype;
559 #endif
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
576 #ifdef PUP
577 	case AF_PUP:
578 		dest = ((struct sockaddr_pup *)dst)->spup_host;
579 		type = ENTYPE_PUP;
580 		off = 0;
581 		goto gottype;
582 #endif
583 
584 #ifdef notdef
585 	case AF_ETHERLINK:
586 		goto gotheader;
587 #endif
588 
589 	default:
590 		printf("en%d: can't handle af%d\n", ifp->if_unit,
591 			dst->sa_family);
592 		error = EAFNOSUPPORT;
593 		goto bad;
594 	}
595 
596 gottrailertype:
597 	/*
598 	 * Packet to be sent as trailer: move first packet
599 	 * (control information) to end of chain.
600 	 */
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;
606 	m0 = m;
607 
608 gottype:
609 	/*
610 	 * Add local net header.  If no space in first mbuf,
611 	 * allocate another.
612 	 */
613 	if (m->m_off > MMAXOFF ||
614 	    MMINOFF + sizeof (struct en_header) > m->m_off) {
615 		MGET(m, M_DONTWAIT, MT_HEADER);
616 		if (m == 0) {
617 			error = ENOBUFS;
618 			goto bad;
619 		}
620 		m->m_next = m0;
621 		m->m_off = MMINOFF;
622 		m->m_len = sizeof (struct en_header);
623 	} else {
624 		m->m_off -= sizeof (struct en_header);
625 		m->m_len += sizeof (struct en_header);
626 	}
627 	en = mtod(m, struct en_header *);
628 	/* add en_shost later */
629 	en->en_dhost = dest;
630 	en->en_type = htons((u_short)type);
631 
632 #ifdef notdef
633 gotheader:
634 #endif
635 	/*
636 	 * Queue message on interface, and start output if interface
637 	 * not yet active.
638 	 */
639 	s = splimp();
640 	if (IF_QFULL(&ifp->if_snd)) {
641 		IF_DROP(&ifp->if_snd);
642 		error = ENOBUFS;
643 		goto qfull;
644 	}
645 	IF_ENQUEUE(&ifp->if_snd, m);
646 	if (en_softc[ifp->if_unit].es_oactive == 0)
647 		enstart(ifp->if_unit);
648 	splx(s);
649 	return (0);
650 qfull:
651 	m0 = m;
652 	splx(s);
653 bad:
654 	m_freem(m0);
655 	return (error);
656 }
657 
658 /*
659  * Process an ioctl request.
660  */
661 enioctl(ifp, cmd, data)
662 	register struct ifnet *ifp;
663 	int cmd;
664 	caddr_t data;
665 {
666 	register struct en_softc *es = ((struct en_softc *)ifp);
667 	struct ifaddr *ifa = (struct ifaddr *) data;
668 	int s = splimp(), error = 0;
669 	struct endevice *enaddr;
670 
671 	switch (cmd) {
672 
673 	case SIOCSIFADDR:
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;
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
693 		}
694 		ifp->if_flags |= IFF_UP;
695 		if ((ifp->if_flags & IFF_RUNNING) == 0)
696 			eninit(ifp->if_unit);
697 		break;
698 
699 	default:
700 		error = EINVAL;
701 		break;
702 	}
703 	splx(s);
704 	return (error);
705 }
706 
707 #ifdef ENF_SWABIPS
708 /*
709  * Swab bytes
710  * Jeffrey Mogul, Stanford
711  */
712 enswab(from, to, n)
713 	register unsigned char *from, *to;
714 	register int n;
715 {
716 	register unsigned long temp;
717 
718 	if ((n <= 0) || (n > 0xFFFF)) {
719 		printf("enswab: bad len %d\n", n);
720 		return;
721 	}
722 
723 	n >>= 1; n++;
724 #define	STEP	{temp = *from++;*to++ = *from++;*to++ = temp;}
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
735 #endif
736