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.21 (Berkeley) 06/05/93 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 void eonrtrequest(); 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 } 174 break; 175 } 176 splx(s); 177 return(error); 178 } 179 180 181 eoniphdr(hdr, loc, ro, class, zero) 182 struct route *ro; 183 register struct eon_iphdr *hdr; 184 caddr_t loc; 185 { 186 struct mbuf mhead; 187 register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst; 188 if (zero) { 189 bzero((caddr_t)hdr, sizeof (*hdr)); 190 bzero((caddr_t)ro, sizeof (*ro)); 191 } 192 sin->sin_family = AF_INET; 193 sin->sin_len = sizeof (*sin); 194 bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr)); 195 /* 196 * If there is a cached route, 197 * check that it is to the same destination 198 * and is still up. If not, free it and try again. 199 */ 200 if (ro->ro_rt) { 201 struct sockaddr_in *dst = 202 (struct sockaddr_in *)rt_key(ro->ro_rt); 203 if ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 204 sin->sin_addr.s_addr != dst->sin_addr.s_addr) { 205 RTFREE(ro->ro_rt); 206 ro->ro_rt = (struct rtentry *)0; 207 } 208 } 209 rtalloc(ro); 210 if (ro->ro_rt) 211 ro->ro_rt->rt_use++; 212 hdr->ei_ip.ip_dst = sin->sin_addr; 213 hdr->ei_ip.ip_p = IPPROTO_EON; 214 hdr->ei_ip.ip_ttl = MAXTTL; 215 hdr->ei_eh.eonh_class = class; 216 hdr->ei_eh.eonh_vers = EON_VERSION; 217 hdr->ei_eh.eonh_csum = 0; 218 mhead.m_data = (caddr_t) &hdr->ei_eh; 219 mhead.m_len = sizeof(struct eon_hdr); 220 mhead.m_next = 0; 221 IFDEBUG(D_EON) 222 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", 223 &mhead, 224 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 225 ENDDEBUG 226 iso_gen_csum(&mhead, 227 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 228 } 229 /* 230 * FUNCTION: eonrtrequest 231 * 232 * PURPOSE: maintains list of direct eon recipients. 233 * sets up IP route for rest. 234 * 235 * RETURNS: nothing 236 */ 237 void 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, NULL); 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