patch lastdel to 100 temporarily
[unix-history] / usr / src / sys / vax / if / if_en.c
CommitLineData
f2853b65 1/* if_en.c 4.62 82/05/27 */
11720282
BJ
2
3#include "en.h"
a9f3e174 4#include "imp.h"
f1b2fa5b 5
11720282 6/*
f1b2fa5b 7 * Xerox prototype (3 Mb) Ethernet interface driver.
11720282
BJ
8 */
9
10#include "../h/param.h"
11#include "../h/systm.h"
12#include "../h/mbuf.h"
11720282
BJ
13#include "../h/pte.h"
14#include "../h/buf.h"
8a13b737
BJ
15#include "../h/protosw.h"
16#include "../h/socket.h"
11720282
BJ
17#include "../h/ubareg.h"
18#include "../h/ubavar.h"
11720282 19#include "../h/enreg.h"
11720282 20#include "../h/cpu.h"
8a13b737
BJ
21#include "../h/mtpr.h"
22#include "../h/vmmac.h"
23#include "../net/in.h"
24#include "../net/in_systm.h"
25#include "../net/if.h"
26#include "../net/if_en.h"
27#include "../net/if_uba.h"
28#include "../net/ip.h"
29#include "../net/ip_var.h"
31c2345c 30#include "../net/pup.h"
f6311fb6 31#include "../net/route.h"
8a2f82db 32#include <errno.h>
8a13b737 33
a453e1b5 34#define ENMTU (1024+512)
dc39362e 35#define ENMRU (1024+512+16) /* 16 is enough to receive trailer */
11720282 36
11720282
BJ
37int enprobe(), enattach(), enrint(), enxint(), encollide();
38struct uba_device *eninfo[NEN];
39u_short enstd[] = { 0 };
40struct uba_driver endriver =
b454c3ea 41 { enprobe, 0, enattach, 0, enstd, "en", eninfo };
11720282
BJ
42#define ENUNIT(x) minor(x)
43
f1b2fa5b
BJ
44int eninit(),enoutput(),enreset();
45
46/*
47 * Ethernet software status per interface.
48 *
49 * Each interface is referenced by a network interface structure,
50 * es_if, which the routing code uses to locate the interface.
51 * This structure contains the output queue for the interface, its address, ...
52 * We also have, for each interface, a UBA interface structure, which
53 * contains information about the UNIBUS resources held by the interface:
54 * map registers, buffered data paths, etc. Information is cached in this
55 * structure for use by the if_uba.c routines in running the interface
56 * efficiently.
57 */
8a13b737 58struct en_softc {
f1b2fa5b
BJ
59 struct ifnet es_if; /* network-visible interface */
60 struct ifuba es_ifuba; /* UNIBUS resources */
61 short es_delay; /* current output delay */
62 short es_mask; /* mask for current output delay */
0658a645 63 short es_lastx; /* host last transmitted to */
f1b2fa5b
BJ
64 short es_oactive; /* is output active? */
65 short es_olen; /* length of last output */
8a13b737 66} en_softc[NEN];
11720282 67
f1b2fa5b
BJ
68/*
69 * Do output DMA to determine interface presence and
70 * interrupt vector. DMA is too short to disturb other hosts.
71 */
11720282
BJ
72enprobe(reg)
73 caddr_t reg;
74{
b454c3ea 75 register int br, cvec; /* r11, r10 value-result */
11720282
BJ
76 register struct endevice *addr = (struct endevice *)reg;
77
8a13b737 78COUNT(ENPROBE);
11720282
BJ
79#ifdef lint
80 br = 0; cvec = br; br = cvec;
2b4b57cd 81 enrint(0); enxint(0); encollide(0);
11720282 82#endif
11720282 83 addr->en_istat = 0;
11720282
BJ
84 addr->en_owc = -1;
85 addr->en_oba = 0;
941ee7ef 86 addr->en_ostat = EN_IEN|EN_GO;
11720282
BJ
87 DELAY(100000);
88 addr->en_ostat = 0;
7d6f1cd5
SL
89#ifdef ECHACK
90 br = 0x16;
91#endif
11720282
BJ
92 return (1);
93}
94
f1b2fa5b
BJ
95/*
96 * Interface exists: make available by filling in network interface
97 * record. System will initialize the interface when it is ready
98 * to accept packets.
99 */
11720282
BJ
100enattach(ui)
101 struct uba_device *ui;
102{
f1b2fa5b 103 register struct en_softc *es = &en_softc[ui->ui_unit];
ee787340 104 register struct sockaddr_in *sin;
8a13b737 105COUNT(ENATTACH);
f1b2fa5b
BJ
106
107 es->es_if.if_unit = ui->ui_unit;
b454c3ea 108 es->es_if.if_name = "en";
f1b2fa5b 109 es->es_if.if_mtu = ENMTU;
e3631d06 110 es->es_if.if_net = ui->ui_flags & 0xff;
f1b2fa5b 111 es->es_if.if_host[0] =
ee787340
SL
112 (~(((struct endevice *)eninfo[ui->ui_unit]->ui_addr)->en_addr)) & 0xff;
113 sin = (struct sockaddr_in *)&es->es_if.if_addr;
114 sin->sin_family = AF_INET;
115 sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]);
116 sin = (struct sockaddr_in *)&es->es_if.if_broadaddr;
117 sin->sin_family = AF_INET;
118 sin->sin_addr = if_makeaddr(es->es_if.if_net, 0);
119 es->es_if.if_flags = IFF_BROADCAST;
f1b2fa5b 120 es->es_if.if_init = eninit;
b454c3ea 121 es->es_if.if_output = enoutput;
f1b2fa5b 122 es->es_if.if_ubareset = enreset;
d9c0644f 123 es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
405c9168 124 if_attach(&es->es_if);
a9f3e174
SL
125#if NIMP == 0
126 /* here's one for you john baby.... */
dc39362e
BJ
127 if (ui->ui_flags &~ 0xff)
128 enlhinit(&es->es_if, (ui->ui_flags &~ 0xff) | 0x0a);
a9f3e174 129#endif
11720282
BJ
130}
131
f1b2fa5b
BJ
132/*
133 * Reset of interface after UNIBUS reset.
134 * If interface is on specified uba, reset its state.
135 */
136enreset(unit, uban)
137 int unit, uban;
8a13b737 138{
11720282 139 register struct uba_device *ui;
f1b2fa5b 140COUNT(ENRESET);
11720282 141
b454c3ea
BJ
142 if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
143 ui->ui_ubanum != uban)
f1b2fa5b 144 return;
b454c3ea 145 printf(" en%d", unit);
f1b2fa5b
BJ
146 eninit(unit);
147}
148
149/*
150 * Initialization of interface; clear recorded pending
151 * operations, and reinitialize UNIBUS usage.
152 */
153eninit(unit)
154 int unit;
155{
b454c3ea
BJ
156 register struct en_softc *es = &en_softc[unit];
157 register struct uba_device *ui = eninfo[unit];
f1b2fa5b 158 register struct endevice *addr;
f1b2fa5b
BJ
159 int s;
160
f1b2fa5b 161 if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
dc39362e 162 sizeof (struct en_header), (int)btoc(ENMRU)) == 0) {
b454c3ea 163 printf("en%d: can't initialize\n", unit);
ee787340 164 es->es_if.if_flags &= ~IFF_UP;
8a13b737 165 return;
11720282 166 }
11720282 167 addr = (struct endevice *)ui->ui_addr;
8a13b737 168 addr->en_istat = addr->en_ostat = 0;
11720282 169
f1b2fa5b 170 /*
b454c3ea
BJ
171 * Hang a receive and start any
172 * pending writes by faking a transmit complete.
f1b2fa5b
BJ
173 */
174 s = splimp();
b454c3ea 175 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
dc39362e 176 addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
b454c3ea
BJ
177 addr->en_istat = EN_IEN|EN_GO;
178 es->es_oactive = 1;
ee787340 179 es->es_if.if_flags |= IFF_UP;
f1b2fa5b
BJ
180 enxint(unit);
181 splx(s);
f6311fb6 182 if_rtinit(&es->es_if, RTF_DIRECT|RTF_UP);
11720282
BJ
183}
184
0658a645 185int enalldelay = 0;
3552a746 186int enlastdel = 25;
0658a645 187int enlastmask = (~0) << 5;
8a13b737 188
f1b2fa5b
BJ
189/*
190 * Start or restart output on interface.
191 * If interface is already active, then this is a retransmit
192 * after a collision, and just restuff registers and delay.
193 * If interface is not already active, get another datagram
194 * to send off of the interface queue, and map it to the interface
195 * before starting the output.
196 */
ae348eea 197enstart(dev)
11720282
BJ
198 dev_t dev;
199{
b454c3ea
BJ
200 int unit = ENUNIT(dev);
201 struct uba_device *ui = eninfo[unit];
202 register struct en_softc *es = &en_softc[unit];
8a13b737 203 register struct endevice *addr;
8a13b737
BJ
204 struct mbuf *m;
205 int dest;
ae348eea 206COUNT(ENSTART);
11720282 207
8a13b737
BJ
208 if (es->es_oactive)
209 goto restart;
f1b2fa5b
BJ
210
211 /*
212 * Not already active: dequeue another request
213 * and map it to the UNIBUS. If no more requests,
214 * just return.
215 */
216 IF_DEQUEUE(&es->es_if.if_snd, m);
8a13b737
BJ
217 if (m == 0) {
218 es->es_oactive = 0;
11720282
BJ
219 return;
220 }
a453e1b5 221 dest = mtod(m, struct en_header *)->en_dhost;
8a13b737 222 es->es_olen = if_wubaput(&es->es_ifuba, m);
f1b2fa5b
BJ
223
224 /*
225 * Ethernet cannot take back-to-back packets (no
0658a645
BJ
226 * buffering in interface. To help avoid overrunning
227 * receivers, enforce a small delay (about 1ms) in interface:
228 * * between all packets when enalldelay
229 * * whenever last packet was broadcast
230 * * whenever this packet is to same host as last packet
f1b2fa5b 231 */
0658a645 232 if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
8a13b737 233 es->es_delay = enlastdel;
0658a645
BJ
234 es->es_mask = enlastmask;
235 }
236 es->es_lastx = dest;
f1b2fa5b 237
8a13b737 238restart:
f1b2fa5b
BJ
239 /*
240 * Have request mapped to UNIBUS for transmission.
241 * Purge any stale data from this BDP, and start the otput.
242 */
ee787340
SL
243 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
244 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
11720282 245 addr = (struct endevice *)ui->ui_addr;
405c9168 246 addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
8a13b737
BJ
247 addr->en_odelay = es->es_delay;
248 addr->en_owc = -((es->es_olen + 1) >> 1);
941ee7ef 249 addr->en_ostat = EN_IEN|EN_GO;
8a13b737 250 es->es_oactive = 1;
11720282
BJ
251}
252
f1b2fa5b
BJ
253/*
254 * Ethernet interface transmitter interrupt.
255 * Start another output if more data to send.
256 */
11720282
BJ
257enxint(unit)
258 int unit;
259{
b454c3ea
BJ
260 register struct uba_device *ui = eninfo[unit];
261 register struct en_softc *es = &en_softc[unit];
519a1ecf 262 register struct endevice *addr = (struct endevice *)ui->ui_addr;
11720282
BJ
263COUNT(ENXINT);
264
8a13b737
BJ
265 if (es->es_oactive == 0)
266 return;
519a1ecf 267 if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
89413846 268 es->es_if.if_oerrors++;
4020bf24
BJ
269 if (es->es_if.if_oerrors % 100 == 0)
270 printf("en%d: += 100 output errors\n", unit);
519a1ecf
BJ
271 endocoll(unit);
272 return;
89413846 273 }
519a1ecf
BJ
274 es->es_if.if_opackets++;
275 es->es_oactive = 0;
276 es->es_delay = 0;
277 es->es_mask = ~0;
7a66118b
BJ
278 if (es->es_ifuba.ifu_xtofree) {
279 m_freem(es->es_ifuba.ifu_xtofree);
280 es->es_ifuba.ifu_xtofree = 0;
281 }
f1b2fa5b 282 if (es->es_if.if_snd.ifq_head == 0) {
0658a645 283 es->es_lastx = 256; /* putatively illegal */
11720282
BJ
284 return;
285 }
8a13b737 286 enstart(unit);
11720282
BJ
287}
288
f1b2fa5b
BJ
289/*
290 * Collision on ethernet interface. Do exponential
291 * backoff, and retransmit. If have backed off all
ee787340 292 * the way print warning diagnostic, and drop packet.
f1b2fa5b 293 */
11720282
BJ
294encollide(unit)
295 int unit;
296{
519a1ecf 297 struct en_softc *es = &en_softc[unit];
11720282
BJ
298COUNT(ENCOLLIDE);
299
f1b2fa5b 300 es->es_if.if_collisions++;
8a13b737 301 if (es->es_oactive == 0)
11720282 302 return;
519a1ecf
BJ
303 endocoll(unit);
304}
305
306endocoll(unit)
307 int unit;
308{
309 register struct en_softc *es = &en_softc[unit];
310
b454c3ea
BJ
311 /*
312 * Es_mask is a 16 bit number with n low zero bits, with
313 * n the number of backoffs. When es_mask is 0 we have
314 * backed off 16 times, and give up.
315 */
8a13b737 316 if (es->es_mask == 0) {
a453e1b5 317 printf("en%d: send error\n", unit);
8a13b737 318 enxint(unit);
b454c3ea 319 return;
11720282 320 }
b454c3ea
BJ
321 /*
322 * Another backoff. Restart with delay based on n low bits
323 * of the interval timer.
324 */
325 es->es_mask <<= 1;
326 es->es_delay = mfpr(ICR) &~ es->es_mask;
327 enstart(unit);
11720282
BJ
328}
329
31c2345c
SL
330struct sockaddr_pup pupsrc = { AF_PUP };
331struct sockaddr_pup pupdst = { AF_PUP };
332struct sockproto pupproto = { PF_PUP };
f1b2fa5b
BJ
333/*
334 * Ethernet interface receiver interrupt.
335 * If input error just drop packet.
336 * Otherwise purge input buffered data path and examine
337 * packet to determine type. If can't determine length
338 * from type, then have to drop packet. Othewise decapsulate
339 * packet based on type and pass to type specific higher-level
340 * input routine.
341 */
11720282
BJ
342enrint(unit)
343 int unit;
344{
b454c3ea
BJ
345 register struct en_softc *es = &en_softc[unit];
346 struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
347 register struct en_header *en;
8a13b737 348 struct mbuf *m;
0658a645 349 int len, plen; short resid;
b454c3ea 350 register struct ifqueue *inq;
8a13b737 351 int off;
11720282
BJ
352COUNT(ENRINT);
353
b454c3ea 354 es->es_if.if_ipackets++;
f1b2fa5b
BJ
355
356 /*
b454c3ea 357 * Purge BDP; drop if input error indicated.
f1b2fa5b 358 */
ee787340
SL
359 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
360 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
941ee7ef 361 if (addr->en_istat&EN_IERROR) {
f1b2fa5b 362 es->es_if.if_ierrors++;
4020bf24
BJ
363 if (es->es_if.if_ierrors % 100 == 0)
364 printf("en%d: += 100 input errors\n", unit);
8a13b737 365 goto setup;
11720282 366 }
f1b2fa5b
BJ
367
368 /*
0658a645 369 * Calculate input data length.
f1b2fa5b
BJ
370 * Get pointer to ethernet header (in input buffer).
371 * Deal with trailer protocol: if type is PUP trailer
372 * get true type from first 16-bit word past data.
373 * Remember that type was trailer by setting off.
374 */
0658a645
BJ
375 resid = addr->en_iwc;
376 if (resid)
377 resid |= 0176000;
dc39362e 378 len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
0658a645 379 len -= sizeof (struct en_header);
dc39362e 380 if (len > ENMRU)
0658a645 381 goto setup; /* sanity */
f1b2fa5b 382 en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
8a13b737
BJ
383#define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off))))
384 if (en->en_type >= ENPUP_TRAIL &&
385 en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
386 off = (en->en_type - ENPUP_TRAIL) * 512;
dc39362e 387 if (off > ENMTU)
b454c3ea 388 goto setup; /* sanity */
8a13b737 389 en->en_type = *endataaddr(en, off, u_short *);
0658a645
BJ
390 resid = *(endataaddr(en, off+2, u_short *));
391 if (off + resid > len)
392 goto setup; /* sanity */
393 len = off + resid;
8a13b737
BJ
394 } else
395 off = 0;
8a13b737
BJ
396 if (len == 0)
397 goto setup;
f1b2fa5b
BJ
398 /*
399 * Pull packet off interface. Off is nonzero if packet
400 * has trailing header; if_rubaget will then force this header
401 * information to be at the front, but we still have to drop
0658a645 402 * the type and length which are at the front of any trailer data.
f1b2fa5b
BJ
403 */
404 m = if_rubaget(&es->es_ifuba, len, off);
a453e1b5
BJ
405 if (m == 0)
406 goto setup;
f1b2fa5b 407 if (off) {
0658a645
BJ
408 m->m_off += 2 * sizeof (u_short);
409 m->m_len -= 2 * sizeof (u_short);
f1b2fa5b 410 }
31c2345c
SL
411 switch (en->en_type) {
412
413#ifdef INET
414 case ENPUP_IPTYPE:
9c8692e9 415 schednetisr(NETISR_IP);
31c2345c
SL
416 inq = &ipintrq;
417 break;
418#endif
ee787340 419#ifdef PUP
31c2345c
SL
420 case ENPUP_PUPTYPE: {
421 struct pup_header *pup = mtod(m, struct pup_header *);
422
423 pupproto.sp_protocol = pup->pup_type;
424 pupdst.spup_addr = pup->pup_dport;
425 pupsrc.spup_addr = pup->pup_sport;
57aa3090
SL
426 raw_input(m, &pupproto, (struct sockaddr *)&pupsrc,
427 (struct sockaddr *)&pupdst);
31c2345c 428 goto setup;
31c2345c 429 }
ee787340 430#endif
c8f8184f
BJ
431 default:
432 m_freem(m);
433 goto setup;
ee787340
SL
434 }
435
1e977657
BJ
436 if (IF_QFULL(inq)) {
437 IF_DROP(inq);
ee787340 438 m_freem(m);
1e977657
BJ
439 } else
440 IF_ENQUEUE(inq, m);
f1b2fa5b 441
ae348eea 442setup:
f1b2fa5b
BJ
443 /*
444 * Reset for next packet.
445 */
446 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
dc39362e 447 addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
941ee7ef 448 addr->en_istat = EN_IEN|EN_GO;
ae348eea 449}
11720282 450
8a13b737
BJ
451/*
452 * Ethernet output routine.
453 * Encapsulate a packet of type family for the local net.
f1b2fa5b
BJ
454 * Use trailer local net encapsulation if enough data in first
455 * packet leaves a multiple of 512 bytes of data in remainder.
8a13b737 456 */
ee787340 457enoutput(ifp, m0, dst)
8a13b737
BJ
458 struct ifnet *ifp;
459 struct mbuf *m0;
ee787340 460 struct sockaddr *dst;
11720282 461{
8a2f82db 462 int type, dest, s, error;
f1b2fa5b 463 register struct mbuf *m = m0;
8a13b737 464 register struct en_header *en;
ee787340 465 register int off;
8a13b737 466
9d1b03e0 467COUNT(ENOUTPUT);
ee787340 468 switch (dst->sa_family) {
11720282 469
8a13b737 470#ifdef INET
ee787340 471 case AF_INET:
4e818526 472 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
8a2f82db
SL
473 if (dest & 0x00ffff00) {
474 error = EPERM; /* ??? */
3734056d 475 goto bad;
8a2f82db 476 }
4e818526 477 dest = (dest >> 24) & 0xff;
ee787340
SL
478 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
479 if (off > 0 && (off & 0x1ff) == 0 &&
0658a645 480 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
8a13b737 481 type = ENPUP_TRAIL + (off>>9);
0658a645
BJ
482 m->m_off -= 2 * sizeof (u_short);
483 m->m_len += 2 * sizeof (u_short);
f1b2fa5b 484 *mtod(m, u_short *) = ENPUP_IPTYPE;
0658a645 485 *(mtod(m, u_short *) + 1) = m->m_len;
f1b2fa5b 486 goto gottrailertype;
8a13b737 487 }
f1b2fa5b
BJ
488 type = ENPUP_IPTYPE;
489 off = 0;
490 goto gottype;
8a13b737 491#endif
31c2345c 492#ifdef PUP
ee787340
SL
493 case AF_PUP:
494 dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host;
31c2345c
SL
495 type = ENPUP_PUPTYPE;
496 off = 0;
497 goto gottype;
31c2345c 498#endif
8a13b737
BJ
499
500 default:
ee787340
SL
501 printf("en%d: can't handle af%d\n", ifp->if_unit,
502 dst->sa_family);
8a2f82db
SL
503 error = EAFNOSUPPORT;
504 goto bad;
8a13b737 505 }
f1b2fa5b 506
b454c3ea 507gottrailertype:
f1b2fa5b
BJ
508 /*
509 * Packet to be sent as trailer: move first packet
510 * (control information) to end of chain.
511 */
f1b2fa5b
BJ
512 while (m->m_next)
513 m = m->m_next;
514 m->m_next = m0;
515 m = m0->m_next;
516 m0->m_next = 0;
b454c3ea 517 m0 = m;
f1b2fa5b 518
b454c3ea 519gottype:
f1b2fa5b
BJ
520 /*
521 * Add local net header. If no space in first mbuf,
522 * allocate another.
523 */
a453e1b5
BJ
524 if (m->m_off > MMAXOFF ||
525 MMINOFF + sizeof (struct en_header) > m->m_off) {
ef9b4258 526 m = m_get(M_DONTWAIT);
8a13b737 527 if (m == 0) {
8a2f82db
SL
528 error = ENOBUFS;
529 goto bad;
8a13b737
BJ
530 }
531 m->m_next = m0;
532 m->m_off = MMINOFF;
533 m->m_len = sizeof (struct en_header);
534 } else {
8a13b737
BJ
535 m->m_off -= sizeof (struct en_header);
536 m->m_len += sizeof (struct en_header);
11720282 537 }
8a13b737
BJ
538 en = mtod(m, struct en_header *);
539 en->en_shost = ifp->if_host[0];
540 en->en_dhost = dest;
541 en->en_type = type;
f1b2fa5b
BJ
542
543 /*
544 * Queue message on interface, and start output if interface
545 * not yet active.
546 */
8a13b737 547 s = splimp();
1e977657
BJ
548 if (IF_QFULL(&ifp->if_snd)) {
549 IF_DROP(&ifp->if_snd);
8a2f82db
SL
550 error = ENOBUFS;
551 goto qfull;
1e977657 552 }
8a13b737 553 IF_ENQUEUE(&ifp->if_snd, m);
8a13b737
BJ
554 if (en_softc[ifp->if_unit].es_oactive == 0)
555 enstart(ifp->if_unit);
89413846 556 splx(s);
4e818526 557 return (0);
8a2f82db
SL
558qfull:
559 m0 = m;
560 splx(s);
561bad:
562 m_freem(m0);
563 return (error);
11720282 564}
a9f3e174
SL
565
566#if NIMP == 0 && NEN > 0
567/*
568 * Logical host interface driver.
569 * Allows host to appear as an ARPAnet
570 * logical host. Must also have routing
571 * table entry set up to forward packets
572 * to appropriate gateway on localnet.
573 */
574
575struct ifnet enlhif;
dc39362e 576int looutput();
a9f3e174
SL
577
578/*
579 * Called by localnet interface to allow logical
dc39362e 580 * host interface to "attach", it's purpose
a9f3e174
SL
581 * is simply to establish the host's arpanet address.
582 */
dc39362e
BJ
583enlhinit(esifp, addr)
584 struct ifnet *esifp;
a9f3e174
SL
585 int addr;
586{
587 register struct ifnet *ifp = &enlhif;
588 register struct sockaddr_in *sin;
589
590COUNT(ENLHINIT);
591 ifp->if_name = "lh";
592 ifp->if_mtu = ENMTU;
593 sin = (struct sockaddr_in *)&ifp->if_addr;
594 sin->sin_family = AF_INET;
595 sin->sin_addr.s_addr = addr;
596 ifp->if_net = sin->sin_addr.s_net;
dc39362e
BJ
597 ifp->if_flags = IFF_UP|IFF_POINTOPOINT;
598 ifp->if_dstaddr = esifp->if_addr;
599 ifp->if_output = looutput;
a9f3e174 600 if_attach(ifp);
c46ba114 601 rtinit(&ifp->if_addr, &ifp->if_addr, RTF_UP|RTF_DIRECT|RTF_HOST);
a9f3e174
SL
602}
603#endif