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