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