xref: /csrg-svn/sys/netiso/if_eon.c (revision 41926)
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.8 (Berkeley) 05/14/90 *
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/if_dl.h"
62 #include "../net/netisr.h"
63 #include "../net/route.h"
64 #include "machine/mtpr.h"
65 
66 #include "../netinet/in.h"
67 #include "../netinet/in_systm.h"
68 #include "../netinet/in_var.h"
69 #include "../netinet/ip.h"
70 #include "../netinet/ip_var.h"
71 #include "../netinet/if_ether.h"
72 
73 #include "iso.h"
74 #include "iso_var.h"
75 #include "iso_snpac.h"
76 extern struct snpa_cache all_es, all_is;
77 #include "argo_debug.h"
78 #include "iso_errno.h"
79 #include "eonvar.h"
80 extern struct timeval time;
81 
82 #define EOK 0
83 
84 int						eoninput();
85 int						eonoutput();
86 int						eonioctl();
87 int						eonattach();
88 int						eoninit();
89 int						eonrtrequest();
90 extern 	int				ip_output();
91 struct ifnet			eonif[1];
92 
93 eonprotoinit() {
94 	(void) eonattach();
95 }
96 
97 struct eon_llinfo eon_llinfo;
98 #define PROBE_OK 0;
99 
100 
101 /*
102  * FUNCTION:		eonattach
103  *
104  * PURPOSE:			autoconf attach routine
105  *
106  * RETURNS:			void
107  */
108 
109 eonattach()
110 {
111 	register struct ifnet *ifp = eonif;
112 
113 	IFDEBUG(D_EON)
114 		printf("eonattach()\n");
115 	ENDDEBUG
116 	ifp->if_unit = 0;
117 	ifp->if_name = "eon";
118 	ifp->if_mtu = ETHERMTU;
119 		/* since everything will go out over ether or token ring */
120 
121 	ifp->if_init = eoninit;
122 	ifp->if_ioctl = eonioctl;
123 	ifp->if_output = eonoutput;
124 	ifp->if_type = IFT_EON;
125 	ifp->if_addrlen = 5;
126 	ifp->if_hdrlen = EONIPLEN;
127 	ifp->if_flags = IFF_BROADCAST;
128 	if_attach(ifp);
129 	eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist);
130 	eon_llinfo.el_qhdr.link =
131 		eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr);
132 
133 	IFDEBUG(D_EON)
134 		printf("eonattach()\n");
135 	ENDDEBUG
136 }
137 
138 
139 /*
140  * FUNCTION:		eonioctl
141  *
142  * PURPOSE:			io controls - ifconfig
143  *				need commands to
144  *					link-UP (core addr) (flags: ES, IS)
145  *					link-DOWN (core addr) (flags: ES, IS)
146  *				must be callable from kernel or user
147  *
148  * RETURNS:			nothing
149  */
150 eonioctl(ifp, cmd, data)
151 	register struct ifnet *ifp;
152 	int cmd;
153 	register caddr_t data;
154 {
155 	int s = splimp();
156 	register int error = 0;
157 
158 	IFDEBUG(D_EON)
159 		printf("eonioctl (cmd 0x%x) \n", cmd);
160 	ENDDEBUG
161 
162 	switch (cmd) {
163 		register struct ifaddr *ifa;
164 		extern link_rtrequest();
165 
166 	case SIOCSIFADDR:
167 		if (ifa = (struct ifaddr *)data) {
168 			ifp->if_flags |= IFF_UP;
169 			if (ifa->ifa_addr->sa_family != AF_LINK)
170 				ifa->ifa_rtrequest = eonrtrequest;
171 			ifa->ifa_llinfolen = sizeof(struct eon_llinfo);
172 		}
173 		break;
174 	}
175 	splx(s);
176 	return(error);
177 }
178 
179 
180 eoniphdr(hdr, loc, ro, class, zero)
181 struct route *ro;
182 register struct eon_iphdr *hdr;
183 caddr_t loc;
184 {
185 	struct mbuf mhead;
186 	register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
187 	if (zero) {
188 		bzero((caddr_t)hdr, sizeof (*hdr));
189 		bzero((caddr_t)ro, sizeof (*ro));
190 	}
191 	sin->sin_family = AF_INET;
192 	sin->sin_len = sizeof (*sin);
193 	bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
194 	hdr->ei_ip.ip_dst = sin->sin_addr;
195 	hdr->ei_ip.ip_p = IPPROTO_EON;
196 	hdr->ei_ip.ip_ttl = MAXTTL;
197 	hdr->ei_eh.eonh_class = class;
198 	hdr->ei_eh.eonh_vers = EON_VERSION;
199 	hdr->ei_eh.eonh_csum = 0;
200 	mhead.m_data = (caddr_t) &hdr->ei_eh;
201 	mhead.m_len = sizeof(struct eon_hdr);
202 	mhead.m_next = 0;
203 	IFDEBUG(D_EON)
204 		printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
205 			&mhead,
206 			_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
207 	ENDDEBUG
208 	iso_gen_csum(&mhead,
209 		_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
210 }
211 /*
212  * FUNCTION:		eonrtrequest
213  *
214  * PURPOSE:			maintains list of direct eon recipients.
215  *					sets up IP route for rest.
216  *
217  * RETURNS:			nothing
218  */
219 eonrtrequest(cmd, rt, gate)
220 register struct rtentry *rt;
221 struct sockaddr *gate;
222 {
223 	caddr_t	ipaddrloc = 0;
224 	register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
225 	register struct rtentry *iprt;
226 	register struct sockaddr_in sin;
227 
228 	if (el == 0)
229 		panic("eonrtrequest");
230 	iprt = el->el_iproute.ro_rt;
231 	/*
232 	 * Common Housekeeping
233 	 */
234 	switch (cmd) {
235 
236 	case RTM_ADD:
237 		insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
238 		el->el_rt = rt;
239 		break;
240 
241 	case RTM_DELETE:
242 		remque(&(el->el_qhdr));
243 		/* FALLTHROUGH */
244 	case RTM_CHANGE:
245 		el->el_flags &= ~RTF_UP;
246 		if (iprt)
247 			RTFREE(iprt);
248 		if (cmd = RTM_DELETE)
249 			return;
250 	}
251 	if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
252 		case AF_LINK:
253 			ipaddrloc = LLADDR((struct sockaddr_dl *)gate);
254 			break;
255 		case AF_INET:
256 			ipaddrloc = (caddr_t) &((struct sockaddr_in *)gate)->sin_addr;
257 			break;
258 		default:
259 			return;
260 	}
261 	el->el_flags |= RTF_UP;
262 	eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0);
263 }
264 
265 /*
266  * FUNCTION:		eoninit
267  *
268  * PURPOSE:			initialization
269  *
270  * RETURNS:			nothing
271  */
272 
273 eoninit(unit)
274 	int unit;
275 {
276 	printf("eon driver-init eon%d\n", unit);
277 }
278 
279 
280 /*
281  * FUNCTION:		eonoutput
282  *
283  * PURPOSE:			prepend an eon header and hand to IP
284  * ARGUMENTS:	 	(ifp) is points to the ifnet structure for this unit/device
285  *					(m)  is an mbuf *, *m is a CLNL packet
286  *					(dst) is a destination address - have to interp. as
287  *					multicast or broadcast or real address.
288  *
289  * RETURNS:			unix error code
290  *
291  * NOTES:
292  *
293  */
294 eonoutput(ifp, m, dst, rt)
295 	struct ifnet 	*ifp;
296 	register struct mbuf	*m;		/* packet */
297 	struct sockaddr_iso		*dst;		/* destination addr */
298 	struct rtentry *rt;
299 {
300 	register struct eon_llinfo *el;
301 	register struct eon_iphdr *ei;
302 	struct route *ro;
303 	int	datalen;
304 	struct mbuf *mh;
305 	int	error = 0;
306 	caddr_t ippaddrloc;
307 	static struct eon_iphdr eon_iphdr;
308 	static struct route route;
309 
310 	IFDEBUG(D_EON)
311 		printf("eonoutput \n" );
312 	ENDDEBUG
313 
314 	ifp->if_lastchange = time;
315 	ifp->if_opackets++;
316 	if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
317 		if (dst->siso_family == AF_LINK) {
318 			register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
319 			caddr_t ipaddrloc = LLADDR(sdl);
320 			int class = (sdl->sdl_alen == 5) ? 4[(u_char *)ipaddrloc] : 0;
321 
322 			if (sdl->sdl_alen == 4 || sdl->sdl_alen == 5) {
323 				ipaddrloc = LLADDR(sdl);
324 				ro = &route;
325 				ei = &eon_iphdr;
326 				eoniphdr(ei, ipaddrloc, ro, class, 1);
327 				goto send;
328 			}
329 		}
330 einval:
331 		error =  EINVAL;
332 		goto flush;
333 	}
334 	if ((el->el_flags & RTF_UP) == 0) {
335 		eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
336 		if ((el->el_flags & RTF_UP) == 0) {
337 			error = EHOSTUNREACH;
338 			goto flush;
339 		}
340 	}
341 	if ((m->m_flags & M_PKTHDR) == 0) {
342 		printf("eon: got non headered packet\n");
343 		goto einval;
344 	}
345 	ei = &el->el_ei;
346 	ro = &el->el_iproute;
347 send:
348 	/* put an eon_hdr in the buffer, prepended by an ip header */
349 	datalen = m->m_pkthdr.len + EONIPLEN;
350 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
351 	if(mh == (struct mbuf *)0)
352 		goto flush;
353 	mh->m_next = m;
354 	m = mh;
355 	MH_ALIGN(m, sizeof(struct eon_iphdr));
356 	m->m_len = sizeof(struct eon_iphdr);
357 	ifp->if_obytes +=
358 		(ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
359 	*mtod(m, struct eon_iphdr *) = *ei;
360 
361 	IFDEBUG(D_EON)
362 		printf("eonoutput dst ip addr : %x\n",  ei->ei_ip.ip_dst.s_addr);
363 		printf("eonoutput ip_output : eonip header:\n");
364 		dump_buf(ei, sizeof(struct eon_iphdr));
365 	ENDDEBUG
366 
367 	error = ip_output(m, (struct mbuf *)0, ro, 0);
368 	m = 0;
369 	if (error) {
370 		ifp->if_oerrors++;
371 		ifp->if_opackets--;
372 		ifp->if_obytes -= datalen;
373 	}
374 flush:
375 	if (m)
376 		m_freem(m);
377 	return error;
378 }
379 
380 eoninput(m, iphlen)
381 	register struct mbuf	*m;
382 	int iphlen;
383 {
384 	register struct eon_hdr	*eonhdr;
385 	register struct ip		*iphdr;
386 	struct ifnet 			*eonifp;
387 	int						s;
388 
389 	eonifp = &eonif[0]; /* kludge - really want to give CLNP
390 						* the ifp for eon, not for the real device
391 						*/
392 
393 	IFDEBUG(D_EON)
394 		printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
395 			m, m?m->m_data:0, m?m->m_len:0);
396 	ENDDEBUG
397 
398 	if (m == 0)
399 		return;
400 	if (iphlen > sizeof (struct ip))
401 		ip_stripoptions(m, (struct mbuf *)0);
402 	if (m->m_len < EONIPLEN) {
403 		if ((m = m_pullup(m, EONIPLEN)) == 0) {
404 			IncStat(es_badhdr);
405 drop:
406 			IFDEBUG(D_EON)
407 				printf("eoninput: DROP \n" );
408 			ENDDEBUG
409 			eonifp->if_ierrors ++;
410 			m_freem(m);
411 			return;
412 		}
413 	}
414 	eonif->if_ibytes += m->m_pkthdr.len;
415 	eonif->if_lastchange = time;
416 	iphdr = mtod(m, struct ip *);
417 	/* do a few checks for debugging */
418 	if( iphdr->ip_p != IPPROTO_EON ) {
419 		IncStat(es_badhdr);
420 		goto drop;
421 	}
422 	/* temporarily drop ip header from the mbuf */
423 	m->m_data += sizeof(struct ip);
424 	eonhdr = mtod(m, struct eon_hdr *);
425 	if( iso_check_csum( m, sizeof(struct eon_hdr) )   != EOK ) {
426 		IncStat(es_badcsum);
427 		goto drop;
428 	}
429 	m->m_data -= sizeof(struct ip);
430 
431 	IFDEBUG(D_EON)
432 		printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
433 		printf("eoninput: eon header:\n");
434 		dump_buf(eonhdr, sizeof(struct eon_hdr));
435 	ENDDEBUG
436 
437 	/* checks for debugging */
438 	if( eonhdr->eonh_vers != EON_VERSION) {
439 		IncStat(es_badhdr);
440 		goto drop;
441 	}
442 	m->m_flags &= ~(M_BCAST|M_MCAST);
443 	switch( eonhdr->eonh_class) {
444 		case EON_BROADCAST:
445 			IncStat(es_in_broad);
446 			m->m_flags |= M_BCAST;
447 			break;
448 		case EON_NORMAL_ADDR:
449 			IncStat(es_in_normal);
450 			break;
451 		case EON_MULTICAST_ES:
452 			IncStat(es_in_multi_es);
453 			m->m_flags |= M_MCAST;
454 			break;
455 		case EON_MULTICAST_IS:
456 			IncStat(es_in_multi_is);
457 			m->m_flags |= M_MCAST;
458 			break;
459 	}
460 	eonifp->if_ipackets++;
461 
462 	{
463 		/* put it on the CLNP queue and set soft interrupt */
464 		struct ifqueue 			*ifq;
465 		extern struct ifqueue 	clnlintrq;
466 
467 		m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
468 		IFDEBUG(D_EON)
469 			printf("eoninput to clnl IFQ\n");
470 		ENDDEBUG
471 		ifq = &clnlintrq;
472 		s = splimp();
473 		if (IF_QFULL(ifq)) {
474 			IF_DROP(ifq);
475 			m_freem(m);
476 			eonifp->if_iqdrops++;
477 			eonifp->if_ipackets--;
478 			splx(s);
479 			return;
480 		}
481 		IF_ENQUEUE(ifq, m);
482 		IFDEBUG(D_EON)
483 			printf(
484 	"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
485 				m, m->m_len, m->m_type, m->m_data);
486 			dump_buf(mtod(m, caddr_t), m->m_len);
487 		ENDDEBUG
488 		schednetisr(NETISR_ISO);
489 		splx(s);
490 	}
491 }
492 
493 int
494 eonctlinput(cmd, sin)
495 	int cmd;
496 	struct sockaddr_in *sin;
497 {
498 	extern u_char inetctlerrmap[];
499 
500 	IFDEBUG(D_EON)
501 		printf("eonctlinput: cmd 0x%x addr: ", cmd);
502 		dump_isoaddr(sin);
503 		printf("\n");
504 	ENDDEBUG
505 
506 	if (cmd < 0 || cmd > PRC_NCMDS)
507 		return 0;
508 
509 	IncStat(es_icmp[cmd]);
510 	switch (cmd) {
511 
512 		case	PRC_QUENCH:
513 		case	PRC_QUENCH2:
514 			/* TODO: set the dec bit */
515 			break;
516 		case	PRC_TIMXCEED_REASS:
517 		case	PRC_ROUTEDEAD:
518 		case	PRC_HOSTUNREACH:
519 		case	PRC_UNREACH_NET:
520 		case	PRC_IFDOWN:
521 		case	PRC_UNREACH_HOST:
522 		case	PRC_HOSTDEAD:
523 		case	PRC_TIMXCEED_INTRANS:
524 			/* TODO: mark the link down */
525 			break;
526 
527 		case	PRC_UNREACH_PROTOCOL:
528 		case	PRC_UNREACH_PORT:
529 		case	PRC_UNREACH_SRCFAIL:
530 		case	PRC_REDIRECT_NET:
531 		case	PRC_REDIRECT_HOST:
532 		case	PRC_REDIRECT_TOSNET:
533 		case	PRC_REDIRECT_TOSHOST:
534 		case	PRC_MSGSIZE:
535 		case	PRC_PARAMPROB:
536 			printf("eonctlinput: ICMP cmd 0x%x\n", cmd );
537 		break;
538 	}
539 	return 0;
540 }
541 
542 #endif
543