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