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