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