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.19 (Berkeley) 10/11/92 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 <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/mbuf.h> 55 #include <sys/buf.h> 56 #include <sys/protosw.h> 57 #include <sys/socket.h> 58 #include <sys/ioctl.h> 59 #include <sys/errno.h> 60 #include <sys/types.h> 61 62 #include <net/if.h> 63 #include <net/if_types.h> 64 #include <net/if_dl.h> 65 #include <net/netisr.h> 66 #include <net/route.h> 67 #include <machine/mtpr.h> 68 69 #include <netinet/in.h> 70 #include <netinet/in_systm.h> 71 #include <netinet/in_var.h> 72 #include <netinet/ip.h> 73 #include <netinet/ip_var.h> 74 #include <netinet/if_ether.h> 75 76 #include <netiso/iso.h> 77 #include <netiso/iso_var.h> 78 #include <netiso/iso_snpac.h> 79 #include <netiso/argo_debug.h> 80 #include <netiso/iso_errno.h> 81 #include <netiso/eonvar.h> 82 83 extern struct timeval time; 84 extern struct ifnet loif; 85 86 #define EOK 0 87 88 int eoninput(); 89 int eonoutput(); 90 int eonioctl(); 91 int eonattach(); 92 int eoninit(); 93 int eonrtrequest(); 94 extern int ip_output(); 95 struct ifnet eonif[1]; 96 97 eonprotoinit() { 98 (void) eonattach(); 99 } 100 101 struct eon_llinfo eon_llinfo; 102 #define PROBE_OK 0; 103 104 105 /* 106 * FUNCTION: eonattach 107 * 108 * PURPOSE: autoconf attach routine 109 * 110 * RETURNS: void 111 */ 112 113 eonattach() 114 { 115 register struct ifnet *ifp = eonif; 116 117 IFDEBUG(D_EON) 118 printf("eonattach()\n"); 119 ENDDEBUG 120 ifp->if_unit = 0; 121 ifp->if_name = "eon"; 122 ifp->if_mtu = ETHERMTU; 123 /* since everything will go out over ether or token ring */ 124 125 ifp->if_init = eoninit; 126 ifp->if_ioctl = eonioctl; 127 ifp->if_output = eonoutput; 128 ifp->if_type = IFT_EON; 129 ifp->if_addrlen = 5; 130 ifp->if_hdrlen = EONIPLEN; 131 ifp->if_flags = IFF_BROADCAST; 132 if_attach(ifp); 133 eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist); 134 eon_llinfo.el_qhdr.link = 135 eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr); 136 137 IFDEBUG(D_EON) 138 printf("eonattach()\n"); 139 ENDDEBUG 140 } 141 142 143 /* 144 * FUNCTION: eonioctl 145 * 146 * PURPOSE: io controls - ifconfig 147 * need commands to 148 * link-UP (core addr) (flags: ES, IS) 149 * link-DOWN (core addr) (flags: ES, IS) 150 * must be callable from kernel or user 151 * 152 * RETURNS: nothing 153 */ 154 eonioctl(ifp, cmd, data) 155 register struct ifnet *ifp; 156 int cmd; 157 register caddr_t data; 158 { 159 int s = splimp(); 160 register int error = 0; 161 162 IFDEBUG(D_EON) 163 printf("eonioctl (cmd 0x%x) \n", cmd); 164 ENDDEBUG 165 166 switch (cmd) { 167 register struct ifaddr *ifa; 168 169 case SIOCSIFADDR: 170 if (ifa = (struct ifaddr *)data) { 171 ifp->if_flags |= IFF_UP; 172 if (ifa->ifa_addr->sa_family != AF_LINK) 173 ifa->ifa_rtrequest = eonrtrequest; 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 register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst; 189 if (zero) { 190 bzero((caddr_t)hdr, sizeof (*hdr)); 191 bzero((caddr_t)ro, sizeof (*ro)); 192 } 193 sin->sin_family = AF_INET; 194 sin->sin_len = sizeof (*sin); 195 bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr)); 196 /* 197 * If there is a cached route, 198 * check that it is to the same destination 199 * and is still up. If not, free it and try again. 200 */ 201 if (ro->ro_rt) { 202 struct sockaddr_in *dst = 203 (struct sockaddr_in *)rt_key(ro->ro_rt); 204 if ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 205 sin->sin_addr.s_addr != dst->sin_addr.s_addr) { 206 RTFREE(ro->ro_rt); 207 ro->ro_rt = (struct rtentry *)0; 208 } 209 } 210 rtalloc(ro); 211 if (ro->ro_rt) 212 ro->ro_rt->rt_use++; 213 hdr->ei_ip.ip_dst = sin->sin_addr; 214 hdr->ei_ip.ip_p = IPPROTO_EON; 215 hdr->ei_ip.ip_ttl = MAXTTL; 216 hdr->ei_eh.eonh_class = class; 217 hdr->ei_eh.eonh_vers = EON_VERSION; 218 hdr->ei_eh.eonh_csum = 0; 219 mhead.m_data = (caddr_t) &hdr->ei_eh; 220 mhead.m_len = sizeof(struct eon_hdr); 221 mhead.m_next = 0; 222 IFDEBUG(D_EON) 223 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", 224 &mhead, 225 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 226 ENDDEBUG 227 iso_gen_csum(&mhead, 228 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 229 } 230 /* 231 * FUNCTION: eonrtrequest 232 * 233 * PURPOSE: maintains list of direct eon recipients. 234 * sets up IP route for rest. 235 * 236 * RETURNS: nothing 237 */ 238 eonrtrequest(cmd, rt, gate) 239 register struct rtentry *rt; 240 register struct sockaddr *gate; 241 { 242 unsigned long zerodst = 0; 243 caddr_t ipaddrloc = (caddr_t) &zerodst; 244 register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo; 245 246 /* 247 * Common Housekeeping 248 */ 249 switch (cmd) { 250 case RTM_DELETE: 251 if (el) { 252 remque(&(el->el_qhdr)); 253 if (el->el_iproute.ro_rt) 254 RTFREE(el->el_iproute.ro_rt); 255 Free(el); 256 rt->rt_llinfo = 0; 257 } 258 return; 259 260 case RTM_ADD: 261 case RTM_RESOLVE: 262 rt->rt_rmx.rmx_mtu = loif.if_mtu; /* unless better below */ 263 R_Malloc(el, struct eon_llinfo *, sizeof(*el)); 264 rt->rt_llinfo = (caddr_t)el; 265 if (el == 0) 266 return; 267 Bzero(el, sizeof(*el)); 268 insque(&(el->el_qhdr), &eon_llinfo.el_qhdr); 269 el->el_rt = rt; 270 break; 271 } 272 if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) { 273 case AF_LINK: 274 #define SDL(x) ((struct sockaddr_dl *)x) 275 if (SDL(gate)->sdl_alen == 1) 276 el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate)); 277 else 278 ipaddrloc = LLADDR(SDL(gate)); 279 break; 280 case AF_INET: 281 #define SIN(x) ((struct sockaddr_in *)x) 282 ipaddrloc = (caddr_t) &SIN(gate)->sin_addr; 283 break; 284 default: 285 return; 286 } 287 el->el_flags |= RTF_UP; 288 eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0); 289 if (el->el_iproute.ro_rt) 290 rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu 291 - 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