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.15 (Berkeley) 05/09/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->rt_rmx.rmx_mtu 292 - sizeof(el->el_ei); 293 } 294 295 /* 296 * FUNCTION: eoninit 297 * 298 * PURPOSE: initialization 299 * 300 * RETURNS: nothing 301 */ 302 303 eoninit(unit) 304 int unit; 305 { 306 printf("eon driver-init eon%d\n", unit); 307 } 308 309 310 /* 311 * FUNCTION: eonoutput 312 * 313 * PURPOSE: prepend an eon header and hand to IP 314 * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device 315 * (m) is an mbuf *, *m is a CLNL packet 316 * (dst) is a destination address - have to interp. as 317 * multicast or broadcast or real address. 318 * 319 * RETURNS: unix error code 320 * 321 * NOTES: 322 * 323 */ 324 eonoutput(ifp, m, dst, rt) 325 struct ifnet *ifp; 326 register struct mbuf *m; /* packet */ 327 struct sockaddr_iso *dst; /* destination addr */ 328 struct rtentry *rt; 329 { 330 register struct eon_llinfo *el; 331 register struct eon_iphdr *ei; 332 struct route *ro; 333 int datalen; 334 struct mbuf *mh; 335 int error = 0, class = 0, alen = 0; 336 caddr_t ipaddrloc; 337 static struct eon_iphdr eon_iphdr; 338 static struct route route; 339 340 IFDEBUG(D_EON) 341 printf("eonoutput \n" ); 342 ENDDEBUG 343 344 ifp->if_lastchange = time; 345 ifp->if_opackets++; 346 if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) { 347 if (dst->siso_family == AF_LINK) { 348 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst; 349 350 ipaddrloc = LLADDR(sdl); 351 alen = sdl->sdl_alen; 352 } else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) { 353 alen = dst->siso_nlen - 1; 354 ipaddrloc = (caddr_t) dst->siso_data + 1; 355 } 356 switch (alen) { 357 case 5: 358 class = 4[(u_char *)ipaddrloc]; 359 case 4: 360 ro = &route; 361 ei = &eon_iphdr; 362 eoniphdr(ei, ipaddrloc, ro, class, 1); 363 goto send; 364 } 365 einval: 366 error = EINVAL; 367 goto flush; 368 } 369 if ((el->el_flags & RTF_UP) == 0) { 370 eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0); 371 if ((el->el_flags & RTF_UP) == 0) { 372 error = EHOSTUNREACH; 373 goto flush; 374 } 375 } 376 if ((m->m_flags & M_PKTHDR) == 0) { 377 printf("eon: got non headered packet\n"); 378 goto einval; 379 } 380 ei = &el->el_ei; 381 ro = &el->el_iproute; 382 if (el->el_snpaoffset) { 383 if (dst->siso_family == AF_ISO) { 384 bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset], 385 (caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst)); 386 } else 387 goto einval; 388 } 389 send: 390 /* put an eon_hdr in the buffer, prepended by an ip header */ 391 datalen = m->m_pkthdr.len + EONIPLEN; 392 MGETHDR(mh, M_DONTWAIT, MT_HEADER); 393 if(mh == (struct mbuf *)0) 394 goto flush; 395 mh->m_next = m; 396 m = mh; 397 MH_ALIGN(m, sizeof(struct eon_iphdr)); 398 m->m_len = sizeof(struct eon_iphdr); 399 ifp->if_obytes += 400 (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen)); 401 *mtod(m, struct eon_iphdr *) = *ei; 402 403 IFDEBUG(D_EON) 404 printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr); 405 printf("eonoutput ip_output : eonip header:\n"); 406 dump_buf(ei, sizeof(struct eon_iphdr)); 407 ENDDEBUG 408 409 error = ip_output(m, (struct mbuf *)0, ro, 0); 410 m = 0; 411 if (error) { 412 ifp->if_oerrors++; 413 ifp->if_opackets--; 414 ifp->if_obytes -= datalen; 415 } 416 flush: 417 if (m) 418 m_freem(m); 419 return error; 420 } 421 422 eoninput(m, iphlen) 423 register struct mbuf *m; 424 int iphlen; 425 { 426 register struct eon_hdr *eonhdr; 427 register struct ip *iphdr; 428 struct ifnet *eonifp; 429 int s; 430 431 eonifp = &eonif[0]; /* kludge - really want to give CLNP 432 * the ifp for eon, not for the real device 433 */ 434 435 IFDEBUG(D_EON) 436 printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n", 437 m, m?m->m_data:0, m?m->m_len:0); 438 ENDDEBUG 439 440 if (m == 0) 441 return; 442 if (iphlen > sizeof (struct ip)) 443 ip_stripoptions(m, (struct mbuf *)0); 444 if (m->m_len < EONIPLEN) { 445 if ((m = m_pullup(m, EONIPLEN)) == 0) { 446 IncStat(es_badhdr); 447 drop: 448 IFDEBUG(D_EON) 449 printf("eoninput: DROP \n" ); 450 ENDDEBUG 451 eonifp->if_ierrors ++; 452 m_freem(m); 453 return; 454 } 455 } 456 eonif->if_ibytes += m->m_pkthdr.len; 457 eonif->if_lastchange = time; 458 iphdr = mtod(m, struct ip *); 459 /* do a few checks for debugging */ 460 if( iphdr->ip_p != IPPROTO_EON ) { 461 IncStat(es_badhdr); 462 goto drop; 463 } 464 /* temporarily drop ip header from the mbuf */ 465 m->m_data += sizeof(struct ip); 466 eonhdr = mtod(m, struct eon_hdr *); 467 if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { 468 IncStat(es_badcsum); 469 goto drop; 470 } 471 m->m_data -= sizeof(struct ip); 472 473 IFDEBUG(D_EON) 474 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); 475 printf("eoninput: eon header:\n"); 476 dump_buf(eonhdr, sizeof(struct eon_hdr)); 477 ENDDEBUG 478 479 /* checks for debugging */ 480 if( eonhdr->eonh_vers != EON_VERSION) { 481 IncStat(es_badhdr); 482 goto drop; 483 } 484 m->m_flags &= ~(M_BCAST|M_MCAST); 485 switch( eonhdr->eonh_class) { 486 case EON_BROADCAST: 487 IncStat(es_in_broad); 488 m->m_flags |= M_BCAST; 489 break; 490 case EON_NORMAL_ADDR: 491 IncStat(es_in_normal); 492 break; 493 case EON_MULTICAST_ES: 494 IncStat(es_in_multi_es); 495 m->m_flags |= M_MCAST; 496 break; 497 case EON_MULTICAST_IS: 498 IncStat(es_in_multi_is); 499 m->m_flags |= M_MCAST; 500 break; 501 } 502 eonifp->if_ipackets++; 503 504 { 505 /* put it on the CLNP queue and set soft interrupt */ 506 struct ifqueue *ifq; 507 extern struct ifqueue clnlintrq; 508 509 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ 510 IFDEBUG(D_EON) 511 printf("eoninput to clnl IFQ\n"); 512 ENDDEBUG 513 ifq = &clnlintrq; 514 s = splimp(); 515 if (IF_QFULL(ifq)) { 516 IF_DROP(ifq); 517 m_freem(m); 518 eonifp->if_iqdrops++; 519 eonifp->if_ipackets--; 520 splx(s); 521 return; 522 } 523 IF_ENQUEUE(ifq, m); 524 IFDEBUG(D_EON) 525 printf( 526 "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n", 527 m, m->m_len, m->m_type, m->m_data); 528 dump_buf(mtod(m, caddr_t), m->m_len); 529 ENDDEBUG 530 schednetisr(NETISR_ISO); 531 splx(s); 532 } 533 } 534 535 int 536 eonctlinput(cmd, sin) 537 int cmd; 538 struct sockaddr_in *sin; 539 { 540 extern u_char inetctlerrmap[]; 541 542 IFDEBUG(D_EON) 543 printf("eonctlinput: cmd 0x%x addr: ", cmd); 544 dump_isoaddr(sin); 545 printf("\n"); 546 ENDDEBUG 547 548 if (cmd < 0 || cmd > PRC_NCMDS) 549 return 0; 550 551 IncStat(es_icmp[cmd]); 552 switch (cmd) { 553 554 case PRC_QUENCH: 555 case PRC_QUENCH2: 556 /* TODO: set the dec bit */ 557 break; 558 case PRC_TIMXCEED_REASS: 559 case PRC_ROUTEDEAD: 560 case PRC_HOSTUNREACH: 561 case PRC_UNREACH_NET: 562 case PRC_IFDOWN: 563 case PRC_UNREACH_HOST: 564 case PRC_HOSTDEAD: 565 case PRC_TIMXCEED_INTRANS: 566 /* TODO: mark the link down */ 567 break; 568 569 case PRC_UNREACH_PROTOCOL: 570 case PRC_UNREACH_PORT: 571 case PRC_UNREACH_SRCFAIL: 572 case PRC_REDIRECT_NET: 573 case PRC_REDIRECT_HOST: 574 case PRC_REDIRECT_TOSNET: 575 case PRC_REDIRECT_TOSHOST: 576 case PRC_MSGSIZE: 577 case PRC_PARAMPROB: 578 /* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/ 579 break; 580 } 581 return 0; 582 } 583 584 #endif 585