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