xref: /original-bsd/sys/netiso/if_eon.c (revision 3aaddff2)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_eon.c	7.15 (Berkeley) 05/09/91
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $
38  * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $
39  *
40  *	EON rfc
41  *  Layer between IP and CLNL
42  *
43  * TODO:
44  * Put together a current rfc986 address format and get the right offset
45  * for the nsel
46  */
47 
48 #ifdef EON
49 #define NEON 1
50 
51 
52 #include "param.h"
53 #include "systm.h"
54 #include "types.h"
55 #include "mbuf.h"
56 #include "buf.h"
57 #include "protosw.h"
58 #include "socket.h"
59 #include "ioctl.h"
60 #include "errno.h"
61 #include "types.h"
62 
63 #include "../net/if.h"
64 #include "../net/if_types.h"
65 #include "../net/if_dl.h"
66 #include "../net/netisr.h"
67 #include "../net/route.h"
68 #include "machine/mtpr.h"
69 
70 #include "../netinet/in.h"
71 #include "../netinet/in_systm.h"
72 #include "../netinet/in_var.h"
73 #include "../netinet/ip.h"
74 #include "../netinet/ip_var.h"
75 #include "../netinet/if_ether.h"
76 
77 #include "iso.h"
78 #include "iso_var.h"
79 #include "iso_snpac.h"
80 #include "argo_debug.h"
81 #include "iso_errno.h"
82 #include "eonvar.h"
83 extern struct timeval time;
84 
85 #define EOK 0
86 
87 int						eoninput();
88 int						eonoutput();
89 int						eonioctl();
90 int						eonattach();
91 int						eoninit();
92 int						eonrtrequest();
93 extern 	int				ip_output();
94 struct ifnet			eonif[1];
95 
96 eonprotoinit() {
97 	(void) eonattach();
98 }
99 
100 struct eon_llinfo eon_llinfo;
101 #define PROBE_OK 0;
102 
103 
104 /*
105  * FUNCTION:		eonattach
106  *
107  * PURPOSE:			autoconf attach routine
108  *
109  * RETURNS:			void
110  */
111 
112 eonattach()
113 {
114 	register struct ifnet *ifp = eonif;
115 
116 	IFDEBUG(D_EON)
117 		printf("eonattach()\n");
118 	ENDDEBUG
119 	ifp->if_unit = 0;
120 	ifp->if_name = "eon";
121 	ifp->if_mtu = ETHERMTU;
122 		/* since everything will go out over ether or token ring */
123 
124 	ifp->if_init = eoninit;
125 	ifp->if_ioctl = eonioctl;
126 	ifp->if_output = eonoutput;
127 	ifp->if_type = IFT_EON;
128 	ifp->if_addrlen = 5;
129 	ifp->if_hdrlen = EONIPLEN;
130 	ifp->if_flags = IFF_BROADCAST;
131 	if_attach(ifp);
132 	eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist);
133 	eon_llinfo.el_qhdr.link =
134 		eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr);
135 
136 	IFDEBUG(D_EON)
137 		printf("eonattach()\n");
138 	ENDDEBUG
139 }
140 
141 
142 /*
143  * FUNCTION:		eonioctl
144  *
145  * PURPOSE:			io controls - ifconfig
146  *				need commands to
147  *					link-UP (core addr) (flags: ES, IS)
148  *					link-DOWN (core addr) (flags: ES, IS)
149  *				must be callable from kernel or user
150  *
151  * RETURNS:			nothing
152  */
153 eonioctl(ifp, cmd, data)
154 	register struct ifnet *ifp;
155 	int cmd;
156 	register caddr_t data;
157 {
158 	int s = splimp();
159 	register int error = 0;
160 
161 	IFDEBUG(D_EON)
162 		printf("eonioctl (cmd 0x%x) \n", cmd);
163 	ENDDEBUG
164 
165 	switch (cmd) {
166 		register struct ifaddr *ifa;
167 
168 	case SIOCSIFADDR:
169 		if (ifa = (struct ifaddr *)data) {
170 			ifp->if_flags |= IFF_UP;
171 			if (ifa->ifa_addr->sa_family != AF_LINK)
172 				ifa->ifa_rtrequest = eonrtrequest;
173 			ifa->ifa_llinfolen = sizeof(struct eon_llinfo);
174 		}
175 		break;
176 	}
177 	splx(s);
178 	return(error);
179 }
180 
181 
182 eoniphdr(hdr, loc, ro, class, zero)
183 struct route *ro;
184 register struct eon_iphdr *hdr;
185 caddr_t loc;
186 {
187 	struct mbuf mhead;
188 	extern struct ifnet loif;
189 	register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
190 	if (zero) {
191 		bzero((caddr_t)hdr, sizeof (*hdr));
192 		bzero((caddr_t)ro, sizeof (*ro));
193 	}
194 	sin->sin_family = AF_INET;
195 	sin->sin_len = sizeof (*sin);
196 	bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
197 	/*
198 	 * If there is a cached route,
199 	 * check that it is to the same destination
200 	 * and is still up.  If not, free it and try again.
201 	 */
202 	if (ro->ro_rt) {
203 		struct sockaddr_in *dst =
204 			(struct sockaddr_in *)rt_key(ro->ro_rt);
205 		if ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
206 		   sin->sin_addr.s_addr != dst->sin_addr.s_addr) {
207 			RTFREE(ro->ro_rt);
208 			ro->ro_rt = (struct rtentry *)0;
209 		}
210 	}
211 	rtalloc(ro);
212 	if (ro->ro_rt)
213 		ro->ro_rt->rt_use++;
214 	hdr->ei_ip.ip_dst = sin->sin_addr;
215 	hdr->ei_ip.ip_p = IPPROTO_EON;
216 	hdr->ei_ip.ip_ttl = MAXTTL;
217 	hdr->ei_eh.eonh_class = class;
218 	hdr->ei_eh.eonh_vers = EON_VERSION;
219 	hdr->ei_eh.eonh_csum = 0;
220 	mhead.m_data = (caddr_t) &hdr->ei_eh;
221 	mhead.m_len = sizeof(struct eon_hdr);
222 	mhead.m_next = 0;
223 	IFDEBUG(D_EON)
224 		printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
225 			&mhead,
226 			_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
227 	ENDDEBUG
228 	iso_gen_csum(&mhead,
229 		_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
230 }
231 /*
232  * FUNCTION:		eonrtrequest
233  *
234  * PURPOSE:			maintains list of direct eon recipients.
235  *					sets up IP route for rest.
236  *
237  * RETURNS:			nothing
238  */
239 eonrtrequest(cmd, rt, gate)
240 register struct rtentry *rt;
241 register struct sockaddr *gate;
242 {
243 	unsigned long zerodst = 0;
244 	caddr_t	ipaddrloc = (caddr_t) &zerodst;
245 	register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
246 
247 	/*
248 	 * Common Housekeeping
249 	 */
250 	switch (cmd) {
251 	case RTM_DELETE:
252 		if (el) {
253 			remque(&(el->el_qhdr));
254 			if (el->el_iproute.ro_rt)
255 				RTFREE(el->el_iproute.ro_rt);
256 			Free(el);
257 			rt->rt_llinfo = 0;
258 		}
259 		return;
260 
261 	case RTM_ADD:
262 	case RTM_RESOLVE:
263 		rt->rt_rmx.rmx_mtu = loif.if_mtu; /* unless better below */
264 		R_Malloc(el, struct eon_llinfo *, sizeof(*el));
265 		rt->rt_llinfo = (caddr_t)el;
266 		if (el == 0)
267 			return;
268 		Bzero(el, sizeof(*el));
269 		insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
270 		el->el_rt = rt;
271 		break;
272 	}
273 	if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
274 		case AF_LINK:
275 #define SDL(x) ((struct sockaddr_dl *)x)
276 			if (SDL(gate)->sdl_alen = 1)
277 				el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate));
278 			else
279 				ipaddrloc = LLADDR(SDL(gate));
280 			break;
281 		case AF_INET:
282 #define SIN(x) ((struct sockaddr_in *)x)
283 			ipaddrloc = (caddr_t) &SIN(gate)->sin_addr;
284 			break;
285 		default:
286 			return;
287 	}
288 	el->el_flags |= RTF_UP;
289 	eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0);
290 	if (el->el_iproute.ro_rt)
291 		rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu
292 							- sizeof(el->el_ei);
293 }
294 
295 /*
296  * FUNCTION:		eoninit
297  *
298  * PURPOSE:			initialization
299  *
300  * RETURNS:			nothing
301  */
302 
303 eoninit(unit)
304 	int unit;
305 {
306 	printf("eon driver-init eon%d\n", unit);
307 }
308 
309 
310 /*
311  * FUNCTION:		eonoutput
312  *
313  * PURPOSE:			prepend an eon header and hand to IP
314  * ARGUMENTS:	 	(ifp) is points to the ifnet structure for this unit/device
315  *					(m)  is an mbuf *, *m is a CLNL packet
316  *					(dst) is a destination address - have to interp. as
317  *					multicast or broadcast or real address.
318  *
319  * RETURNS:			unix error code
320  *
321  * NOTES:
322  *
323  */
324 eonoutput(ifp, m, dst, rt)
325 	struct ifnet 	*ifp;
326 	register struct mbuf	*m;		/* packet */
327 	struct sockaddr_iso		*dst;		/* destination addr */
328 	struct rtentry *rt;
329 {
330 	register struct eon_llinfo *el;
331 	register struct eon_iphdr *ei;
332 	struct route *ro;
333 	int	datalen;
334 	struct mbuf *mh;
335 	int	error = 0, class = 0, alen = 0;
336 	caddr_t ipaddrloc;
337 	static struct eon_iphdr eon_iphdr;
338 	static struct route route;
339 
340 	IFDEBUG(D_EON)
341 		printf("eonoutput \n" );
342 	ENDDEBUG
343 
344 	ifp->if_lastchange = time;
345 	ifp->if_opackets++;
346 	if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
347 		if (dst->siso_family == AF_LINK) {
348 			register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
349 
350 			ipaddrloc = LLADDR(sdl);
351 			alen = sdl->sdl_alen;
352 		} else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) {
353 			alen = dst->siso_nlen - 1;
354 			ipaddrloc = (caddr_t) dst->siso_data + 1;
355 		}
356 		switch (alen) {
357 		case 5:
358 			class =  4[(u_char *)ipaddrloc];
359 		case 4:
360 			ro = &route;
361 			ei = &eon_iphdr;
362 			eoniphdr(ei, ipaddrloc, ro, class, 1);
363 			goto send;
364 		}
365 einval:
366 		error =  EINVAL;
367 		goto flush;
368 	}
369 	if ((el->el_flags & RTF_UP) == 0) {
370 		eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
371 		if ((el->el_flags & RTF_UP) == 0) {
372 			error = EHOSTUNREACH;
373 			goto flush;
374 		}
375 	}
376 	if ((m->m_flags & M_PKTHDR) == 0) {
377 		printf("eon: got non headered packet\n");
378 		goto einval;
379 	}
380 	ei = &el->el_ei;
381 	ro = &el->el_iproute;
382 	if (el->el_snpaoffset) {
383 		if (dst->siso_family == AF_ISO) {
384 			bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset],
385 					(caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst));
386 		} else
387 			goto einval;
388 	}
389 send:
390 	/* put an eon_hdr in the buffer, prepended by an ip header */
391 	datalen = m->m_pkthdr.len + EONIPLEN;
392 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
393 	if(mh == (struct mbuf *)0)
394 		goto flush;
395 	mh->m_next = m;
396 	m = mh;
397 	MH_ALIGN(m, sizeof(struct eon_iphdr));
398 	m->m_len = sizeof(struct eon_iphdr);
399 	ifp->if_obytes +=
400 		(ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
401 	*mtod(m, struct eon_iphdr *) = *ei;
402 
403 	IFDEBUG(D_EON)
404 		printf("eonoutput dst ip addr : %x\n",  ei->ei_ip.ip_dst.s_addr);
405 		printf("eonoutput ip_output : eonip header:\n");
406 		dump_buf(ei, sizeof(struct eon_iphdr));
407 	ENDDEBUG
408 
409 	error = ip_output(m, (struct mbuf *)0, ro, 0);
410 	m = 0;
411 	if (error) {
412 		ifp->if_oerrors++;
413 		ifp->if_opackets--;
414 		ifp->if_obytes -= datalen;
415 	}
416 flush:
417 	if (m)
418 		m_freem(m);
419 	return error;
420 }
421 
422 eoninput(m, iphlen)
423 	register struct mbuf	*m;
424 	int iphlen;
425 {
426 	register struct eon_hdr	*eonhdr;
427 	register struct ip		*iphdr;
428 	struct ifnet 			*eonifp;
429 	int						s;
430 
431 	eonifp = &eonif[0]; /* kludge - really want to give CLNP
432 						* the ifp for eon, not for the real device
433 						*/
434 
435 	IFDEBUG(D_EON)
436 		printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
437 			m, m?m->m_data:0, m?m->m_len:0);
438 	ENDDEBUG
439 
440 	if (m == 0)
441 		return;
442 	if (iphlen > sizeof (struct ip))
443 		ip_stripoptions(m, (struct mbuf *)0);
444 	if (m->m_len < EONIPLEN) {
445 		if ((m = m_pullup(m, EONIPLEN)) == 0) {
446 			IncStat(es_badhdr);
447 drop:
448 			IFDEBUG(D_EON)
449 				printf("eoninput: DROP \n" );
450 			ENDDEBUG
451 			eonifp->if_ierrors ++;
452 			m_freem(m);
453 			return;
454 		}
455 	}
456 	eonif->if_ibytes += m->m_pkthdr.len;
457 	eonif->if_lastchange = time;
458 	iphdr = mtod(m, struct ip *);
459 	/* do a few checks for debugging */
460 	if( iphdr->ip_p != IPPROTO_EON ) {
461 		IncStat(es_badhdr);
462 		goto drop;
463 	}
464 	/* temporarily drop ip header from the mbuf */
465 	m->m_data += sizeof(struct ip);
466 	eonhdr = mtod(m, struct eon_hdr *);
467 	if( iso_check_csum( m, sizeof(struct eon_hdr) )   != EOK ) {
468 		IncStat(es_badcsum);
469 		goto drop;
470 	}
471 	m->m_data -= sizeof(struct ip);
472 
473 	IFDEBUG(D_EON)
474 		printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
475 		printf("eoninput: eon header:\n");
476 		dump_buf(eonhdr, sizeof(struct eon_hdr));
477 	ENDDEBUG
478 
479 	/* checks for debugging */
480 	if( eonhdr->eonh_vers != EON_VERSION) {
481 		IncStat(es_badhdr);
482 		goto drop;
483 	}
484 	m->m_flags &= ~(M_BCAST|M_MCAST);
485 	switch( eonhdr->eonh_class) {
486 		case EON_BROADCAST:
487 			IncStat(es_in_broad);
488 			m->m_flags |= M_BCAST;
489 			break;
490 		case EON_NORMAL_ADDR:
491 			IncStat(es_in_normal);
492 			break;
493 		case EON_MULTICAST_ES:
494 			IncStat(es_in_multi_es);
495 			m->m_flags |= M_MCAST;
496 			break;
497 		case EON_MULTICAST_IS:
498 			IncStat(es_in_multi_is);
499 			m->m_flags |= M_MCAST;
500 			break;
501 	}
502 	eonifp->if_ipackets++;
503 
504 	{
505 		/* put it on the CLNP queue and set soft interrupt */
506 		struct ifqueue 			*ifq;
507 		extern struct ifqueue 	clnlintrq;
508 
509 		m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
510 		IFDEBUG(D_EON)
511 			printf("eoninput to clnl IFQ\n");
512 		ENDDEBUG
513 		ifq = &clnlintrq;
514 		s = splimp();
515 		if (IF_QFULL(ifq)) {
516 			IF_DROP(ifq);
517 			m_freem(m);
518 			eonifp->if_iqdrops++;
519 			eonifp->if_ipackets--;
520 			splx(s);
521 			return;
522 		}
523 		IF_ENQUEUE(ifq, m);
524 		IFDEBUG(D_EON)
525 			printf(
526 	"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
527 				m, m->m_len, m->m_type, m->m_data);
528 			dump_buf(mtod(m, caddr_t), m->m_len);
529 		ENDDEBUG
530 		schednetisr(NETISR_ISO);
531 		splx(s);
532 	}
533 }
534 
535 int
536 eonctlinput(cmd, sin)
537 	int cmd;
538 	struct sockaddr_in *sin;
539 {
540 	extern u_char inetctlerrmap[];
541 
542 	IFDEBUG(D_EON)
543 		printf("eonctlinput: cmd 0x%x addr: ", cmd);
544 		dump_isoaddr(sin);
545 		printf("\n");
546 	ENDDEBUG
547 
548 	if (cmd < 0 || cmd > PRC_NCMDS)
549 		return 0;
550 
551 	IncStat(es_icmp[cmd]);
552 	switch (cmd) {
553 
554 		case	PRC_QUENCH:
555 		case	PRC_QUENCH2:
556 			/* TODO: set the dec bit */
557 			break;
558 		case	PRC_TIMXCEED_REASS:
559 		case	PRC_ROUTEDEAD:
560 		case	PRC_HOSTUNREACH:
561 		case	PRC_UNREACH_NET:
562 		case	PRC_IFDOWN:
563 		case	PRC_UNREACH_HOST:
564 		case	PRC_HOSTDEAD:
565 		case	PRC_TIMXCEED_INTRANS:
566 			/* TODO: mark the link down */
567 			break;
568 
569 		case	PRC_UNREACH_PROTOCOL:
570 		case	PRC_UNREACH_PORT:
571 		case	PRC_UNREACH_SRCFAIL:
572 		case	PRC_REDIRECT_NET:
573 		case	PRC_REDIRECT_HOST:
574 		case	PRC_REDIRECT_TOSNET:
575 		case	PRC_REDIRECT_TOSHOST:
576 		case	PRC_MSGSIZE:
577 		case	PRC_PARAMPROB:
578 			/* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/
579 		break;
580 	}
581 	return 0;
582 }
583 
584 #endif
585