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