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