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.11 (Berkeley) 01/09/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 register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst; 185 if (zero) { 186 bzero((caddr_t)hdr, sizeof (*hdr)); 187 bzero((caddr_t)ro, sizeof (*ro)); 188 } 189 sin->sin_family = AF_INET; 190 sin->sin_len = sizeof (*sin); 191 bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr)); 192 hdr->ei_ip.ip_dst = sin->sin_addr; 193 hdr->ei_ip.ip_p = IPPROTO_EON; 194 hdr->ei_ip.ip_ttl = MAXTTL; 195 hdr->ei_eh.eonh_class = class; 196 hdr->ei_eh.eonh_vers = EON_VERSION; 197 hdr->ei_eh.eonh_csum = 0; 198 mhead.m_data = (caddr_t) &hdr->ei_eh; 199 mhead.m_len = sizeof(struct eon_hdr); 200 mhead.m_next = 0; 201 IFDEBUG(D_EON) 202 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", 203 &mhead, 204 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 205 ENDDEBUG 206 iso_gen_csum(&mhead, 207 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 208 } 209 /* 210 * FUNCTION: eonrtrequest 211 * 212 * PURPOSE: maintains list of direct eon recipients. 213 * sets up IP route for rest. 214 * 215 * RETURNS: nothing 216 */ 217 eonrtrequest(cmd, rt, gate) 218 register struct rtentry *rt; 219 register struct sockaddr *gate; 220 { 221 unsigned long zerodst = 0; 222 caddr_t ipaddrloc = (caddr_t) &zerodst; 223 register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo; 224 225 /* 226 * Common Housekeeping 227 */ 228 switch (cmd) { 229 case RTM_DELETE: 230 if (el) { 231 remque(&(el->el_qhdr)); 232 if (el->el_iproute.ro_rt) 233 RTFREE(el->el_iproute.ro_rt); 234 Free(el); 235 rt->rt_llinfo = 0; 236 } 237 return; 238 239 case RTM_RESOLVE: 240 case RTM_ADD: 241 R_Malloc(el, struct eon_llinfo *, sizeof(*el)); 242 rt->rt_llinfo = (caddr_t)el; 243 if (el == 0) 244 return; 245 Bzero(el, sizeof(*el)); 246 insque(&(el->el_qhdr), &eon_llinfo.el_qhdr); 247 el->el_rt = rt; 248 break; 249 } 250 if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) { 251 case AF_LINK: 252 #define SDL(x) ((struct sockaddr_dl *)x) 253 if (SDL(gate)->sdl_alen = 1) 254 el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate)); 255 else 256 ipaddrloc = LLADDR(SDL(gate)); 257 break; 258 case AF_INET: 259 #define SIN(x) ((struct sockaddr_in *)x) 260 ipaddrloc = (caddr_t) &SIN(gate)->sin_addr; 261 break; 262 default: 263 return; 264 } 265 el->el_flags |= RTF_UP; 266 eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0); 267 } 268 269 /* 270 * FUNCTION: eoninit 271 * 272 * PURPOSE: initialization 273 * 274 * RETURNS: nothing 275 */ 276 277 eoninit(unit) 278 int unit; 279 { 280 printf("eon driver-init eon%d\n", unit); 281 } 282 283 284 /* 285 * FUNCTION: eonoutput 286 * 287 * PURPOSE: prepend an eon header and hand to IP 288 * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device 289 * (m) is an mbuf *, *m is a CLNL packet 290 * (dst) is a destination address - have to interp. as 291 * multicast or broadcast or real address. 292 * 293 * RETURNS: unix error code 294 * 295 * NOTES: 296 * 297 */ 298 eonoutput(ifp, m, dst, rt) 299 struct ifnet *ifp; 300 register struct mbuf *m; /* packet */ 301 struct sockaddr_iso *dst; /* destination addr */ 302 struct rtentry *rt; 303 { 304 register struct eon_llinfo *el; 305 register struct eon_iphdr *ei; 306 struct route *ro; 307 int datalen; 308 struct mbuf *mh; 309 int error = 0, class = 0, alen = 0; 310 caddr_t ipaddrloc; 311 static struct eon_iphdr eon_iphdr; 312 static struct route route; 313 314 IFDEBUG(D_EON) 315 printf("eonoutput \n" ); 316 ENDDEBUG 317 318 ifp->if_lastchange = time; 319 ifp->if_opackets++; 320 if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) { 321 if (dst->siso_family == AF_LINK) { 322 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst; 323 324 ipaddrloc = LLADDR(sdl); 325 alen = sdl->sdl_alen; 326 } else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) { 327 alen = dst->siso_nlen - 1; 328 ipaddrloc = (caddr_t) dst->siso_data + 1; 329 } 330 switch (alen) { 331 case 5: 332 class = 4[(u_char *)ipaddrloc]; 333 case 4: 334 ro = &route; 335 ei = &eon_iphdr; 336 eoniphdr(ei, ipaddrloc, ro, class, 1); 337 goto send; 338 } 339 einval: 340 error = EINVAL; 341 goto flush; 342 } 343 if ((el->el_flags & RTF_UP) == 0) { 344 eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0); 345 if ((el->el_flags & RTF_UP) == 0) { 346 error = EHOSTUNREACH; 347 goto flush; 348 } 349 } 350 if ((m->m_flags & M_PKTHDR) == 0) { 351 printf("eon: got non headered packet\n"); 352 goto einval; 353 } 354 ei = &el->el_ei; 355 ro = &el->el_iproute; 356 if (el->el_snpaoffset) { 357 if (dst->siso_family == AF_ISO) { 358 bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset], 359 (caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst)); 360 } else 361 goto einval; 362 } 363 send: 364 /* put an eon_hdr in the buffer, prepended by an ip header */ 365 datalen = m->m_pkthdr.len + EONIPLEN; 366 MGETHDR(mh, M_DONTWAIT, MT_HEADER); 367 if(mh == (struct mbuf *)0) 368 goto flush; 369 mh->m_next = m; 370 m = mh; 371 MH_ALIGN(m, sizeof(struct eon_iphdr)); 372 m->m_len = sizeof(struct eon_iphdr); 373 ifp->if_obytes += 374 (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen)); 375 *mtod(m, struct eon_iphdr *) = *ei; 376 377 IFDEBUG(D_EON) 378 printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr); 379 printf("eonoutput ip_output : eonip header:\n"); 380 dump_buf(ei, sizeof(struct eon_iphdr)); 381 ENDDEBUG 382 383 error = ip_output(m, (struct mbuf *)0, ro, 0); 384 m = 0; 385 if (error) { 386 ifp->if_oerrors++; 387 ifp->if_opackets--; 388 ifp->if_obytes -= datalen; 389 } 390 flush: 391 if (m) 392 m_freem(m); 393 return error; 394 } 395 396 eoninput(m, iphlen) 397 register struct mbuf *m; 398 int iphlen; 399 { 400 register struct eon_hdr *eonhdr; 401 register struct ip *iphdr; 402 struct ifnet *eonifp; 403 int s; 404 405 eonifp = &eonif[0]; /* kludge - really want to give CLNP 406 * the ifp for eon, not for the real device 407 */ 408 409 IFDEBUG(D_EON) 410 printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n", 411 m, m?m->m_data:0, m?m->m_len:0); 412 ENDDEBUG 413 414 if (m == 0) 415 return; 416 if (iphlen > sizeof (struct ip)) 417 ip_stripoptions(m, (struct mbuf *)0); 418 if (m->m_len < EONIPLEN) { 419 if ((m = m_pullup(m, EONIPLEN)) == 0) { 420 IncStat(es_badhdr); 421 drop: 422 IFDEBUG(D_EON) 423 printf("eoninput: DROP \n" ); 424 ENDDEBUG 425 eonifp->if_ierrors ++; 426 m_freem(m); 427 return; 428 } 429 } 430 eonif->if_ibytes += m->m_pkthdr.len; 431 eonif->if_lastchange = time; 432 iphdr = mtod(m, struct ip *); 433 /* do a few checks for debugging */ 434 if( iphdr->ip_p != IPPROTO_EON ) { 435 IncStat(es_badhdr); 436 goto drop; 437 } 438 /* temporarily drop ip header from the mbuf */ 439 m->m_data += sizeof(struct ip); 440 eonhdr = mtod(m, struct eon_hdr *); 441 if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { 442 IncStat(es_badcsum); 443 goto drop; 444 } 445 m->m_data -= sizeof(struct ip); 446 447 IFDEBUG(D_EON) 448 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); 449 printf("eoninput: eon header:\n"); 450 dump_buf(eonhdr, sizeof(struct eon_hdr)); 451 ENDDEBUG 452 453 /* checks for debugging */ 454 if( eonhdr->eonh_vers != EON_VERSION) { 455 IncStat(es_badhdr); 456 goto drop; 457 } 458 m->m_flags &= ~(M_BCAST|M_MCAST); 459 switch( eonhdr->eonh_class) { 460 case EON_BROADCAST: 461 IncStat(es_in_broad); 462 m->m_flags |= M_BCAST; 463 break; 464 case EON_NORMAL_ADDR: 465 IncStat(es_in_normal); 466 break; 467 case EON_MULTICAST_ES: 468 IncStat(es_in_multi_es); 469 m->m_flags |= M_MCAST; 470 break; 471 case EON_MULTICAST_IS: 472 IncStat(es_in_multi_is); 473 m->m_flags |= M_MCAST; 474 break; 475 } 476 eonifp->if_ipackets++; 477 478 { 479 /* put it on the CLNP queue and set soft interrupt */ 480 struct ifqueue *ifq; 481 extern struct ifqueue clnlintrq; 482 483 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ 484 IFDEBUG(D_EON) 485 printf("eoninput to clnl IFQ\n"); 486 ENDDEBUG 487 ifq = &clnlintrq; 488 s = splimp(); 489 if (IF_QFULL(ifq)) { 490 IF_DROP(ifq); 491 m_freem(m); 492 eonifp->if_iqdrops++; 493 eonifp->if_ipackets--; 494 splx(s); 495 return; 496 } 497 IF_ENQUEUE(ifq, m); 498 IFDEBUG(D_EON) 499 printf( 500 "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n", 501 m, m->m_len, m->m_type, m->m_data); 502 dump_buf(mtod(m, caddr_t), m->m_len); 503 ENDDEBUG 504 schednetisr(NETISR_ISO); 505 splx(s); 506 } 507 } 508 509 int 510 eonctlinput(cmd, sin) 511 int cmd; 512 struct sockaddr_in *sin; 513 { 514 extern u_char inetctlerrmap[]; 515 516 IFDEBUG(D_EON) 517 printf("eonctlinput: cmd 0x%x addr: ", cmd); 518 dump_isoaddr(sin); 519 printf("\n"); 520 ENDDEBUG 521 522 if (cmd < 0 || cmd > PRC_NCMDS) 523 return 0; 524 525 IncStat(es_icmp[cmd]); 526 switch (cmd) { 527 528 case PRC_QUENCH: 529 case PRC_QUENCH2: 530 /* TODO: set the dec bit */ 531 break; 532 case PRC_TIMXCEED_REASS: 533 case PRC_ROUTEDEAD: 534 case PRC_HOSTUNREACH: 535 case PRC_UNREACH_NET: 536 case PRC_IFDOWN: 537 case PRC_UNREACH_HOST: 538 case PRC_HOSTDEAD: 539 case PRC_TIMXCEED_INTRANS: 540 /* TODO: mark the link down */ 541 break; 542 543 case PRC_UNREACH_PROTOCOL: 544 case PRC_UNREACH_PORT: 545 case PRC_UNREACH_SRCFAIL: 546 case PRC_REDIRECT_NET: 547 case PRC_REDIRECT_HOST: 548 case PRC_REDIRECT_TOSNET: 549 case PRC_REDIRECT_TOSHOST: 550 case PRC_MSGSIZE: 551 case PRC_PARAMPROB: 552 /* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/ 553 break; 554 } 555 return 0; 556 } 557 558 #endif 559