xref: /original-bsd/sys/netiso/if_eon.c (revision 4092c5cc)
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.21 (Berkeley) 06/05/93
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 <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/mbuf.h>
55 #include <sys/buf.h>
56 #include <sys/protosw.h>
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
59 #include <sys/errno.h>
60 #include <sys/types.h>
61 
62 #include <net/if.h>
63 #include <net/if_types.h>
64 #include <net/if_dl.h>
65 #include <net/netisr.h>
66 #include <net/route.h>
67 #include <machine/mtpr.h>
68 
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/in_var.h>
72 #include <netinet/ip.h>
73 #include <netinet/ip_var.h>
74 #include <netinet/if_ether.h>
75 
76 #include <netiso/iso.h>
77 #include <netiso/iso_var.h>
78 #include <netiso/iso_snpac.h>
79 #include <netiso/argo_debug.h>
80 #include <netiso/iso_errno.h>
81 #include <netiso/eonvar.h>
82 
83 extern struct timeval time;
84 extern struct ifnet loif;
85 
86 #define EOK 0
87 
88 int						eoninput();
89 int						eonoutput();
90 int						eonioctl();
91 int						eonattach();
92 int						eoninit();
93 void						eonrtrequest();
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 		}
174 		break;
175 	}
176 	splx(s);
177 	return(error);
178 }
179 
180 
181 eoniphdr(hdr, loc, ro, class, zero)
182 struct route *ro;
183 register struct eon_iphdr *hdr;
184 caddr_t loc;
185 {
186 	struct mbuf mhead;
187 	register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
188 	if (zero) {
189 		bzero((caddr_t)hdr, sizeof (*hdr));
190 		bzero((caddr_t)ro, sizeof (*ro));
191 	}
192 	sin->sin_family = AF_INET;
193 	sin->sin_len = sizeof (*sin);
194 	bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
195 	/*
196 	 * If there is a cached route,
197 	 * check that it is to the same destination
198 	 * and is still up.  If not, free it and try again.
199 	 */
200 	if (ro->ro_rt) {
201 		struct sockaddr_in *dst =
202 			(struct sockaddr_in *)rt_key(ro->ro_rt);
203 		if ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
204 		   sin->sin_addr.s_addr != dst->sin_addr.s_addr) {
205 			RTFREE(ro->ro_rt);
206 			ro->ro_rt = (struct rtentry *)0;
207 		}
208 	}
209 	rtalloc(ro);
210 	if (ro->ro_rt)
211 		ro->ro_rt->rt_use++;
212 	hdr->ei_ip.ip_dst = sin->sin_addr;
213 	hdr->ei_ip.ip_p = IPPROTO_EON;
214 	hdr->ei_ip.ip_ttl = MAXTTL;
215 	hdr->ei_eh.eonh_class = class;
216 	hdr->ei_eh.eonh_vers = EON_VERSION;
217 	hdr->ei_eh.eonh_csum = 0;
218 	mhead.m_data = (caddr_t) &hdr->ei_eh;
219 	mhead.m_len = sizeof(struct eon_hdr);
220 	mhead.m_next = 0;
221 	IFDEBUG(D_EON)
222 		printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
223 			&mhead,
224 			_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
225 	ENDDEBUG
226 	iso_gen_csum(&mhead,
227 		_offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
228 }
229 /*
230  * FUNCTION:		eonrtrequest
231  *
232  * PURPOSE:			maintains list of direct eon recipients.
233  *					sets up IP route for rest.
234  *
235  * RETURNS:			nothing
236  */
237 void
238 eonrtrequest(cmd, rt, gate)
239 register struct rtentry *rt;
240 register struct sockaddr *gate;
241 {
242 	unsigned long zerodst = 0;
243 	caddr_t	ipaddrloc = (caddr_t) &zerodst;
244 	register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
245 
246 	/*
247 	 * Common Housekeeping
248 	 */
249 	switch (cmd) {
250 	case RTM_DELETE:
251 		if (el) {
252 			remque(&(el->el_qhdr));
253 			if (el->el_iproute.ro_rt)
254 				RTFREE(el->el_iproute.ro_rt);
255 			Free(el);
256 			rt->rt_llinfo = 0;
257 		}
258 		return;
259 
260 	case RTM_ADD:
261 	case RTM_RESOLVE:
262 		rt->rt_rmx.rmx_mtu = loif.if_mtu; /* unless better below */
263 		R_Malloc(el, struct eon_llinfo *, sizeof(*el));
264 		rt->rt_llinfo = (caddr_t)el;
265 		if (el == 0)
266 			return;
267 		Bzero(el, sizeof(*el));
268 		insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
269 		el->el_rt = rt;
270 		break;
271 	}
272 	if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
273 		case AF_LINK:
274 #define SDL(x) ((struct sockaddr_dl *)x)
275 			if (SDL(gate)->sdl_alen == 1)
276 				el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate));
277 			else
278 				ipaddrloc = LLADDR(SDL(gate));
279 			break;
280 		case AF_INET:
281 #define SIN(x) ((struct sockaddr_in *)x)
282 			ipaddrloc = (caddr_t) &SIN(gate)->sin_addr;
283 			break;
284 		default:
285 			return;
286 	}
287 	el->el_flags |= RTF_UP;
288 	eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0);
289 	if (el->el_iproute.ro_rt)
290 		rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu
291 							- sizeof(el->el_ei);
292 }
293 
294 /*
295  * FUNCTION:		eoninit
296  *
297  * PURPOSE:			initialization
298  *
299  * RETURNS:			nothing
300  */
301 
302 eoninit(unit)
303 	int unit;
304 {
305 	printf("eon driver-init eon%d\n", unit);
306 }
307 
308 
309 /*
310  * FUNCTION:		eonoutput
311  *
312  * PURPOSE:			prepend an eon header and hand to IP
313  * ARGUMENTS:	 	(ifp) is points to the ifnet structure for this unit/device
314  *					(m)  is an mbuf *, *m is a CLNL packet
315  *					(dst) is a destination address - have to interp. as
316  *					multicast or broadcast or real address.
317  *
318  * RETURNS:			unix error code
319  *
320  * NOTES:
321  *
322  */
323 eonoutput(ifp, m, dst, rt)
324 	struct ifnet 	*ifp;
325 	register struct mbuf	*m;		/* packet */
326 	struct sockaddr_iso		*dst;		/* destination addr */
327 	struct rtentry *rt;
328 {
329 	register struct eon_llinfo *el;
330 	register struct eon_iphdr *ei;
331 	struct route *ro;
332 	int	datalen;
333 	struct mbuf *mh;
334 	int	error = 0, class = 0, alen = 0;
335 	caddr_t ipaddrloc;
336 	static struct eon_iphdr eon_iphdr;
337 	static struct route route;
338 
339 	IFDEBUG(D_EON)
340 		printf("eonoutput \n" );
341 	ENDDEBUG
342 
343 	ifp->if_lastchange = time;
344 	ifp->if_opackets++;
345 	if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
346 		if (dst->siso_family == AF_LINK) {
347 			register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
348 
349 			ipaddrloc = LLADDR(sdl);
350 			alen = sdl->sdl_alen;
351 		} else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) {
352 			alen = dst->siso_nlen - 1;
353 			ipaddrloc = (caddr_t) dst->siso_data + 1;
354 		}
355 		switch (alen) {
356 		case 5:
357 			class =  4[(u_char *)ipaddrloc];
358 		case 4:
359 			ro = &route;
360 			ei = &eon_iphdr;
361 			eoniphdr(ei, ipaddrloc, ro, class, 1);
362 			goto send;
363 		}
364 einval:
365 		error =  EINVAL;
366 		goto flush;
367 	}
368 	if ((el->el_flags & RTF_UP) == 0) {
369 		eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
370 		if ((el->el_flags & RTF_UP) == 0) {
371 			error = EHOSTUNREACH;
372 			goto flush;
373 		}
374 	}
375 	if ((m->m_flags & M_PKTHDR) == 0) {
376 		printf("eon: got non headered packet\n");
377 		goto einval;
378 	}
379 	ei = &el->el_ei;
380 	ro = &el->el_iproute;
381 	if (el->el_snpaoffset) {
382 		if (dst->siso_family == AF_ISO) {
383 			bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset],
384 					(caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst));
385 		} else
386 			goto einval;
387 	}
388 send:
389 	/* put an eon_hdr in the buffer, prepended by an ip header */
390 	datalen = m->m_pkthdr.len + EONIPLEN;
391 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
392 	if(mh == (struct mbuf *)0)
393 		goto flush;
394 	mh->m_next = m;
395 	m = mh;
396 	MH_ALIGN(m, sizeof(struct eon_iphdr));
397 	m->m_len = sizeof(struct eon_iphdr);
398 	ifp->if_obytes +=
399 		(ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
400 	*mtod(m, struct eon_iphdr *) = *ei;
401 
402 	IFDEBUG(D_EON)
403 		printf("eonoutput dst ip addr : %x\n",  ei->ei_ip.ip_dst.s_addr);
404 		printf("eonoutput ip_output : eonip header:\n");
405 		dump_buf(ei, sizeof(struct eon_iphdr));
406 	ENDDEBUG
407 
408 	error = ip_output(m, (struct mbuf *)0, ro, 0, NULL);
409 	m = 0;
410 	if (error) {
411 		ifp->if_oerrors++;
412 		ifp->if_opackets--;
413 		ifp->if_obytes -= datalen;
414 	}
415 flush:
416 	if (m)
417 		m_freem(m);
418 	return error;
419 }
420 
421 eoninput(m, iphlen)
422 	register struct mbuf	*m;
423 	int iphlen;
424 {
425 	register struct eon_hdr	*eonhdr;
426 	register struct ip		*iphdr;
427 	struct ifnet 			*eonifp;
428 	int						s;
429 
430 	eonifp = &eonif[0]; /* kludge - really want to give CLNP
431 						* the ifp for eon, not for the real device
432 						*/
433 
434 	IFDEBUG(D_EON)
435 		printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
436 			m, m?m->m_data:0, m?m->m_len:0);
437 	ENDDEBUG
438 
439 	if (m == 0)
440 		return;
441 	if (iphlen > sizeof (struct ip))
442 		ip_stripoptions(m, (struct mbuf *)0);
443 	if (m->m_len < EONIPLEN) {
444 		if ((m = m_pullup(m, EONIPLEN)) == 0) {
445 			IncStat(es_badhdr);
446 drop:
447 			IFDEBUG(D_EON)
448 				printf("eoninput: DROP \n" );
449 			ENDDEBUG
450 			eonifp->if_ierrors ++;
451 			m_freem(m);
452 			return;
453 		}
454 	}
455 	eonif->if_ibytes += m->m_pkthdr.len;
456 	eonif->if_lastchange = time;
457 	iphdr = mtod(m, struct ip *);
458 	/* do a few checks for debugging */
459 	if( iphdr->ip_p != IPPROTO_EON ) {
460 		IncStat(es_badhdr);
461 		goto drop;
462 	}
463 	/* temporarily drop ip header from the mbuf */
464 	m->m_data += sizeof(struct ip);
465 	eonhdr = mtod(m, struct eon_hdr *);
466 	if( iso_check_csum( m, sizeof(struct eon_hdr) )   != EOK ) {
467 		IncStat(es_badcsum);
468 		goto drop;
469 	}
470 	m->m_data -= sizeof(struct ip);
471 
472 	IFDEBUG(D_EON)
473 		printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
474 		printf("eoninput: eon header:\n");
475 		dump_buf(eonhdr, sizeof(struct eon_hdr));
476 	ENDDEBUG
477 
478 	/* checks for debugging */
479 	if( eonhdr->eonh_vers != EON_VERSION) {
480 		IncStat(es_badhdr);
481 		goto drop;
482 	}
483 	m->m_flags &= ~(M_BCAST|M_MCAST);
484 	switch( eonhdr->eonh_class) {
485 		case EON_BROADCAST:
486 			IncStat(es_in_broad);
487 			m->m_flags |= M_BCAST;
488 			break;
489 		case EON_NORMAL_ADDR:
490 			IncStat(es_in_normal);
491 			break;
492 		case EON_MULTICAST_ES:
493 			IncStat(es_in_multi_es);
494 			m->m_flags |= M_MCAST;
495 			break;
496 		case EON_MULTICAST_IS:
497 			IncStat(es_in_multi_is);
498 			m->m_flags |= M_MCAST;
499 			break;
500 	}
501 	eonifp->if_ipackets++;
502 
503 	{
504 		/* put it on the CLNP queue and set soft interrupt */
505 		struct ifqueue 			*ifq;
506 		extern struct ifqueue 	clnlintrq;
507 
508 		m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
509 		IFDEBUG(D_EON)
510 			printf("eoninput to clnl IFQ\n");
511 		ENDDEBUG
512 		ifq = &clnlintrq;
513 		s = splimp();
514 		if (IF_QFULL(ifq)) {
515 			IF_DROP(ifq);
516 			m_freem(m);
517 			eonifp->if_iqdrops++;
518 			eonifp->if_ipackets--;
519 			splx(s);
520 			return;
521 		}
522 		IF_ENQUEUE(ifq, m);
523 		IFDEBUG(D_EON)
524 			printf(
525 	"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
526 				m, m->m_len, m->m_type, m->m_data);
527 			dump_buf(mtod(m, caddr_t), m->m_len);
528 		ENDDEBUG
529 		schednetisr(NETISR_ISO);
530 		splx(s);
531 	}
532 }
533 
534 int
535 eonctlinput(cmd, sin)
536 	int cmd;
537 	struct sockaddr_in *sin;
538 {
539 	extern u_char inetctlerrmap[];
540 
541 	IFDEBUG(D_EON)
542 		printf("eonctlinput: cmd 0x%x addr: ", cmd);
543 		dump_isoaddr(sin);
544 		printf("\n");
545 	ENDDEBUG
546 
547 	if (cmd < 0 || cmd > PRC_NCMDS)
548 		return 0;
549 
550 	IncStat(es_icmp[cmd]);
551 	switch (cmd) {
552 
553 		case	PRC_QUENCH:
554 		case	PRC_QUENCH2:
555 			/* TODO: set the dec bit */
556 			break;
557 		case	PRC_TIMXCEED_REASS:
558 		case	PRC_ROUTEDEAD:
559 		case	PRC_HOSTUNREACH:
560 		case	PRC_UNREACH_NET:
561 		case	PRC_IFDOWN:
562 		case	PRC_UNREACH_HOST:
563 		case	PRC_HOSTDEAD:
564 		case	PRC_TIMXCEED_INTRANS:
565 			/* TODO: mark the link down */
566 			break;
567 
568 		case	PRC_UNREACH_PROTOCOL:
569 		case	PRC_UNREACH_PORT:
570 		case	PRC_UNREACH_SRCFAIL:
571 		case	PRC_REDIRECT_NET:
572 		case	PRC_REDIRECT_HOST:
573 		case	PRC_REDIRECT_TOSNET:
574 		case	PRC_REDIRECT_TOSHOST:
575 		case	PRC_MSGSIZE:
576 		case	PRC_PARAMPROB:
577 			/* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/
578 		break;
579 	}
580 	return 0;
581 }
582 
583 #endif
584