xref: /original-bsd/sys/netiso/if_eon.c (revision c47935e1)
1 /***********************************************************
2 		Copyright IBM Corporation 1987
3 
4                       All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of IBM not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13 
14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 ******************************************************************/
23 
24 /*
25  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26  */
27 /*
28  * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $
29  * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $
30  *
31  *	EON rfc
32  *  Layer between IP and CLNL
33  *
34  * TODO:
35  * Put together a current rfc986 address format and get the right offset
36  * for the nsel
37  */
38 
39 #ifndef lint
40 static char *rcsid = "$Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $";
41 #endif lint
42 
43 #ifdef EON
44 #define NEON 1
45 
46 
47 #include "param.h"
48 #include "systm.h"
49 #include "types.h"
50 #include "mbuf.h"
51 #include "buf.h"
52 #include "protosw.h"
53 #include "socket.h"
54 #include "ioctl.h"
55 #include "errno.h"
56 #include "types.h"
57 
58 #include "../net/if.h"
59 #include "../net/iftypes.h"
60 #include "../net/netisr.h"
61 #include "../net/route.h"
62 #include "machine/mtpr.h"
63 
64 #include "../netinet/in.h"
65 #include "../netinet/in_systm.h"
66 #include "../netinet/ip.h"
67 #include "../netinet/ip_var.h"
68 #include "../netinet/if_ether.h"
69 
70 #include "iso.h"
71 #include "iso_var.h"
72 #include "iso_snpac.h"
73 extern struct snpa_cache all_es, all_is;
74 #include "argo_debug.h"
75 #include "iso_errno.h"
76 #include "eonvar.h"
77 
78 #define EOK 0
79 
80 int						eoninput();
81 int						eonint();
82 int						eonoutput();
83 int						eonioctl();
84 int						eonprobe();
85 int						eonattach();
86 int						eoninit();
87 extern 	int				ip_output();
88 struct ifnet			eonif[NEON];
89 
90 #ifdef FAKEIOCCDEV
91 #include "machine/io.h"
92 #include "../machineio/ioccvar.h"
93 
94 #define EON_FAKE_CSR 0
95 int eon_fakeautoconf[2]; /* need at least 2 ints */
96 
97 caddr_t eonstd[] = { (caddr_t) eon_fakeautoconf, 0 };
98 struct	iocc_device *eoninfo[NEON];
99 
100 struct	iocc_driver eondriver = {
101 	eonprobe, 	/* idr_probe */
102 	0,			/* idr_slave */
103 	eonattach,	/* idr_attach */
104 	0,			/* idr_dgo */
105 	eonstd,		/* idr_addr - list of standard addresses for device */
106 	"eon",		/* idr_dname */
107 	eoninfo,	/* idr_dinfo - backptrs to iodinit structs */
108 	0,			/* idr_mname - controller name */
109 	0,			/* idr_minfo -- backptrs to iominit structs */
110 	eonint,		/* idr_intr - interrupt rtn */
111 	0,  		/* idr_csr - offset to read/write csr */
112 	EON_FAKE_CSR,	 /* idr_chanrelse */
113 	0, 			/* idr_flags */
114 };
115 #else
116 struct iocc_device {
117 	int iod_unit;
118 } bsd_iocc_fakeout;
119 
120 eonprotoinit() {
121 	(void) eonprobe();
122 	(void) eonattach(&bsd_iocc_fakeout);
123 }
124 #define PROBE_OK 0;
125 #endif
126 
127 
128 /*
129  * entry in the EON address cache (list)
130  * (or pt-pt links list, however you view it)
131  */
132 
133 struct eon_centry {
134 	struct qhdr eonc_q_LINK;
135 #define eonc_nextLINK eonc_q_LINK.link
136 #define eonc_prevLINK eonc_q_LINK.flink
137 
138 	struct qhdr eonc_q_IS;
139 #define eonc_nextIS eonc_q_IS.link
140 #define eonc_prevIS eonc_q_IS.flink
141 
142 	struct qhdr eonc_q_ES;
143 #define eonc_nextES eonc_q_ES.link
144 #define eonc_prevES eonc_q_ES.flink
145 
146 	struct in_addr	eonc_addr;
147 	u_short		eonc_status;
148 };
149 
150 /* kinda like mtod() but for eon_centries */
151 #define qtocentry(q, off)  ((struct eon_centry *)  (((caddr_t)(q)) - off))
152 #define centrytoq(c, off)  ((struct qhdr *)  (((caddr_t)(c)) + off))
153 
154 struct qhdr 			eon_LINK_hdr = {
155 	(struct qhdr *)0,
156 	(struct qhdr *)0,
157 };
158 static struct qhdr 		eon_IS_hdr = {
159 	(struct qhdr *)0,
160 	(struct qhdr *)0,
161 };
162 static struct qhdr 		eon_ES_hdr = {
163 	(struct qhdr *)0,
164 	(struct qhdr *)0,
165 };
166 static struct qhdr 		eon_FREE_hdr = {
167 	(struct qhdr *)0,
168 	(struct qhdr *)0,
169 };
170 
171 #define INITQ(q)  (q)->rlink = (q)->link = (q)
172 
173 /*
174  * FUNCTION:		eon_dumpcache
175  *
176  * PURPOSE:			dump the cache beginning with the argument given
177  *
178  * RETURNS:			0
179  */
180 
181 eon_dumpcache(which)
182 	int 						which;
183 {
184 	register int 				off;
185 	register struct eon_centry 	*ent;
186 	struct	qhdr				*hdr;
187 
188 	switch (which) {
189 		case E_FREE:
190 			printf("FREE LIST\n");
191 			off = _offsetof( struct eon_centry, eonc_q_LINK);
192 			hdr = &eon_FREE_hdr;
193 			ent = qtocentry( hdr->link,
194 				_offsetof( struct eon_centry, eonc_q_LINK));
195 			break;
196 		case E_ES:
197 			printf("ES LIST\n");
198 			off = _offsetof( struct eon_centry, eonc_q_ES);
199 			hdr = &eon_ES_hdr;
200 			ent = qtocentry( hdr->link,
201 				_offsetof( struct eon_centry, eonc_q_ES));
202 			break;
203 		case E_IS:
204 			printf("IS LIST\n");
205 			off = _offsetof( struct eon_centry, eonc_q_IS);
206 			hdr = &eon_IS_hdr;
207 			ent = qtocentry( hdr->link,
208 				_offsetof( struct eon_centry, eonc_q_IS));
209 			break;
210 		case E_LINK:
211 			printf("LINK LIST\n");
212 			off = _offsetof( struct eon_centry, eonc_q_LINK);
213 			hdr = &eon_LINK_hdr;
214 			ent = qtocentry( hdr->link,
215 				_offsetof( struct eon_centry, eonc_q_LINK));
216 			break;
217 	}
218 	if(hdr == centrytoq(ent, off)->link )
219 		printf("EMPTY\n");
220 	else while(1) {
221 		printf("0x%x: %d.%d.%d.%d, %s %s\n", ent,
222 			(ent->eonc_addr.s_addr>>24)&0xff,
223 			(ent->eonc_addr.s_addr>>16)&0xff,
224 			(ent->eonc_addr.s_addr>>8)&0xff,
225 			(ent->eonc_addr.s_addr)&0xff,
226 			((ent->eonc_status & EON_ESLINK_UP)?"ES^":
227 				(ent->eonc_status & EON_ESLINK_DOWN)?"es*": "   "),
228 			((ent->eonc_status & EON_ISLINK_UP)?"IS^":
229 				(ent->eonc_status & EON_ISLINK_DOWN)?"is*": "   ")
230 			);
231 		dump_buf(ent, sizeof(struct eon_centry) );
232 
233 		{ 	/* ent = ent.next: */
234 			register struct qhdr 	*q;
235 
236 			q = centrytoq(ent, off)->link;
237 			if( q == hdr)
238 				break;
239 			if( q == (struct qhdr *)0) /* panic */ {
240 				printf("eon0: BAD Q HDR or CENTRY! q 0x%x ent 0x%x off 0x%x\n",
241 					q, ent, off);
242 				break;
243 			}
244 			ent = qtocentry( q,  off );
245 		}
246 	}
247 }
248 /*
249  * FUNCTION:		eon_initcache
250  *
251  * PURPOSE:			allocs a bunch of free cache entries
252  *
253  * RETURNS:			0
254  */
255 
256 eon_initcache()
257 {
258 	static struct eon_centry	eoncache[EON_CACHESIZE];
259 	register int 				i;
260 	register struct eon_centry 	*ent;
261 
262 	bzero( eoncache, EON_CACHESIZE*sizeof(struct eon_centry));
263 	INITQ( &eon_FREE_hdr );
264 	INITQ( &eon_LINK_hdr );
265 	INITQ( &eon_IS_hdr );
266 	INITQ( &eon_ES_hdr );
267 
268 	ent = eoncache;
269 
270 	for(i=0; i< EON_CACHESIZE; i++,ent++) {
271 		_insque( centrytoq(ent, _offsetof( struct eon_centry, eonc_q_LINK)),
272 			&eon_FREE_hdr);
273 	}
274 	printf("eon0: cache initialized\n");
275 }
276 
277 /*
278  * FUNCTION:		eonprobe
279  *
280  * PURPOSE:			filler for device configuration
281  *
282  * RETURNS:			PROBE_OK
283  */
284 
285 int int_level, int_irq;
286 eonprobe()
287 {
288 	extern int	int_level, int_irq;
289 
290 	printf("eonprobe() \n");
291 	int_level = int_irq = 0x3; /* pick something - anything but -1 */
292 	return PROBE_OK;
293 }
294 
295 /*
296  * FUNCTION:		eonattach
297  *
298  * PURPOSE:			autoconf attach routine
299  *
300  * RETURNS:			void
301  */
302 
303 eonattach(iod)
304 	register struct iocc_device *iod;
305 {
306 	register struct ifnet *ifp = &eonif[iod->iod_unit];
307 
308 	IFDEBUG(D_EON)
309 		printf("eonattach()\n");
310 	ENDDEBUG
311 	ifp->if_unit = iod->iod_unit;
312 	ifp->if_name = "eon";
313 	ifp->if_mtu = ETHERMTU;
314 		/* since everything will go out over ether or token ring */
315 
316 	ifp->if_init = eoninit;
317 	ifp->if_ioctl = eonioctl;
318 	ifp->if_output = eonoutput;
319 	ifp->if_type = IFT_EON;
320 	ifp->if_addrlen = 5;
321 	ifp->if_hdrlen = EONIPLEN;
322 	ifp->if_flags = IFF_BROADCAST;
323 	if_attach(ifp);
324 
325 	IFDEBUG(D_EON)
326 		printf("eonattach()\n");
327 	ENDDEBUG
328 	eon_initcache();
329 	IFDEBUG(D_EON)
330 		printf("eon%d: attached\n", iod->iod_unit);
331 	ENDDEBUG
332 }
333 
334 static struct eon_centry *
335 find_oldent( ea )
336 	struct sockaddr_eon *ea;
337 {
338 	register	int				offset =
339 						_offsetof( struct eon_centry, eonc_q_LINK);
340 	register struct eon_centry 	*ent, *oent;
341 
342 	oent = ent = qtocentry(eon_LINK_hdr.link, offset);
343 	IFDEBUG(D_EON)
344 		printf("eon: find_oldent() ipaddr: %d.%d.%d.%d\n",
345 			(ea->seon_ipaddr>>24)&0xff,
346 			(ea->seon_ipaddr>>16)&0xff,
347 			(ea->seon_ipaddr>>8)&0xff,
348 			(ea->seon_ipaddr)&0xff );
349 	ENDDEBUG
350 	do {
351 		if( ent->eonc_addr.s_addr == ea->seon_ipaddr )
352 			return ent;
353 		ent = qtocentry(ent->eonc_nextLINK, offset);
354 	} while (ent != oent);
355 	return (struct eon_centry *)0;
356 }
357 
358 /*
359  * FUNCTION:		eonioctl
360  *
361  * PURPOSE:			io controls - ifconfig
362  *				need commands to
363  *					link-UP (core addr) (flags: ES, IS)
364  *					link-DOWN (core addr) (flags: ES, IS)
365  *				must be callable from kernel or user
366  *
367  * RETURNS:			nothing
368  */
369 eonioctl(ifp, cmd, data)
370 	register struct ifnet *ifp;
371 	register int cmd;
372 	register caddr_t data;
373 {
374 	struct iso_ifreq *ifr = (struct iso_ifreq *)data;
375 	register struct sockaddr_eon *eoa =
376 				(struct sockaddr_eon *)&(ifr->ifr_Addr);
377 	register int s = splimp();
378 	register int error = 0;
379 
380 	IFDEBUG(D_EON)
381 		printf("eonioctl (cmd 0x%x) \n", cmd);
382 	ENDDEBUG
383 
384 	switch (cmd){
385 	case SIOCSEONCORE: {
386 			/* add pt-pt link to the set of core addrs */
387 			register 	struct eon_centry *ent, *oldent;
388 			register	u_short			  which;
389 
390 			/* "which" tells which lists to put these guys in - don't
391 			 * want to insert something in a list if it's already there
392 			 */
393 #define LEGIT_EONADDR(a)\
394 	((a->seon_family == AF_ISO) && (a->seon_afi == AFI_RFC986) &&\
395 	(a->seon_idi[0] == 0) && (a->seon_idi[1] == 6) \
396 	&& (a->seon_vers == EON_986_VERSION) && (a->seon_adrlen == 0x14))
397 
398 			if( ! LEGIT_EONADDR(eoa) ) {
399 				error = EADDRNOTAVAIL;
400 				break;
401 			}
402 
403 			oldent = find_oldent( eoa );
404 			IFDEBUG(D_EON)
405 				printf("eonioctl legit seon_status 0x%x oldent %s\n",
406 					eoa->seon_status, oldent?"found":"not found");
407 			ENDDEBUG
408 
409 			if( eoa->seon_status & UPBITS ) {
410 				if (!oldent) {
411 					/* doesn't exist - need to create one */
412 					if (eon_FREE_hdr.link == eon_FREE_hdr.rlink)
413 						return ENOBUFS;
414 					ent = qtocentry(eon_FREE_hdr.link,
415 								_offsetof( struct eon_centry, eonc_q_LINK));
416 					remque( &(ent->eonc_q_LINK) );
417 					ent->eonc_addr.s_addr = eoa->seon_ipaddr;
418 					insque( &(ent->eonc_q_LINK), (&eon_LINK_hdr));
419 					oldent = ent;
420 				}
421 
422 				which = (eoa->seon_status ^ oldent->eonc_status) &
423 					eoa->seon_status & UPBITS;
424 
425 				oldent->eonc_status |= (eoa->seon_status & UPBITS);
426 
427 				if( which & EON_ESLINK_UP )
428 					insque( &oldent->eonc_q_ES, (&eon_ES_hdr));
429 				if( which & EON_ISLINK_UP )
430 					insque( &oldent->eonc_q_IS, (&eon_IS_hdr));
431 			}
432 
433 			if( eoa->seon_status & DOWNBITS ) {
434 				if(!oldent) {
435 					return ENOENT; /* no such entry */
436 				}
437 				which = (eoa->seon_status ^ oldent->eonc_status) &
438 					eoa->seon_status & DOWNBITS;
439 
440 				oldent->eonc_status |= (eoa->seon_status & DOWNBITS);
441 
442 				if( which & EON_ESLINK_DOWN )
443 					remque( &(oldent->eonc_q_ES) );
444 				if( which & EON_ISLINK_DOWN )
445 					remque( &(oldent->eonc_q_IS) );
446 			}
447 
448 		IFDEBUG(D_EON)
449 			printf("at end status 0x%x\n", oldent->eonc_status);
450 		ENDDEBUG
451 		break;
452 		}
453 
454 	case SIOCGEONCORE:
455 		{
456 			register 	struct eon_centry *oldent;
457 
458 			oldent = find_oldent( eoa );
459 			if( oldent == (struct eon_centry *)0 )
460 				error = EADDRNOTAVAIL;
461 			else
462 				eoa->seon_status = oldent->eonc_status;
463 		}
464 		break;
465 
466 	case SIOCSIFADDR:
467 		ifp->if_flags |= IFF_UP;
468 		break;
469 
470 	case SIOCSIFFLAGS:
471 		if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags &
472 		  IFF_RUNNING){
473 			ifp->if_flags &= ~IFF_RUNNING;
474 		} else if (ifp->if_flags & IFF_UP && (ifp->if_flags &
475 		  IFF_RUNNING) == 0)
476 			eoninit(ifp->if_unit);
477 		break;
478 	default:
479 		error = EINVAL;
480 	}
481 	splx(s);
482 	return(error);
483 }
484 
485 /*
486  * FUNCTION:		eoninit
487  *
488  * PURPOSE:			initialization
489  *
490  * RETURNS:			nothing
491  */
492 
493 eoninit(unit)
494 	int unit;
495 {
496 	printf("eon driver-init eon%d\n", unit);
497 }
498 
499 
500 /*
501  * FUNCTION:		eonint
502  *
503  * PURPOSE:			filler for device configuration
504  *
505  * RETURNS:			nothing
506  *
507  * NOTES:			*should* never get called - for debugging it's here
508  */
509 
510 eonint()
511 {
512 	/* silent - so no more stray interrupt messages from the aed! yay
513 	printf("eonint() called - BOGUS INTERRUPT\n");
514 	*/
515 }
516 
517 
518 /*
519  * FUNCTION:		eonoutput
520  *
521  * PURPOSE:			prepend an eon header and hand to IP
522  * ARGUMENTS:	 	(ifp) is points to the ifnet structure for this unit/device
523  *					(m)  is an mbuf *, *m is a CLNL packet
524  *					(dst) is a destination address - have to interp. as
525  *					multicast or broadcast or real address.
526  *
527  * RETURNS:			unix error code
528  *
529  * NOTES:
530  *
531  */
532 eonoutput(ifp, morig, dst)
533 	struct ifnet 	*ifp;
534 	register struct mbuf	*morig;		/* packet */
535 	struct sockaddr_iso		*dst;		/* destination addr */
536 {
537 	int						s;
538 	struct eon_hdr			*eonhdr;
539 	struct ip				*iphdr;
540 	struct mbuf				*mh;
541 	int						error = 0;
542 	register int			datalen;
543 	caddr_t					dstipaddrloc;
544 	int						single = 0, class, qoffset = 0, snpalen;
545 	register struct eon_centry	*ent;
546 	register struct sockaddr_eon *eoa;
547 	struct qhdr				*q;
548 	char edst[6];
549 
550 	IFDEBUG(D_EON)
551 		printf("eonoutput \n" );
552 	ENDDEBUG
553 
554 	if( dst->siso_family != AF_ISO ) {
555 	einval:
556 		error =  EINVAL;
557 		goto flush;
558 	}
559 	if ((morig->m_flags & M_PKTHDR) == 0) {
560 		printf("eon: got non headered packet\n");
561 		goto einval;
562 	}
563 	eoa = (struct sockaddr_eon *)dst;
564 	if (LEGIT_EONADDR(eoa)) {
565 		class = eoa->seon_protoid;
566 		dstipaddrloc = (caddr_t)&(eoa->seon_ipaddr);
567 	} else if (eoa->seon_afi == AFI_SNA) {
568 		dstipaddrloc = (caddr_t)&(dst->siso_data[1]);
569 		if (dst->siso_nlen == 6) {
570 			class = dst->siso_data[5];
571 		} else if (dst->siso_nlen == 7) {
572 			if (bcmp(dstipaddrloc, all_is.sc_snpa, 6))
573 				class = EON_MULTICAST_ES;
574 			else if (bcmp(dstipaddrloc, all_es.sc_snpa, 6))
575 				class = EON_MULTICAST_IS;
576 			else
577 				goto einval;
578 		} else
579 				goto einval;
580 	} else if (0 == iso_snparesolve(ifp, dst, edst, &snpalen)) {
581 		dstipaddrloc = (caddr_t)edst;
582 		class = edst[4];
583 	} else {
584 		error = EINVAL;
585 		goto flush;
586 	}
587 	switch (class) {
588 		case EON_NORMAL_ADDR:
589 			IncStat(es_out_normal);
590 			single = 1;
591 			break;
592 
593 		case EON_BROADCAST:
594 			IncStat(es_out_broad);
595 			if(eon_LINK_hdr.link == eon_LINK_hdr.rlink) {
596 				error = EADDRNOTAVAIL;
597 			} else {
598 				qoffset = _offsetof( struct eon_centry, eonc_q_LINK);
599 				ent = qtocentry(eon_LINK_hdr.link, qoffset);
600 				dstipaddrloc = (caddr_t) &(ent->eonc_addr);
601 			}
602 			break;
603 		case EON_MULTICAST_ES:
604 			IncStat(es_out_multi_es);
605 			if (eon_ES_hdr.link == eon_ES_hdr.rlink) {
606 				error = EADDRNOTAVAIL;
607 			} else {
608 				qoffset = _offsetof( struct eon_centry, eonc_q_ES);
609 				ent = qtocentry(eon_ES_hdr.link, qoffset);
610 				dstipaddrloc = (caddr_t) &(ent->eonc_addr);
611 			}
612 			break;
613 		case EON_MULTICAST_IS:
614 			IncStat(es_out_multi_is);
615 			if (eon_IS_hdr.link == eon_IS_hdr.rlink) {
616 				error = EADDRNOTAVAIL;
617 			} else {
618 				qoffset = _offsetof( struct eon_centry, eonc_q_LINK);
619 				ent = qtocentry(eon_IS_hdr.link, qoffset);
620 				dstipaddrloc = (caddr_t) &(ent->eonc_addr);
621 			}
622 			break;
623 		default:
624 			printf("bad class value; treated as EON_NORMAL_ADDR\n");
625 			class = EON_NORMAL_ADDR;
626 			single = 1;
627 			break;
628 	}
629 	if( error )
630 		goto done;
631 
632 	/* get data length -- needed later */
633 	datalen = morig->m_pkthdr.len;
634 	IFDEBUG(D_EON)
635 		printf("eonoutput : m_datalen returns %d\n", datalen);
636 	ENDDEBUG
637 
638 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
639 	if(mh == (struct mbuf *)0)
640 		goto done;
641 
642 	/* put an eon_hdr in the buffer, prepended by an ip header */
643 	mh->m_len = sizeof(struct eon_hdr);
644 	MH_ALIGN(mh, sizeof(struct eon_hdr));
645 	mh->m_next = morig;
646 	eonhdr = mtod(mh, struct eon_hdr *);
647 	eonhdr->eonh_class = class;
648 	eonhdr->eonh_vers = EON_VERSION;
649 	eonhdr->eonh_csum = 0;
650 
651 	IFDEBUG(D_EON)
652 		printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
653 			mh, _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
654 	ENDDEBUG
655 	iso_gen_csum(mh,
656 		_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
657 
658 	mh->m_data -= sizeof(*iphdr);
659 	mh->m_len += sizeof(*iphdr);
660 	iphdr = mtod(mh, struct ip *);
661 	bzero((caddr_t)iphdr, sizeof (*iphdr));
662 
663 	iphdr->ip_p = IPPROTO_EON;
664 	iphdr->ip_len = (u_short)(mh->m_pkthdr.len = EONIPLEN + datalen);
665 	iphdr->ip_ttl = MAXTTL;
666 	iphdr->ip_src.s_addr = INADDR_ANY;
667 
668 	IFDEBUG(D_EON)
669 		printf("eonoutput : after gen csum: ip_len %d/0x%x\n",
670 						mh->m_pkthdr.len, mh->m_pkthdr.len);
671 	ENDDEBUG
672 
673 	morig = mh;
674 
675 	for(;;) {
676 
677 		if( !single ) {
678 			/* make a copy to send */
679 			IFDEBUG(D_EON)
680 				printf("eonoutput : m_copy (0x%x, 0, 0x%x)\n",
681 					morig, iphdr->ip_len);
682 			ENDDEBUG
683 			if (((mh = m_copy(morig, 0, morig->m_pkthdr.len)) == 0) ||
684 			    ((mh = m_pullup(mh, sizeof(struct ip))) == 0)) {
685 				error = ENOBUFS;
686 				goto done;
687 			}
688 			iphdr = mtod(mh, struct ip *);
689 		}
690 		IFDEBUG(D_EON)
691 			printf("eonoutput : bcopy 0x%x to 0x%x length %d\n",
692 				dstipaddrloc,
693 				(caddr_t)&(iphdr->ip_dst.s_addr),
694 				sizeof(iphdr->ip_dst.s_addr));
695 		ENDDEBUG
696 		bcopy(dstipaddrloc, (caddr_t)&(iphdr->ip_dst.s_addr),
697 										sizeof(iphdr->ip_dst.s_addr));
698 		IFDEBUG(D_EON)
699 			printf("eonoutput : dst ip addr : %d.%d.%d.%d",
700 				(iphdr->ip_dst.s_addr>>24)&0xff,
701 				(iphdr->ip_dst.s_addr>>16)&0xff,
702 				(iphdr->ip_dst.s_addr>>8)&0xff,
703 				(iphdr->ip_dst.s_addr)&0xff );
704 		ENDDEBUG
705 
706 		IFDEBUG(D_EON)
707 			printf("eonoutput ip_output : eon header:\n");
708 			dump_buf(eonhdr, sizeof(struct eon_hdr));
709 			printf("ip header:\n");
710 			dump_buf(iphdr, sizeof(struct ip));
711 		ENDDEBUG
712 
713 		IncStat(es_ipout);
714 		if( error = ip_output(mh, (struct mbuf *)0, (struct route *)0, 0) )
715 				break;
716 
717 		IFDEBUG(D_EON)
718 			printf("eonoutput ip_output returns 0x%x; single %d\n",
719 				error, single);
720 		ENDDEBUG
721 
722 		if(single)
723 			break;
724 
725 		q = centrytoq(ent, qoffset)->link;
726 		if( q == (struct qhdr *)0)
727 			break;
728 		ent = qtocentry( q,  qoffset );
729 		IFDEBUG(D_EON)
730 			printf("eonoutput : get next entry: 0x%x\n", ent);
731 		ENDDEBUG
732 		dstipaddrloc = (caddr_t) &(ent->eonc_addr);
733 		IFDEBUG(D_EON)
734 			printf("eonoutput : dump of eon_centry 0x%x:\n", ent );
735 			dump_buf(ent, sizeof(struct eon_centry) );
736 		ENDDEBUG
737 	}
738 done:
739 	if( !single ) {
740 		IFDEBUG(D_EON)
741 			printf("eonoutput : freeing morig 0x%x\n", morig);
742 		ENDDEBUG
743 flush:
744 		m_freem(morig);
745 	}
746 	return error;
747 }
748 
749 eoninput(m, iphlen)
750 	register struct mbuf	*m;
751 	int iphlen;
752 {
753 	register struct eon_hdr	*eonhdr;
754 	register struct ip		*iphdr;
755 	struct ifnet 			*eonifp;
756 	int						s;
757 
758 	eonifp = &eonif[0]; /* kludge - really want to give CLNP
759 						* the ifp for eon, not for the real device
760 						*/
761 
762 	IFDEBUG(D_EON)
763 		printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
764 			m, m?m->m_data:0, m?m->m_len:0);
765 	ENDDEBUG
766 
767 	if (m == 0)
768 		return;
769 	if (iphlen > sizeof (struct ip))
770 		ip_stripoptions(m, (struct mbuf *)0);
771 	if (m->m_len < EONIPLEN) {
772 		if ((m = m_pullup(m, EONIPLEN)) == 0) {
773 			IncStat(es_badhdr);
774 drop:
775 			IFDEBUG(D_EON)
776 				printf("eoninput: DROP \n" );
777 			ENDDEBUG
778 			eonifp->if_ierrors ++;
779 			m_freem(m);
780 			return;
781 		}
782 	}
783 	iphdr = mtod(m, struct ip *);
784 	/* do a few checks for debugging */
785 	if( iphdr->ip_p != IPPROTO_EON ) {
786 		IncStat(es_badhdr);
787 		goto drop;
788 	}
789 	/* temporarily drop ip header from the mbuf */
790 	m->m_data += sizeof(struct ip);
791 	eonhdr = mtod(m, struct eon_hdr *);
792 	if( iso_check_csum( m, sizeof(struct eon_hdr) )   != EOK ) {
793 		IncStat(es_badcsum);
794 		goto drop;
795 	}
796 	m->m_data -= sizeof(struct ip);
797 
798 	IFDEBUG(D_EON)
799 		printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
800 		printf("eoninput: eon header:\n");
801 		dump_buf(eonhdr, sizeof(struct eon_hdr));
802 	ENDDEBUG
803 
804 	/* checks for debugging */
805 	if( eonhdr->eonh_vers != EON_VERSION) {
806 		IncStat(es_badhdr);
807 		goto drop;
808 	}
809 	m->m_flags &= ~(M_BCAST|M_MCAST);
810 	switch( eonhdr->eonh_class) {
811 		case EON_BROADCAST:
812 			IncStat(es_in_broad);
813 			m->m_flags |= M_BCAST;
814 			break;
815 		case EON_NORMAL_ADDR:
816 			IncStat(es_in_normal);
817 			break;
818 		case EON_MULTICAST_ES:
819 			IncStat(es_in_multi_es);
820 			m->m_flags |= M_MCAST;
821 			break;
822 		case EON_MULTICAST_IS:
823 			IncStat(es_in_multi_is);
824 			m->m_flags |= M_MCAST;
825 			break;
826 	}
827 	eonifp->if_ipackets ++;
828 
829 	{
830 		/* put it on the CLNP queue and set soft interrupt */
831 		struct ifqueue 			*ifq;
832 		extern struct ifqueue 	clnlintrq;
833 
834 		m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
835 		IFDEBUG(D_EON)
836 			printf("eoninput to clnl IFQ\n");
837 		ENDDEBUG
838 		ifq = &clnlintrq;
839 		s = splimp();
840 		if (IF_QFULL(ifq)) {
841 			IF_DROP(ifq);
842 			m_freem(m);
843 			eonifp->if_ierrors ++;
844 			splx(s);
845 			return;
846 		}
847 		IF_ENQUEUE(ifq, m);
848 		IFDEBUG(D_EON)
849 			printf(
850 	"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
851 				m, m->m_len, m->m_type, m->m_data);
852 			dump_buf(mtod(m, caddr_t), m->m_len);
853 		ENDDEBUG
854 		schednetisr(NETISR_ISO);
855 		splx(s);
856 	}
857 }
858 
859 int
860 eonctlinput(cmd, sin)
861 	int cmd;
862 	struct sockaddr_in *sin;
863 {
864 	extern u_char inetctlerrmap[];
865 
866 	IFDEBUG(D_EON)
867 		printf("eonctlinput: cmd 0x%x addr: ", cmd);
868 		dump_isoaddr(sin);
869 		printf("\n");
870 	ENDDEBUG
871 
872 	if (cmd < 0 || cmd > PRC_NCMDS)
873 		return 0;
874 
875 	IncStat(es_icmp[cmd]);
876 	switch (cmd) {
877 
878 		case	PRC_QUENCH:
879 		case	PRC_QUENCH2:
880 			/* TODO: set the dec bit */
881 			break;
882 		case	PRC_TIMXCEED_REASS:
883 		case	PRC_ROUTEDEAD:
884 		case	PRC_HOSTUNREACH:
885 		case	PRC_UNREACH_NET:
886 		case	PRC_IFDOWN:
887 		case	PRC_UNREACH_HOST:
888 		case	PRC_HOSTDEAD:
889 		case	PRC_TIMXCEED_INTRANS:
890 			/* TODO: mark the link down */
891 			break;
892 
893 		case	PRC_UNREACH_PROTOCOL:
894 		case	PRC_UNREACH_PORT:
895 		case	PRC_UNREACH_NEEDFRAG:
896 		case	PRC_UNREACH_SRCFAIL:
897 		case	PRC_REDIRECT_NET:
898 		case	PRC_REDIRECT_HOST:
899 		case	PRC_REDIRECT_TOSNET:
900 		case	PRC_REDIRECT_TOSHOST:
901 		case	PRC_MSGSIZE:
902 		case	PRC_PARAMPROB:
903 			printf("eonctlinput: ICMP cmd 0x%x\n", cmd );
904 		break;
905 	}
906 	return 0;
907 }
908 
909 #endif
910