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