1 /*********************************************************** 2 Copyright IBM Corporation 1987 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, 8 provided that the above copyright notice appear in all copies and that 9 both that copyright notice and this permission notice appear in 10 supporting documentation, and that the name of IBM not be 11 used in advertising or publicity pertaining to distribution of the 12 software without specific, written prior permission. 13 14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 22 ******************************************************************/ 23 24 /* 25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26 */ 27 /* 28 * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $ 29 * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $ 30 * @(#)if_eon.c 7.5 (Berkeley) 09/22/89 * 31 * 32 * EON rfc 33 * Layer between IP and CLNL 34 * 35 * TODO: 36 * Put together a current rfc986 address format and get the right offset 37 * for the nsel 38 */ 39 40 #ifndef lint 41 static char *rcsid = "$Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $"; 42 #endif lint 43 44 #ifdef EON 45 #define NEON 1 46 47 48 #include "param.h" 49 #include "systm.h" 50 #include "types.h" 51 #include "mbuf.h" 52 #include "buf.h" 53 #include "protosw.h" 54 #include "socket.h" 55 #include "ioctl.h" 56 #include "errno.h" 57 #include "types.h" 58 59 #include "../net/if.h" 60 #include "../net/if_types.h" 61 #include "../net/netisr.h" 62 #include "../net/route.h" 63 #include "machine/mtpr.h" 64 65 #include "../netinet/in.h" 66 #include "../netinet/in_systm.h" 67 #include "../netinet/ip.h" 68 #include "../netinet/ip_var.h" 69 #include "../netinet/if_ether.h" 70 71 #include "iso.h" 72 #include "iso_var.h" 73 #include "iso_snpac.h" 74 extern struct snpa_cache all_es, all_is; 75 #include "argo_debug.h" 76 #include "iso_errno.h" 77 #include "eonvar.h" 78 extern struct timeval time; 79 80 #define EOK 0 81 82 int eoninput(); 83 int eonint(); 84 int eonoutput(); 85 int eonioctl(); 86 int eonprobe(); 87 int eonattach(); 88 int eoninit(); 89 extern int ip_output(); 90 struct ifnet eonif[NEON]; 91 92 #ifdef FAKEIOCCDEV 93 #include "machine/io.h" 94 #include "../machineio/ioccvar.h" 95 96 #define EON_FAKE_CSR 0 97 int eon_fakeautoconf[2]; /* need at least 2 ints */ 98 99 caddr_t eonstd[] = { (caddr_t) eon_fakeautoconf, 0 }; 100 struct iocc_device *eoninfo[NEON]; 101 102 struct iocc_driver eondriver = { 103 eonprobe, /* idr_probe */ 104 0, /* idr_slave */ 105 eonattach, /* idr_attach */ 106 0, /* idr_dgo */ 107 eonstd, /* idr_addr - list of standard addresses for device */ 108 "eon", /* idr_dname */ 109 eoninfo, /* idr_dinfo - backptrs to iodinit structs */ 110 0, /* idr_mname - controller name */ 111 0, /* idr_minfo -- backptrs to iominit structs */ 112 eonint, /* idr_intr - interrupt rtn */ 113 0, /* idr_csr - offset to read/write csr */ 114 EON_FAKE_CSR, /* idr_chanrelse */ 115 0, /* idr_flags */ 116 }; 117 #else 118 struct iocc_device { 119 int iod_unit; 120 } bsd_iocc_fakeout; 121 122 eonprotoinit() { 123 (void) eonprobe(); 124 (void) eonattach(&bsd_iocc_fakeout); 125 } 126 #define PROBE_OK 0; 127 #endif 128 129 130 /* 131 * entry in the EON address cache (list) 132 * (or pt-pt links list, however you view it) 133 */ 134 135 struct eon_centry { 136 struct qhdr eonc_q_LINK; 137 #define eonc_nextLINK eonc_q_LINK.link 138 #define eonc_prevLINK eonc_q_LINK.flink 139 140 struct qhdr eonc_q_IS; 141 #define eonc_nextIS eonc_q_IS.link 142 #define eonc_prevIS eonc_q_IS.flink 143 144 struct qhdr eonc_q_ES; 145 #define eonc_nextES eonc_q_ES.link 146 #define eonc_prevES eonc_q_ES.flink 147 148 struct in_addr eonc_addr; 149 u_short eonc_status; 150 }; 151 152 /* kinda like mtod() but for eon_centries */ 153 #define qtocentry(q, off) ((struct eon_centry *) (((caddr_t)(q)) - off)) 154 #define centrytoq(c, off) ((struct qhdr *) (((caddr_t)(c)) + off)) 155 156 struct qhdr eon_LINK_hdr = { 157 (struct qhdr *)0, 158 (struct qhdr *)0, 159 }; 160 static struct qhdr eon_IS_hdr = { 161 (struct qhdr *)0, 162 (struct qhdr *)0, 163 }; 164 static struct qhdr eon_ES_hdr = { 165 (struct qhdr *)0, 166 (struct qhdr *)0, 167 }; 168 static struct qhdr eon_FREE_hdr = { 169 (struct qhdr *)0, 170 (struct qhdr *)0, 171 }; 172 173 #define INITQ(q) (q)->rlink = (q)->link = (q) 174 175 /* 176 * FUNCTION: eon_dumpcache 177 * 178 * PURPOSE: dump the cache beginning with the argument given 179 * 180 * RETURNS: 0 181 */ 182 183 eon_dumpcache(which) 184 int which; 185 { 186 register int off; 187 register struct eon_centry *ent; 188 struct qhdr *hdr; 189 190 switch (which) { 191 case E_FREE: 192 printf("FREE LIST\n"); 193 off = _offsetof( struct eon_centry, eonc_q_LINK); 194 hdr = &eon_FREE_hdr; 195 ent = qtocentry( hdr->link, 196 _offsetof( struct eon_centry, eonc_q_LINK)); 197 break; 198 case E_ES: 199 printf("ES LIST\n"); 200 off = _offsetof( struct eon_centry, eonc_q_ES); 201 hdr = &eon_ES_hdr; 202 ent = qtocentry( hdr->link, 203 _offsetof( struct eon_centry, eonc_q_ES)); 204 break; 205 case E_IS: 206 printf("IS LIST\n"); 207 off = _offsetof( struct eon_centry, eonc_q_IS); 208 hdr = &eon_IS_hdr; 209 ent = qtocentry( hdr->link, 210 _offsetof( struct eon_centry, eonc_q_IS)); 211 break; 212 case E_LINK: 213 printf("LINK LIST\n"); 214 off = _offsetof( struct eon_centry, eonc_q_LINK); 215 hdr = &eon_LINK_hdr; 216 ent = qtocentry( hdr->link, 217 _offsetof( struct eon_centry, eonc_q_LINK)); 218 break; 219 } 220 if(hdr == centrytoq(ent, off)->link ) 221 printf("EMPTY\n"); 222 else while(1) { 223 printf("0x%x: %d.%d.%d.%d, %s %s\n", ent, 224 (ent->eonc_addr.s_addr>>24)&0xff, 225 (ent->eonc_addr.s_addr>>16)&0xff, 226 (ent->eonc_addr.s_addr>>8)&0xff, 227 (ent->eonc_addr.s_addr)&0xff, 228 ((ent->eonc_status & EON_ESLINK_UP)?"ES^": 229 (ent->eonc_status & EON_ESLINK_DOWN)?"es*": " "), 230 ((ent->eonc_status & EON_ISLINK_UP)?"IS^": 231 (ent->eonc_status & EON_ISLINK_DOWN)?"is*": " ") 232 ); 233 dump_buf(ent, sizeof(struct eon_centry) ); 234 235 { /* ent = ent.next: */ 236 register struct qhdr *q; 237 238 q = centrytoq(ent, off)->link; 239 if( q == hdr) 240 break; 241 if( q == (struct qhdr *)0) /* panic */ { 242 printf("eon0: BAD Q HDR or CENTRY! q 0x%x ent 0x%x off 0x%x\n", 243 q, ent, off); 244 break; 245 } 246 ent = qtocentry( q, off ); 247 } 248 } 249 } 250 /* 251 * FUNCTION: eon_initcache 252 * 253 * PURPOSE: allocs a bunch of free cache entries 254 * 255 * RETURNS: 0 256 */ 257 258 eon_initcache() 259 { 260 static struct eon_centry eoncache[EON_CACHESIZE]; 261 register int i; 262 register struct eon_centry *ent; 263 264 bzero( eoncache, EON_CACHESIZE*sizeof(struct eon_centry)); 265 INITQ( &eon_FREE_hdr ); 266 INITQ( &eon_LINK_hdr ); 267 INITQ( &eon_IS_hdr ); 268 INITQ( &eon_ES_hdr ); 269 270 ent = eoncache; 271 272 for(i=0; i< EON_CACHESIZE; i++,ent++) { 273 _insque( centrytoq(ent, _offsetof( struct eon_centry, eonc_q_LINK)), 274 &eon_FREE_hdr); 275 } 276 printf("eon0: cache initialized\n"); 277 } 278 279 /* 280 * FUNCTION: eonprobe 281 * 282 * PURPOSE: filler for device configuration 283 * 284 * RETURNS: PROBE_OK 285 */ 286 287 int int_level, int_irq; 288 eonprobe() 289 { 290 extern int int_level, int_irq; 291 292 printf("eonprobe() \n"); 293 int_level = int_irq = 0x3; /* pick something - anything but -1 */ 294 return PROBE_OK; 295 } 296 297 /* 298 * FUNCTION: eonattach 299 * 300 * PURPOSE: autoconf attach routine 301 * 302 * RETURNS: void 303 */ 304 305 eonattach(iod) 306 register struct iocc_device *iod; 307 { 308 register struct ifnet *ifp = &eonif[iod->iod_unit]; 309 310 IFDEBUG(D_EON) 311 printf("eonattach()\n"); 312 ENDDEBUG 313 ifp->if_unit = iod->iod_unit; 314 ifp->if_name = "eon"; 315 ifp->if_mtu = ETHERMTU; 316 /* since everything will go out over ether or token ring */ 317 318 ifp->if_init = eoninit; 319 ifp->if_ioctl = eonioctl; 320 ifp->if_output = eonoutput; 321 ifp->if_type = IFT_EON; 322 ifp->if_addrlen = 5; 323 ifp->if_hdrlen = EONIPLEN; 324 ifp->if_flags = IFF_BROADCAST; 325 if_attach(ifp); 326 327 IFDEBUG(D_EON) 328 printf("eonattach()\n"); 329 ENDDEBUG 330 eon_initcache(); 331 IFDEBUG(D_EON) 332 printf("eon%d: attached\n", iod->iod_unit); 333 ENDDEBUG 334 } 335 336 static struct eon_centry * 337 find_oldent( ea ) 338 struct sockaddr_eon *ea; 339 { 340 register int offset = 341 _offsetof( struct eon_centry, eonc_q_LINK); 342 register struct eon_centry *ent, *oent; 343 344 oent = ent = qtocentry(eon_LINK_hdr.link, offset); 345 IFDEBUG(D_EON) 346 printf("eon: find_oldent() ipaddr: %d.%d.%d.%d\n", 347 (ea->seon_ipaddr>>24)&0xff, 348 (ea->seon_ipaddr>>16)&0xff, 349 (ea->seon_ipaddr>>8)&0xff, 350 (ea->seon_ipaddr)&0xff ); 351 ENDDEBUG 352 do { 353 if( ent->eonc_addr.s_addr == ea->seon_ipaddr ) 354 return ent; 355 ent = qtocentry(ent->eonc_nextLINK, offset); 356 } while (ent != oent); 357 return (struct eon_centry *)0; 358 } 359 360 /* 361 * FUNCTION: eonioctl 362 * 363 * PURPOSE: io controls - ifconfig 364 * need commands to 365 * link-UP (core addr) (flags: ES, IS) 366 * link-DOWN (core addr) (flags: ES, IS) 367 * must be callable from kernel or user 368 * 369 * RETURNS: nothing 370 */ 371 eonioctl(ifp, cmd, data) 372 register struct ifnet *ifp; 373 register int cmd; 374 register caddr_t data; 375 { 376 struct iso_ifreq *ifr = (struct iso_ifreq *)data; 377 register struct sockaddr_eon *eoa = 378 (struct sockaddr_eon *)&(ifr->ifr_Addr); 379 register int s = splimp(); 380 register int error = 0; 381 382 IFDEBUG(D_EON) 383 printf("eonioctl (cmd 0x%x) \n", cmd); 384 ENDDEBUG 385 386 switch (cmd){ 387 case SIOCSEONCORE: { 388 /* add pt-pt link to the set of core addrs */ 389 register struct eon_centry *ent, *oldent; 390 register u_short which; 391 392 /* "which" tells which lists to put these guys in - don't 393 * want to insert something in a list if it's already there 394 */ 395 #define LEGIT_EONADDR(a)\ 396 ((a->seon_family == AF_ISO) && (a->seon_afi == AFI_RFC986) &&\ 397 (a->seon_idi[0] == 0) && (a->seon_idi[1] == 6) \ 398 && (a->seon_vers == EON_986_VERSION) && (a->seon_adrlen == 0x14)) 399 400 if( ! LEGIT_EONADDR(eoa) ) { 401 error = EADDRNOTAVAIL; 402 break; 403 } 404 405 oldent = find_oldent( eoa ); 406 IFDEBUG(D_EON) 407 printf("eonioctl legit seon_status 0x%x oldent %s\n", 408 eoa->seon_status, oldent?"found":"not found"); 409 ENDDEBUG 410 411 if( eoa->seon_status & UPBITS ) { 412 if (!oldent) { 413 /* doesn't exist - need to create one */ 414 if (eon_FREE_hdr.link == eon_FREE_hdr.rlink) 415 return ENOBUFS; 416 ent = qtocentry(eon_FREE_hdr.link, 417 _offsetof( struct eon_centry, eonc_q_LINK)); 418 remque( &(ent->eonc_q_LINK) ); 419 ent->eonc_addr.s_addr = eoa->seon_ipaddr; 420 insque( &(ent->eonc_q_LINK), (&eon_LINK_hdr)); 421 oldent = ent; 422 } 423 424 which = (eoa->seon_status ^ oldent->eonc_status) & 425 eoa->seon_status & UPBITS; 426 427 oldent->eonc_status |= (eoa->seon_status & UPBITS); 428 429 if( which & EON_ESLINK_UP ) 430 insque( &oldent->eonc_q_ES, (&eon_ES_hdr)); 431 if( which & EON_ISLINK_UP ) 432 insque( &oldent->eonc_q_IS, (&eon_IS_hdr)); 433 } 434 435 if( eoa->seon_status & DOWNBITS ) { 436 if(!oldent) { 437 return ENOENT; /* no such entry */ 438 } 439 which = (eoa->seon_status ^ oldent->eonc_status) & 440 eoa->seon_status & DOWNBITS; 441 442 oldent->eonc_status |= (eoa->seon_status & DOWNBITS); 443 444 if( which & EON_ESLINK_DOWN ) 445 remque( &(oldent->eonc_q_ES) ); 446 if( which & EON_ISLINK_DOWN ) 447 remque( &(oldent->eonc_q_IS) ); 448 } 449 450 IFDEBUG(D_EON) 451 printf("at end status 0x%x\n", oldent->eonc_status); 452 ENDDEBUG 453 break; 454 } 455 456 case SIOCGEONCORE: 457 { 458 register struct eon_centry *oldent; 459 460 oldent = find_oldent( eoa ); 461 if( oldent == (struct eon_centry *)0 ) 462 error = EADDRNOTAVAIL; 463 else 464 eoa->seon_status = oldent->eonc_status; 465 } 466 break; 467 468 case SIOCSIFADDR: 469 ifp->if_flags |= IFF_UP; 470 break; 471 472 case SIOCSIFFLAGS: 473 if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & 474 IFF_RUNNING){ 475 ifp->if_flags &= ~IFF_RUNNING; 476 } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & 477 IFF_RUNNING) == 0) 478 eoninit(ifp->if_unit); 479 break; 480 default: 481 error = EINVAL; 482 } 483 splx(s); 484 return(error); 485 } 486 487 /* 488 * FUNCTION: eoninit 489 * 490 * PURPOSE: initialization 491 * 492 * RETURNS: nothing 493 */ 494 495 eoninit(unit) 496 int unit; 497 { 498 printf("eon driver-init eon%d\n", unit); 499 } 500 501 502 /* 503 * FUNCTION: eonint 504 * 505 * PURPOSE: filler for device configuration 506 * 507 * RETURNS: nothing 508 * 509 * NOTES: *should* never get called - for debugging it's here 510 */ 511 512 eonint() 513 { 514 /* silent - so no more stray interrupt messages from the aed! yay 515 printf("eonint() called - BOGUS INTERRUPT\n"); 516 */ 517 } 518 519 520 /* 521 * FUNCTION: eonoutput 522 * 523 * PURPOSE: prepend an eon header and hand to IP 524 * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device 525 * (m) is an mbuf *, *m is a CLNL packet 526 * (dst) is a destination address - have to interp. as 527 * multicast or broadcast or real address. 528 * 529 * RETURNS: unix error code 530 * 531 * NOTES: 532 * 533 */ 534 eonoutput(ifp, morig, dst) 535 struct ifnet *ifp; 536 register struct mbuf *morig; /* packet */ 537 struct sockaddr_iso *dst; /* destination addr */ 538 { 539 int s; 540 struct eon_hdr *eonhdr; 541 struct ip *iphdr; 542 struct mbuf *mh; 543 int error = 0; 544 register int datalen; 545 caddr_t dstipaddrloc; 546 int single = 0, class, qoffset = 0, snpalen; 547 register struct eon_centry *ent; 548 register struct sockaddr_eon *eoa; 549 struct qhdr *q; 550 char edst[6]; 551 552 IFDEBUG(D_EON) 553 printf("eonoutput \n" ); 554 ENDDEBUG 555 556 ifp->if_lastchange = time; 557 ifp->if_opackets++; 558 if( dst->siso_family != AF_ISO ) { 559 einval: 560 error = EINVAL; 561 goto flush; 562 } 563 if ((morig->m_flags & M_PKTHDR) == 0) { 564 printf("eon: got non headered packet\n"); 565 goto einval; 566 } 567 eoa = (struct sockaddr_eon *)dst; 568 if (LEGIT_EONADDR(eoa)) { 569 class = eoa->seon_protoid; 570 dstipaddrloc = (caddr_t)&(eoa->seon_ipaddr); 571 } else if (eoa->seon_afi == AFI_SNA) { 572 dstipaddrloc = (caddr_t)&(dst->siso_data[1]); 573 if (dst->siso_nlen == 6) { 574 class = dst->siso_data[5]; 575 } else if (dst->siso_nlen == 7) { 576 if (bcmp(dstipaddrloc, all_is.sc_snpa, 6)) 577 class = EON_MULTICAST_ES; 578 else if (bcmp(dstipaddrloc, all_es.sc_snpa, 6)) 579 class = EON_MULTICAST_IS; 580 else 581 goto einval; 582 } else 583 goto einval; 584 } else if (0 == iso_snparesolve(ifp, dst, edst, &snpalen)) { 585 dstipaddrloc = (caddr_t)edst; 586 class = edst[4]; 587 } else { 588 error = EINVAL; 589 goto flush; 590 } 591 switch (class) { 592 case EON_NORMAL_ADDR: 593 IncStat(es_out_normal); 594 single = 1; 595 break; 596 597 case EON_BROADCAST: 598 IncStat(es_out_broad); 599 if(eon_LINK_hdr.link == eon_LINK_hdr.rlink) { 600 error = EADDRNOTAVAIL; 601 } else { 602 qoffset = _offsetof( struct eon_centry, eonc_q_LINK); 603 ent = qtocentry(eon_LINK_hdr.link, qoffset); 604 dstipaddrloc = (caddr_t) &(ent->eonc_addr); 605 } 606 break; 607 case EON_MULTICAST_ES: 608 IncStat(es_out_multi_es); 609 if (eon_ES_hdr.link == eon_ES_hdr.rlink) { 610 error = EADDRNOTAVAIL; 611 } else { 612 qoffset = _offsetof( struct eon_centry, eonc_q_ES); 613 ent = qtocentry(eon_ES_hdr.link, qoffset); 614 dstipaddrloc = (caddr_t) &(ent->eonc_addr); 615 } 616 break; 617 case EON_MULTICAST_IS: 618 IncStat(es_out_multi_is); 619 if (eon_IS_hdr.link == eon_IS_hdr.rlink) { 620 error = EADDRNOTAVAIL; 621 } else { 622 qoffset = _offsetof( struct eon_centry, eonc_q_LINK); 623 ent = qtocentry(eon_IS_hdr.link, qoffset); 624 dstipaddrloc = (caddr_t) &(ent->eonc_addr); 625 } 626 break; 627 default: 628 printf("bad class value; treated as EON_NORMAL_ADDR\n"); 629 class = EON_NORMAL_ADDR; 630 single = 1; 631 break; 632 } 633 if( error ) 634 goto done; 635 636 /* get data length -- needed later */ 637 datalen = morig->m_pkthdr.len; 638 IFDEBUG(D_EON) 639 printf("eonoutput : m_datalen returns %d\n", datalen); 640 ENDDEBUG 641 642 MGETHDR(mh, M_DONTWAIT, MT_HEADER); 643 if(mh == (struct mbuf *)0) 644 goto done; 645 646 /* put an eon_hdr in the buffer, prepended by an ip header */ 647 mh->m_len = sizeof(struct eon_hdr); 648 MH_ALIGN(mh, sizeof(struct eon_hdr)); 649 mh->m_next = morig; 650 eonhdr = mtod(mh, struct eon_hdr *); 651 eonhdr->eonh_class = class; 652 eonhdr->eonh_vers = EON_VERSION; 653 eonhdr->eonh_csum = 0; 654 655 IFDEBUG(D_EON) 656 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", 657 mh, _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 658 ENDDEBUG 659 iso_gen_csum(mh, 660 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 661 662 mh->m_data -= sizeof(*iphdr); 663 mh->m_len += sizeof(*iphdr); 664 iphdr = mtod(mh, struct ip *); 665 bzero((caddr_t)iphdr, sizeof (*iphdr)); 666 667 iphdr->ip_p = IPPROTO_EON; 668 ifp->if_obytes += 669 (iphdr->ip_len = (u_short)(mh->m_pkthdr.len = EONIPLEN + datalen)); 670 iphdr->ip_ttl = MAXTTL; 671 iphdr->ip_src.s_addr = INADDR_ANY; 672 673 IFDEBUG(D_EON) 674 printf("eonoutput : after gen csum: ip_len %d/0x%x\n", 675 mh->m_pkthdr.len, mh->m_pkthdr.len); 676 ENDDEBUG 677 678 morig = mh; 679 680 for(;;) { 681 682 if( !single ) { 683 /* make a copy to send */ 684 IFDEBUG(D_EON) 685 printf("eonoutput : m_copy (0x%x, 0, 0x%x)\n", 686 morig, iphdr->ip_len); 687 ENDDEBUG 688 if (((mh = m_copy(morig, 0, morig->m_pkthdr.len)) == 0) || 689 ((mh = m_pullup(mh, sizeof(struct ip))) == 0)) { 690 error = ENOBUFS; 691 goto done; 692 } 693 iphdr = mtod(mh, struct ip *); 694 } 695 IFDEBUG(D_EON) 696 printf("eonoutput : bcopy 0x%x to 0x%x length %d\n", 697 dstipaddrloc, 698 (caddr_t)&(iphdr->ip_dst.s_addr), 699 sizeof(iphdr->ip_dst.s_addr)); 700 ENDDEBUG 701 bcopy(dstipaddrloc, (caddr_t)&(iphdr->ip_dst.s_addr), 702 sizeof(iphdr->ip_dst.s_addr)); 703 IFDEBUG(D_EON) 704 printf("eonoutput : dst ip addr : %d.%d.%d.%d", 705 (iphdr->ip_dst.s_addr>>24)&0xff, 706 (iphdr->ip_dst.s_addr>>16)&0xff, 707 (iphdr->ip_dst.s_addr>>8)&0xff, 708 (iphdr->ip_dst.s_addr)&0xff ); 709 ENDDEBUG 710 711 IFDEBUG(D_EON) 712 printf("eonoutput ip_output : eon header:\n"); 713 dump_buf(eonhdr, sizeof(struct eon_hdr)); 714 printf("ip header:\n"); 715 dump_buf(iphdr, sizeof(struct ip)); 716 ENDDEBUG 717 718 IncStat(es_ipout); 719 if( error = ip_output(mh, (struct mbuf *)0, (struct route *)0, 0) ) 720 break; 721 722 IFDEBUG(D_EON) 723 printf("eonoutput ip_output returns 0x%x; single %d\n", 724 error, single); 725 ENDDEBUG 726 727 if(single) 728 break; 729 730 q = centrytoq(ent, qoffset)->link; 731 if( q == (struct qhdr *)0) 732 break; 733 ent = qtocentry( q, qoffset ); 734 IFDEBUG(D_EON) 735 printf("eonoutput : get next entry: 0x%x\n", ent); 736 ENDDEBUG 737 dstipaddrloc = (caddr_t) &(ent->eonc_addr); 738 IFDEBUG(D_EON) 739 printf("eonoutput : dump of eon_centry 0x%x:\n", ent ); 740 dump_buf(ent, sizeof(struct eon_centry) ); 741 ENDDEBUG 742 } 743 done: 744 if( !single ) { 745 IFDEBUG(D_EON) 746 printf("eonoutput : freeing morig 0x%x\n", morig); 747 ENDDEBUG 748 flush: 749 m_freem(morig); 750 } 751 if (error) { 752 ifp->if_oerrors++; 753 ifp->if_opackets--; 754 ifp->if_obytes -= datalen + EONIPLEN; 755 } 756 return error; 757 } 758 759 eoninput(m, iphlen) 760 register struct mbuf *m; 761 int iphlen; 762 { 763 register struct eon_hdr *eonhdr; 764 register struct ip *iphdr; 765 struct ifnet *eonifp; 766 int s; 767 768 eonifp = &eonif[0]; /* kludge - really want to give CLNP 769 * the ifp for eon, not for the real device 770 */ 771 772 IFDEBUG(D_EON) 773 printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n", 774 m, m?m->m_data:0, m?m->m_len:0); 775 ENDDEBUG 776 777 if (m == 0) 778 return; 779 if (iphlen > sizeof (struct ip)) 780 ip_stripoptions(m, (struct mbuf *)0); 781 if (m->m_len < EONIPLEN) { 782 if ((m = m_pullup(m, EONIPLEN)) == 0) { 783 IncStat(es_badhdr); 784 drop: 785 IFDEBUG(D_EON) 786 printf("eoninput: DROP \n" ); 787 ENDDEBUG 788 eonifp->if_ierrors ++; 789 m_freem(m); 790 return; 791 } 792 } 793 eonif->if_ibytes += m->m_pkthdr.len; 794 eonif->if_lastchange = time; 795 iphdr = mtod(m, struct ip *); 796 /* do a few checks for debugging */ 797 if( iphdr->ip_p != IPPROTO_EON ) { 798 IncStat(es_badhdr); 799 goto drop; 800 } 801 /* temporarily drop ip header from the mbuf */ 802 m->m_data += sizeof(struct ip); 803 eonhdr = mtod(m, struct eon_hdr *); 804 if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { 805 IncStat(es_badcsum); 806 goto drop; 807 } 808 m->m_data -= sizeof(struct ip); 809 810 IFDEBUG(D_EON) 811 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); 812 printf("eoninput: eon header:\n"); 813 dump_buf(eonhdr, sizeof(struct eon_hdr)); 814 ENDDEBUG 815 816 /* checks for debugging */ 817 if( eonhdr->eonh_vers != EON_VERSION) { 818 IncStat(es_badhdr); 819 goto drop; 820 } 821 m->m_flags &= ~(M_BCAST|M_MCAST); 822 switch( eonhdr->eonh_class) { 823 case EON_BROADCAST: 824 IncStat(es_in_broad); 825 m->m_flags |= M_BCAST; 826 break; 827 case EON_NORMAL_ADDR: 828 IncStat(es_in_normal); 829 break; 830 case EON_MULTICAST_ES: 831 IncStat(es_in_multi_es); 832 m->m_flags |= M_MCAST; 833 break; 834 case EON_MULTICAST_IS: 835 IncStat(es_in_multi_is); 836 m->m_flags |= M_MCAST; 837 break; 838 } 839 eonifp->if_ipackets++; 840 841 { 842 /* put it on the CLNP queue and set soft interrupt */ 843 struct ifqueue *ifq; 844 extern struct ifqueue clnlintrq; 845 846 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ 847 IFDEBUG(D_EON) 848 printf("eoninput to clnl IFQ\n"); 849 ENDDEBUG 850 ifq = &clnlintrq; 851 s = splimp(); 852 if (IF_QFULL(ifq)) { 853 IF_DROP(ifq); 854 m_freem(m); 855 eonifp->if_iqdrops++; 856 eonifp->if_ipackets--; 857 splx(s); 858 return; 859 } 860 IF_ENQUEUE(ifq, m); 861 IFDEBUG(D_EON) 862 printf( 863 "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n", 864 m, m->m_len, m->m_type, m->m_data); 865 dump_buf(mtod(m, caddr_t), m->m_len); 866 ENDDEBUG 867 schednetisr(NETISR_ISO); 868 splx(s); 869 } 870 } 871 872 int 873 eonctlinput(cmd, sin) 874 int cmd; 875 struct sockaddr_in *sin; 876 { 877 extern u_char inetctlerrmap[]; 878 879 IFDEBUG(D_EON) 880 printf("eonctlinput: cmd 0x%x addr: ", cmd); 881 dump_isoaddr(sin); 882 printf("\n"); 883 ENDDEBUG 884 885 if (cmd < 0 || cmd > PRC_NCMDS) 886 return 0; 887 888 IncStat(es_icmp[cmd]); 889 switch (cmd) { 890 891 case PRC_QUENCH: 892 case PRC_QUENCH2: 893 /* TODO: set the dec bit */ 894 break; 895 case PRC_TIMXCEED_REASS: 896 case PRC_ROUTEDEAD: 897 case PRC_HOSTUNREACH: 898 case PRC_UNREACH_NET: 899 case PRC_IFDOWN: 900 case PRC_UNREACH_HOST: 901 case PRC_HOSTDEAD: 902 case PRC_TIMXCEED_INTRANS: 903 /* TODO: mark the link down */ 904 break; 905 906 case PRC_UNREACH_PROTOCOL: 907 case PRC_UNREACH_PORT: 908 case PRC_UNREACH_NEEDFRAG: 909 case PRC_UNREACH_SRCFAIL: 910 case PRC_REDIRECT_NET: 911 case PRC_REDIRECT_HOST: 912 case PRC_REDIRECT_TOSNET: 913 case PRC_REDIRECT_TOSHOST: 914 case PRC_MSGSIZE: 915 case PRC_PARAMPROB: 916 printf("eonctlinput: ICMP cmd 0x%x\n", cmd ); 917 break; 918 } 919 return 0; 920 } 921 922 #endif 923