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