xref: /original-bsd/sys/netiso/if_eon.c (revision d24b829c)
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.10 (Berkeley) 06/20/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 #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 	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 register struct sockaddr *gate;
220 {
221 	unsigned long zerodst = 0;
222 	caddr_t	ipaddrloc = (caddr_t) &zerodst;
223 	register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
224 
225 	/*
226 	 * Common Housekeeping
227 	 */
228 	switch (cmd) {
229 	case RTM_DELETE:
230 		if (el) {
231 			remque(&(el->el_qhdr));
232 			if (el->el_iproute.ro_rt)
233 				RTFREE(el->el_iproute.ro_rt);
234 			Free(el);
235 			rt->rt_llinfo = 0;
236 		}
237 		return;
238 
239 	case RTM_RESOLVE:
240 	case RTM_ADD:
241 		R_Malloc(el, struct eon_llinfo *, sizeof(*el));
242 		rt->rt_llinfo = (caddr_t)el;
243 		if (el == 0)
244 			return;
245 		Bzero(el, sizeof(*el));
246 		insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
247 		el->el_rt = rt;
248 		break;
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