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