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