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