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