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.9 (Berkeley) 05/24/90 * 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 extern struct snpa_cache all_es, all_is; 77 #include "argo_debug.h" 78 #include "iso_errno.h" 79 #include "eonvar.h" 80 extern struct timeval time; 81 82 #define EOK 0 83 84 int eoninput(); 85 int eonoutput(); 86 int eonioctl(); 87 int eonattach(); 88 int eoninit(); 89 int eonrtrequest(); 90 extern int ip_output(); 91 struct ifnet eonif[1]; 92 93 eonprotoinit() { 94 (void) eonattach(); 95 } 96 97 struct eon_llinfo eon_llinfo; 98 #define PROBE_OK 0; 99 100 101 /* 102 * FUNCTION: eonattach 103 * 104 * PURPOSE: autoconf attach routine 105 * 106 * RETURNS: void 107 */ 108 109 eonattach() 110 { 111 register struct ifnet *ifp = eonif; 112 113 IFDEBUG(D_EON) 114 printf("eonattach()\n"); 115 ENDDEBUG 116 ifp->if_unit = 0; 117 ifp->if_name = "eon"; 118 ifp->if_mtu = ETHERMTU; 119 /* since everything will go out over ether or token ring */ 120 121 ifp->if_init = eoninit; 122 ifp->if_ioctl = eonioctl; 123 ifp->if_output = eonoutput; 124 ifp->if_type = IFT_EON; 125 ifp->if_addrlen = 5; 126 ifp->if_hdrlen = EONIPLEN; 127 ifp->if_flags = IFF_BROADCAST; 128 if_attach(ifp); 129 eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist); 130 eon_llinfo.el_qhdr.link = 131 eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr); 132 133 IFDEBUG(D_EON) 134 printf("eonattach()\n"); 135 ENDDEBUG 136 } 137 138 139 /* 140 * FUNCTION: eonioctl 141 * 142 * PURPOSE: io controls - ifconfig 143 * need commands to 144 * link-UP (core addr) (flags: ES, IS) 145 * link-DOWN (core addr) (flags: ES, IS) 146 * must be callable from kernel or user 147 * 148 * RETURNS: nothing 149 */ 150 eonioctl(ifp, cmd, data) 151 register struct ifnet *ifp; 152 int cmd; 153 register caddr_t data; 154 { 155 int s = splimp(); 156 register int error = 0; 157 158 IFDEBUG(D_EON) 159 printf("eonioctl (cmd 0x%x) \n", cmd); 160 ENDDEBUG 161 162 switch (cmd) { 163 register struct ifaddr *ifa; 164 extern link_rtrequest(); 165 166 case SIOCSIFADDR: 167 if (ifa = (struct ifaddr *)data) { 168 ifp->if_flags |= IFF_UP; 169 if (ifa->ifa_addr->sa_family != AF_LINK) 170 ifa->ifa_rtrequest = eonrtrequest; 171 ifa->ifa_llinfolen = sizeof(struct eon_llinfo); 172 } 173 break; 174 } 175 splx(s); 176 return(error); 177 } 178 179 180 eoniphdr(hdr, loc, ro, class, zero) 181 struct route *ro; 182 register struct eon_iphdr *hdr; 183 caddr_t loc; 184 { 185 struct mbuf mhead; 186 register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst; 187 if (zero) { 188 bzero((caddr_t)hdr, sizeof (*hdr)); 189 bzero((caddr_t)ro, sizeof (*ro)); 190 } 191 sin->sin_family = AF_INET; 192 sin->sin_len = sizeof (*sin); 193 bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr)); 194 hdr->ei_ip.ip_dst = sin->sin_addr; 195 hdr->ei_ip.ip_p = IPPROTO_EON; 196 hdr->ei_ip.ip_ttl = MAXTTL; 197 hdr->ei_eh.eonh_class = class; 198 hdr->ei_eh.eonh_vers = EON_VERSION; 199 hdr->ei_eh.eonh_csum = 0; 200 mhead.m_data = (caddr_t) &hdr->ei_eh; 201 mhead.m_len = sizeof(struct eon_hdr); 202 mhead.m_next = 0; 203 IFDEBUG(D_EON) 204 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", 205 &mhead, 206 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 207 ENDDEBUG 208 iso_gen_csum(&mhead, 209 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); 210 } 211 /* 212 * FUNCTION: eonrtrequest 213 * 214 * PURPOSE: maintains list of direct eon recipients. 215 * sets up IP route for rest. 216 * 217 * RETURNS: nothing 218 */ 219 eonrtrequest(cmd, rt, gate) 220 register struct rtentry *rt; 221 register struct sockaddr *gate; 222 { 223 unsigned long zerodst = 0; 224 caddr_t ipaddrloc = (caddr_t) &zerodst; 225 register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo; 226 227 if (el == 0) 228 panic("eonrtrequest"); 229 /* 230 * Common Housekeeping 231 */ 232 switch (cmd) { 233 234 case RTM_ADD: 235 insque(&(el->el_qhdr), &eon_llinfo.el_qhdr); 236 el->el_rt = rt; 237 break; 238 239 case RTM_DELETE: 240 remque(&(el->el_qhdr)); 241 /* FALLTHROUGH */ 242 case RTM_CHANGE: 243 el->el_flags &= ~RTF_UP; 244 el->el_snpaoffset = 0; 245 if (el->el_iproute.ro_rt) 246 RTFREE(el->el_iproute.ro_rt); 247 if (cmd = RTM_DELETE) 248 return; 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; 310 caddr_t ippaddrloc; 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 caddr_t ipaddrloc = LLADDR(sdl); 324 int class = (sdl->sdl_alen == 5) ? 4[(u_char *)ipaddrloc] : 0; 325 326 if (sdl->sdl_alen == 4 || sdl->sdl_alen == 5) { 327 ro = &route; 328 ei = &eon_iphdr; 329 eoniphdr(ei, ipaddrloc, ro, class, 1); 330 goto send; 331 } 332 } 333 einval: 334 error = EINVAL; 335 goto flush; 336 } 337 if ((el->el_flags & RTF_UP) == 0) { 338 eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0); 339 if ((el->el_flags & RTF_UP) == 0) { 340 error = EHOSTUNREACH; 341 goto flush; 342 } 343 } 344 if ((m->m_flags & M_PKTHDR) == 0) { 345 printf("eon: got non headered packet\n"); 346 goto einval; 347 } 348 ei = &el->el_ei; 349 ro = &el->el_iproute; 350 if (el->el_snpaoffset) { 351 if (dst->siso_family == AF_ISO) { 352 bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset], 353 (caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst)); 354 } else 355 goto einval; 356 } 357 send: 358 /* put an eon_hdr in the buffer, prepended by an ip header */ 359 datalen = m->m_pkthdr.len + EONIPLEN; 360 MGETHDR(mh, M_DONTWAIT, MT_HEADER); 361 if(mh == (struct mbuf *)0) 362 goto flush; 363 mh->m_next = m; 364 m = mh; 365 MH_ALIGN(m, sizeof(struct eon_iphdr)); 366 m->m_len = sizeof(struct eon_iphdr); 367 ifp->if_obytes += 368 (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen)); 369 *mtod(m, struct eon_iphdr *) = *ei; 370 371 IFDEBUG(D_EON) 372 printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr); 373 printf("eonoutput ip_output : eonip header:\n"); 374 dump_buf(ei, sizeof(struct eon_iphdr)); 375 ENDDEBUG 376 377 error = ip_output(m, (struct mbuf *)0, ro, 0); 378 m = 0; 379 if (error) { 380 ifp->if_oerrors++; 381 ifp->if_opackets--; 382 ifp->if_obytes -= datalen; 383 } 384 flush: 385 if (m) 386 m_freem(m); 387 return error; 388 } 389 390 eoninput(m, iphlen) 391 register struct mbuf *m; 392 int iphlen; 393 { 394 register struct eon_hdr *eonhdr; 395 register struct ip *iphdr; 396 struct ifnet *eonifp; 397 int s; 398 399 eonifp = &eonif[0]; /* kludge - really want to give CLNP 400 * the ifp for eon, not for the real device 401 */ 402 403 IFDEBUG(D_EON) 404 printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n", 405 m, m?m->m_data:0, m?m->m_len:0); 406 ENDDEBUG 407 408 if (m == 0) 409 return; 410 if (iphlen > sizeof (struct ip)) 411 ip_stripoptions(m, (struct mbuf *)0); 412 if (m->m_len < EONIPLEN) { 413 if ((m = m_pullup(m, EONIPLEN)) == 0) { 414 IncStat(es_badhdr); 415 drop: 416 IFDEBUG(D_EON) 417 printf("eoninput: DROP \n" ); 418 ENDDEBUG 419 eonifp->if_ierrors ++; 420 m_freem(m); 421 return; 422 } 423 } 424 eonif->if_ibytes += m->m_pkthdr.len; 425 eonif->if_lastchange = time; 426 iphdr = mtod(m, struct ip *); 427 /* do a few checks for debugging */ 428 if( iphdr->ip_p != IPPROTO_EON ) { 429 IncStat(es_badhdr); 430 goto drop; 431 } 432 /* temporarily drop ip header from the mbuf */ 433 m->m_data += sizeof(struct ip); 434 eonhdr = mtod(m, struct eon_hdr *); 435 if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { 436 IncStat(es_badcsum); 437 goto drop; 438 } 439 m->m_data -= sizeof(struct ip); 440 441 IFDEBUG(D_EON) 442 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); 443 printf("eoninput: eon header:\n"); 444 dump_buf(eonhdr, sizeof(struct eon_hdr)); 445 ENDDEBUG 446 447 /* checks for debugging */ 448 if( eonhdr->eonh_vers != EON_VERSION) { 449 IncStat(es_badhdr); 450 goto drop; 451 } 452 m->m_flags &= ~(M_BCAST|M_MCAST); 453 switch( eonhdr->eonh_class) { 454 case EON_BROADCAST: 455 IncStat(es_in_broad); 456 m->m_flags |= M_BCAST; 457 break; 458 case EON_NORMAL_ADDR: 459 IncStat(es_in_normal); 460 break; 461 case EON_MULTICAST_ES: 462 IncStat(es_in_multi_es); 463 m->m_flags |= M_MCAST; 464 break; 465 case EON_MULTICAST_IS: 466 IncStat(es_in_multi_is); 467 m->m_flags |= M_MCAST; 468 break; 469 } 470 eonifp->if_ipackets++; 471 472 { 473 /* put it on the CLNP queue and set soft interrupt */ 474 struct ifqueue *ifq; 475 extern struct ifqueue clnlintrq; 476 477 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ 478 IFDEBUG(D_EON) 479 printf("eoninput to clnl IFQ\n"); 480 ENDDEBUG 481 ifq = &clnlintrq; 482 s = splimp(); 483 if (IF_QFULL(ifq)) { 484 IF_DROP(ifq); 485 m_freem(m); 486 eonifp->if_iqdrops++; 487 eonifp->if_ipackets--; 488 splx(s); 489 return; 490 } 491 IF_ENQUEUE(ifq, m); 492 IFDEBUG(D_EON) 493 printf( 494 "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n", 495 m, m->m_len, m->m_type, m->m_data); 496 dump_buf(mtod(m, caddr_t), m->m_len); 497 ENDDEBUG 498 schednetisr(NETISR_ISO); 499 splx(s); 500 } 501 } 502 503 int 504 eonctlinput(cmd, sin) 505 int cmd; 506 struct sockaddr_in *sin; 507 { 508 extern u_char inetctlerrmap[]; 509 510 IFDEBUG(D_EON) 511 printf("eonctlinput: cmd 0x%x addr: ", cmd); 512 dump_isoaddr(sin); 513 printf("\n"); 514 ENDDEBUG 515 516 if (cmd < 0 || cmd > PRC_NCMDS) 517 return 0; 518 519 IncStat(es_icmp[cmd]); 520 switch (cmd) { 521 522 case PRC_QUENCH: 523 case PRC_QUENCH2: 524 /* TODO: set the dec bit */ 525 break; 526 case PRC_TIMXCEED_REASS: 527 case PRC_ROUTEDEAD: 528 case PRC_HOSTUNREACH: 529 case PRC_UNREACH_NET: 530 case PRC_IFDOWN: 531 case PRC_UNREACH_HOST: 532 case PRC_HOSTDEAD: 533 case PRC_TIMXCEED_INTRANS: 534 /* TODO: mark the link down */ 535 break; 536 537 case PRC_UNREACH_PROTOCOL: 538 case PRC_UNREACH_PORT: 539 case PRC_UNREACH_SRCFAIL: 540 case PRC_REDIRECT_NET: 541 case PRC_REDIRECT_HOST: 542 case PRC_REDIRECT_TOSNET: 543 case PRC_REDIRECT_TOSHOST: 544 case PRC_MSGSIZE: 545 case PRC_PARAMPROB: 546 printf("eonctlinput: ICMP cmd 0x%x\n", cmd ); 547 break; 548 } 549 return 0; 550 } 551 552 #endif 553