xref: /original-bsd/sys/netiso/if_eon.c (revision acda45c0)
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.11 (Berkeley) 01/09/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 	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, class = 0, alen = 0;
310 	caddr_t ipaddrloc;
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 
324 			ipaddrloc = LLADDR(sdl);
325 			alen = sdl->sdl_alen;
326 		} else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) {
327 			alen = dst->siso_nlen - 1;
328 			ipaddrloc = (caddr_t) dst->siso_data + 1;
329 		}
330 		switch (alen) {
331 		case 5:
332 			class =  4[(u_char *)ipaddrloc];
333 		case 4:
334 			ro = &route;
335 			ei = &eon_iphdr;
336 			eoniphdr(ei, ipaddrloc, ro, class, 1);
337 			goto send;
338 		}
339 einval:
340 		error =  EINVAL;
341 		goto flush;
342 	}
343 	if ((el->el_flags & RTF_UP) == 0) {
344 		eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
345 		if ((el->el_flags & RTF_UP) == 0) {
346 			error = EHOSTUNREACH;
347 			goto flush;
348 		}
349 	}
350 	if ((m->m_flags & M_PKTHDR) == 0) {
351 		printf("eon: got non headered packet\n");
352 		goto einval;
353 	}
354 	ei = &el->el_ei;
355 	ro = &el->el_iproute;
356 	if (el->el_snpaoffset) {
357 		if (dst->siso_family == AF_ISO) {
358 			bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset],
359 					(caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst));
360 		} else
361 			goto einval;
362 	}
363 send:
364 	/* put an eon_hdr in the buffer, prepended by an ip header */
365 	datalen = m->m_pkthdr.len + EONIPLEN;
366 	MGETHDR(mh, M_DONTWAIT, MT_HEADER);
367 	if(mh == (struct mbuf *)0)
368 		goto flush;
369 	mh->m_next = m;
370 	m = mh;
371 	MH_ALIGN(m, sizeof(struct eon_iphdr));
372 	m->m_len = sizeof(struct eon_iphdr);
373 	ifp->if_obytes +=
374 		(ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
375 	*mtod(m, struct eon_iphdr *) = *ei;
376 
377 	IFDEBUG(D_EON)
378 		printf("eonoutput dst ip addr : %x\n",  ei->ei_ip.ip_dst.s_addr);
379 		printf("eonoutput ip_output : eonip header:\n");
380 		dump_buf(ei, sizeof(struct eon_iphdr));
381 	ENDDEBUG
382 
383 	error = ip_output(m, (struct mbuf *)0, ro, 0);
384 	m = 0;
385 	if (error) {
386 		ifp->if_oerrors++;
387 		ifp->if_opackets--;
388 		ifp->if_obytes -= datalen;
389 	}
390 flush:
391 	if (m)
392 		m_freem(m);
393 	return error;
394 }
395 
396 eoninput(m, iphlen)
397 	register struct mbuf	*m;
398 	int iphlen;
399 {
400 	register struct eon_hdr	*eonhdr;
401 	register struct ip		*iphdr;
402 	struct ifnet 			*eonifp;
403 	int						s;
404 
405 	eonifp = &eonif[0]; /* kludge - really want to give CLNP
406 						* the ifp for eon, not for the real device
407 						*/
408 
409 	IFDEBUG(D_EON)
410 		printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
411 			m, m?m->m_data:0, m?m->m_len:0);
412 	ENDDEBUG
413 
414 	if (m == 0)
415 		return;
416 	if (iphlen > sizeof (struct ip))
417 		ip_stripoptions(m, (struct mbuf *)0);
418 	if (m->m_len < EONIPLEN) {
419 		if ((m = m_pullup(m, EONIPLEN)) == 0) {
420 			IncStat(es_badhdr);
421 drop:
422 			IFDEBUG(D_EON)
423 				printf("eoninput: DROP \n" );
424 			ENDDEBUG
425 			eonifp->if_ierrors ++;
426 			m_freem(m);
427 			return;
428 		}
429 	}
430 	eonif->if_ibytes += m->m_pkthdr.len;
431 	eonif->if_lastchange = time;
432 	iphdr = mtod(m, struct ip *);
433 	/* do a few checks for debugging */
434 	if( iphdr->ip_p != IPPROTO_EON ) {
435 		IncStat(es_badhdr);
436 		goto drop;
437 	}
438 	/* temporarily drop ip header from the mbuf */
439 	m->m_data += sizeof(struct ip);
440 	eonhdr = mtod(m, struct eon_hdr *);
441 	if( iso_check_csum( m, sizeof(struct eon_hdr) )   != EOK ) {
442 		IncStat(es_badcsum);
443 		goto drop;
444 	}
445 	m->m_data -= sizeof(struct ip);
446 
447 	IFDEBUG(D_EON)
448 		printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
449 		printf("eoninput: eon header:\n");
450 		dump_buf(eonhdr, sizeof(struct eon_hdr));
451 	ENDDEBUG
452 
453 	/* checks for debugging */
454 	if( eonhdr->eonh_vers != EON_VERSION) {
455 		IncStat(es_badhdr);
456 		goto drop;
457 	}
458 	m->m_flags &= ~(M_BCAST|M_MCAST);
459 	switch( eonhdr->eonh_class) {
460 		case EON_BROADCAST:
461 			IncStat(es_in_broad);
462 			m->m_flags |= M_BCAST;
463 			break;
464 		case EON_NORMAL_ADDR:
465 			IncStat(es_in_normal);
466 			break;
467 		case EON_MULTICAST_ES:
468 			IncStat(es_in_multi_es);
469 			m->m_flags |= M_MCAST;
470 			break;
471 		case EON_MULTICAST_IS:
472 			IncStat(es_in_multi_is);
473 			m->m_flags |= M_MCAST;
474 			break;
475 	}
476 	eonifp->if_ipackets++;
477 
478 	{
479 		/* put it on the CLNP queue and set soft interrupt */
480 		struct ifqueue 			*ifq;
481 		extern struct ifqueue 	clnlintrq;
482 
483 		m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
484 		IFDEBUG(D_EON)
485 			printf("eoninput to clnl IFQ\n");
486 		ENDDEBUG
487 		ifq = &clnlintrq;
488 		s = splimp();
489 		if (IF_QFULL(ifq)) {
490 			IF_DROP(ifq);
491 			m_freem(m);
492 			eonifp->if_iqdrops++;
493 			eonifp->if_ipackets--;
494 			splx(s);
495 			return;
496 		}
497 		IF_ENQUEUE(ifq, m);
498 		IFDEBUG(D_EON)
499 			printf(
500 	"0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
501 				m, m->m_len, m->m_type, m->m_data);
502 			dump_buf(mtod(m, caddr_t), m->m_len);
503 		ENDDEBUG
504 		schednetisr(NETISR_ISO);
505 		splx(s);
506 	}
507 }
508 
509 int
510 eonctlinput(cmd, sin)
511 	int cmd;
512 	struct sockaddr_in *sin;
513 {
514 	extern u_char inetctlerrmap[];
515 
516 	IFDEBUG(D_EON)
517 		printf("eonctlinput: cmd 0x%x addr: ", cmd);
518 		dump_isoaddr(sin);
519 		printf("\n");
520 	ENDDEBUG
521 
522 	if (cmd < 0 || cmd > PRC_NCMDS)
523 		return 0;
524 
525 	IncStat(es_icmp[cmd]);
526 	switch (cmd) {
527 
528 		case	PRC_QUENCH:
529 		case	PRC_QUENCH2:
530 			/* TODO: set the dec bit */
531 			break;
532 		case	PRC_TIMXCEED_REASS:
533 		case	PRC_ROUTEDEAD:
534 		case	PRC_HOSTUNREACH:
535 		case	PRC_UNREACH_NET:
536 		case	PRC_IFDOWN:
537 		case	PRC_UNREACH_HOST:
538 		case	PRC_HOSTDEAD:
539 		case	PRC_TIMXCEED_INTRANS:
540 			/* TODO: mark the link down */
541 			break;
542 
543 		case	PRC_UNREACH_PROTOCOL:
544 		case	PRC_UNREACH_PORT:
545 		case	PRC_UNREACH_SRCFAIL:
546 		case	PRC_REDIRECT_NET:
547 		case	PRC_REDIRECT_HOST:
548 		case	PRC_REDIRECT_TOSNET:
549 		case	PRC_REDIRECT_TOSHOST:
550 		case	PRC_MSGSIZE:
551 		case	PRC_PARAMPROB:
552 			/* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/
553 		break;
554 	}
555 	return 0;
556 }
557 
558 #endif
559