xref: /csrg-svn/sys/netiso/if_eon.c (revision 40778)
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.6 (Berkeley) 04/05/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 
165 	case SIOCSIFADDR:
166 		if (ifa = (struct ifaddr *)data) {
167 			ifp->if_flags |= IFF_UP;
168 			ifa->ifa_rtrequest = eonrtrequest;
169 			ifa->ifa_llinfolen = sizeof(struct eon_llinfo);
170 	    }
171 		break;
172 	}
173 	splx(s);
174 	return(error);
175 }
176 
177 
178 eoniphdr(hdr, loc, ro, class, zero)
179 struct route *ro;
180 register struct eon_iphdr *hdr;
181 caddr_t loc;
182 {
183 	struct mbuf mhead;
184 	register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
185 	if (zero) {
186 		bzero((caddr_t)hdr, sizeof (*hdr));
187 		bzero((caddr_t)ro, sizeof (*ro));
188 	}
189 	sin->sin_family = AF_INET;
190 	sin->sin_len = sizeof (*sin);
191 	bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
192 	hdr->ei_ip.ip_dst = sin->sin_addr;
193 	hdr->ei_ip.ip_p = IPPROTO_EON;
194 	hdr->ei_ip.ip_ttl = MAXTTL;
195 	hdr->ei_eh.eonh_class = class;
196 	hdr->ei_eh.eonh_vers = EON_VERSION;
197 	hdr->ei_eh.eonh_csum = 0;
198 	mhead.m_data = (caddr_t) &hdr->ei_eh;
199 	mhead.m_len = sizeof(struct eon_hdr);
200 	mhead.m_next = 0;
201 	IFDEBUG(D_EON)
202 		printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
203 			&mhead,
204 			_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
205 	ENDDEBUG
206 	iso_gen_csum(&mhead,
207 		_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
208 }
209 /*
210  * FUNCTION:		eonrtrequest
211  *
212  * PURPOSE:			maintains list of direct eon recipients.
213  *					sets up IP route for rest.
214  *
215  * RETURNS:			nothing
216  */
217 eonrtrequest(cmd, rt, gate)
218 register struct rtentry *rt;
219 struct sockaddr *gate;
220 {
221 	caddr_t	ipaddrloc = 0;
222 	register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
223 	register struct rtentry *iprt;
224 	register struct sockaddr_in sin;
225 
226 	if (el == 0)
227 		panic("eonrtrequest");
228 	iprt = el->el_iproute.ro_rt;
229 	/*
230 	 * Common Housekeeping
231 	 */
232 	switch (cmd) {
233 
234 	case RTM_ADD:
235 		insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
236 		el->el_rt = rt;
237 		break;
238 
239 	case RTM_DELETE:
240 		remque(&(el->el_qhdr));
241 		/* FALLTHROUGH */
242 	case RTM_CHANGE:
243 		el->el_flags &= ~RTF_UP;
244 		if (iprt)
245 			RTFREE(iprt);
246 		if (cmd = RTM_DELETE)
247 			return;
248 	}
249 	if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
250 		case AF_LINK:
251 			ipaddrloc = LLADDR((struct sockaddr_dl *)gate);
252 			break;
253 		case AF_INET:
254 			ipaddrloc = (caddr_t) &((struct sockaddr_in *)gate)->sin_addr;
255 			break;
256 		default:
257 			return;
258 	}
259 	el->el_flags |= RTF_UP;
260 	eoniphdr(&el->el_ei, &el->el_iproute, ipaddrloc, EON_NORMAL_ADDR, 0);
261 }
262 
263 /*
264  * FUNCTION:		eoninit
265  *
266  * PURPOSE:			initialization
267  *
268  * RETURNS:			nothing
269  */
270 
271 eoninit(unit)
272 	int unit;
273 {
274 	printf("eon driver-init eon%d\n", unit);
275 }
276 
277 
278 /*
279  * FUNCTION:		eonoutput
280  *
281  * PURPOSE:			prepend an eon header and hand to IP
282  * ARGUMENTS:	 	(ifp) is points to the ifnet structure for this unit/device
283  *					(m)  is an mbuf *, *m is a CLNL packet
284  *					(dst) is a destination address - have to interp. as
285  *					multicast or broadcast or real address.
286  *
287  * RETURNS:			unix error code
288  *
289  * NOTES:
290  *
291  */
292 eonoutput(ifp, m, dst, rt)
293 	struct ifnet 	*ifp;
294 	register struct mbuf	*m;		/* packet */
295 	struct sockaddr_iso		*dst;		/* destination addr */
296 	struct rtentry *rt;
297 {
298 	register struct eon_llinfo *el;
299 	register struct eon_iphdr *ei;
300 	struct route *ro;
301 	int	datalen;
302 	struct mbuf *mh;
303 	int	error = 0;
304 	caddr_t ippaddrloc;
305 	static struct eon_iphdr eon_iphdr;
306 	static struct route route;
307 
308 	IFDEBUG(D_EON)
309 		printf("eonoutput \n" );
310 	ENDDEBUG
311 
312 	ifp->if_lastchange = time;
313 	ifp->if_opackets++;
314 	if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
315 		if (dst->siso_family == AF_LINK) {
316 			register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
317 			caddr_t ipaddrloc = LLADDR(sdl);
318 			int class = (sdl->sdl_alen == 5) ? 4[(u_char *)ipaddrloc] : 0;
319 
320 			if (sdl->sdl_alen == 4 || sdl->sdl_alen == 5) {
321 				ipaddrloc = LLADDR(sdl);
322 				ro = &route;
323 				ei = &eon_iphdr;
324 				eoniphdr(ei, ipaddrloc, ro, class, 1);
325 				goto send;
326 			}
327 		}
328 einval:
329 		error =  EINVAL;
330 		goto flush;
331 	}
332 	if ((el->el_flags & RTF_UP) == 0) {
333 		eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
334 		if ((el->el_flags & RTF_UP) == 0) {
335 			error = EHOSTUNREACH;
336 			goto flush;
337 		}
338 	}
339 	if ((m->m_flags & M_PKTHDR) == 0) {
340 		printf("eon: got non headered packet\n");
341 		goto einval;
342 	}
343 	ei = &el->el_ei;
344 	ro = &el->el_iproute;
345 send:
346 	/* put an eon_hdr in the buffer, prepended by an ip header */
347 	datalen = m->m_pkthdr.len + EONIPLEN;
348 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
349 	if(mh == (struct mbuf *)0)
350 		goto flush;
351 	mh->m_next = m;
352 	m = mh;
353 	MH_ALIGN(m, sizeof(struct eon_iphdr));
354 	m->m_len = sizeof(struct eon_iphdr);
355 	ifp->if_obytes +=
356 		(ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
357 	*mtod(m, struct eon_iphdr *) = *ei;
358 
359 	IFDEBUG(D_EON)
360 		printf("eonoutput dst ip addr : %x\n",  ei->ei_ip.ip_dst.s_addr);
361 		printf("eonoutput ip_output : eonip header:\n");
362 		dump_buf(ei, sizeof(struct eon_iphdr));
363 	ENDDEBUG
364 
365 	error = ip_output(m, (struct mbuf *)0, ro, 0);
366 	m = 0;
367 	if (error) {
368 		ifp->if_oerrors++;
369 		ifp->if_opackets--;
370 		ifp->if_obytes -= datalen;
371 	}
372 flush:
373 	if (m)
374 		m_freem(m);
375 	return error;
376 }
377 
378 eoninput(m, iphlen)
379 	register struct mbuf	*m;
380 	int iphlen;
381 {
382 	register struct eon_hdr	*eonhdr;
383 	register struct ip		*iphdr;
384 	struct ifnet 			*eonifp;
385 	int						s;
386 
387 	eonifp = &eonif[0]; /* kludge - really want to give CLNP
388 						* the ifp for eon, not for the real device
389 						*/
390 
391 	IFDEBUG(D_EON)
392 		printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
393 			m, m?m->m_data:0, m?m->m_len:0);
394 	ENDDEBUG
395 
396 	if (m == 0)
397 		return;
398 	if (iphlen > sizeof (struct ip))
399 		ip_stripoptions(m, (struct mbuf *)0);
400 	if (m->m_len < EONIPLEN) {
401 		if ((m = m_pullup(m, EONIPLEN)) == 0) {
402 			IncStat(es_badhdr);
403 drop:
404 			IFDEBUG(D_EON)
405 				printf("eoninput: DROP \n" );
406 			ENDDEBUG
407 			eonifp->if_ierrors ++;
408 			m_freem(m);
409 			return;
410 		}
411 	}
412 	eonif->if_ibytes += m->m_pkthdr.len;
413 	eonif->if_lastchange = time;
414 	iphdr = mtod(m, struct ip *);
415 	/* do a few checks for debugging */
416 	if( iphdr->ip_p != IPPROTO_EON ) {
417 		IncStat(es_badhdr);
418 		goto drop;
419 	}
420 	/* temporarily drop ip header from the mbuf */
421 	m->m_data += sizeof(struct ip);
422 	eonhdr = mtod(m, struct eon_hdr *);
423 	if( iso_check_csum( m, sizeof(struct eon_hdr) )   != EOK ) {
424 		IncStat(es_badcsum);
425 		goto drop;
426 	}
427 	m->m_data -= sizeof(struct ip);
428 
429 	IFDEBUG(D_EON)
430 		printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
431 		printf("eoninput: eon header:\n");
432 		dump_buf(eonhdr, sizeof(struct eon_hdr));
433 	ENDDEBUG
434 
435 	/* checks for debugging */
436 	if( eonhdr->eonh_vers != EON_VERSION) {
437 		IncStat(es_badhdr);
438 		goto drop;
439 	}
440 	m->m_flags &= ~(M_BCAST|M_MCAST);
441 	switch( eonhdr->eonh_class) {
442 		case EON_BROADCAST:
443 			IncStat(es_in_broad);
444 			m->m_flags |= M_BCAST;
445 			break;
446 		case EON_NORMAL_ADDR:
447 			IncStat(es_in_normal);
448 			break;
449 		case EON_MULTICAST_ES:
450 			IncStat(es_in_multi_es);
451 			m->m_flags |= M_MCAST;
452 			break;
453 		case EON_MULTICAST_IS:
454 			IncStat(es_in_multi_is);
455 			m->m_flags |= M_MCAST;
456 			break;
457 	}
458 	eonifp->if_ipackets++;
459 
460 	{
461 		/* put it on the CLNP queue and set soft interrupt */
462 		struct ifqueue 			*ifq;
463 		extern struct ifqueue 	clnlintrq;
464 
465 		m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
466 		IFDEBUG(D_EON)
467 			printf("eoninput to clnl IFQ\n");
468 		ENDDEBUG
469 		ifq = &clnlintrq;
470 		s = splimp();
471 		if (IF_QFULL(ifq)) {
472 			IF_DROP(ifq);
473 			m_freem(m);
474 			eonifp->if_iqdrops++;
475 			eonifp->if_ipackets--;
476 			splx(s);
477 			return;
478 		}
479 		IF_ENQUEUE(ifq, m);
480 		IFDEBUG(D_EON)
481 			printf(
482 	"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
483 				m, m->m_len, m->m_type, m->m_data);
484 			dump_buf(mtod(m, caddr_t), m->m_len);
485 		ENDDEBUG
486 		schednetisr(NETISR_ISO);
487 		splx(s);
488 	}
489 }
490 
491 int
492 eonctlinput(cmd, sin)
493 	int cmd;
494 	struct sockaddr_in *sin;
495 {
496 	extern u_char inetctlerrmap[];
497 
498 	IFDEBUG(D_EON)
499 		printf("eonctlinput: cmd 0x%x addr: ", cmd);
500 		dump_isoaddr(sin);
501 		printf("\n");
502 	ENDDEBUG
503 
504 	if (cmd < 0 || cmd > PRC_NCMDS)
505 		return 0;
506 
507 	IncStat(es_icmp[cmd]);
508 	switch (cmd) {
509 
510 		case	PRC_QUENCH:
511 		case	PRC_QUENCH2:
512 			/* TODO: set the dec bit */
513 			break;
514 		case	PRC_TIMXCEED_REASS:
515 		case	PRC_ROUTEDEAD:
516 		case	PRC_HOSTUNREACH:
517 		case	PRC_UNREACH_NET:
518 		case	PRC_IFDOWN:
519 		case	PRC_UNREACH_HOST:
520 		case	PRC_HOSTDEAD:
521 		case	PRC_TIMXCEED_INTRANS:
522 			/* TODO: mark the link down */
523 			break;
524 
525 		case	PRC_UNREACH_PROTOCOL:
526 		case	PRC_UNREACH_PORT:
527 		case	PRC_UNREACH_SRCFAIL:
528 		case	PRC_REDIRECT_NET:
529 		case	PRC_REDIRECT_HOST:
530 		case	PRC_REDIRECT_TOSNET:
531 		case	PRC_REDIRECT_TOSHOST:
532 		case	PRC_MSGSIZE:
533 		case	PRC_PARAMPROB:
534 			printf("eonctlinput: ICMP cmd 0x%x\n", cmd );
535 		break;
536 	}
537 	return 0;
538 }
539 
540 #endif
541