1 /* 2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved. 3 * 4 * This software may be freely used, copied, modified, and distributed 5 * provided that the above copyright notice is preserved in all copies of the 6 * software. 7 */ 8 9 /* -*-C-*- 10 * 11 * $Revision: 1.3 $ 12 * $Date: 2004/12/27 14:00:54 $ 13 * 14 * 15 * etherdrv.c - Ethernet Driver for Angel. 16 */ 17 18 #ifdef __hpux 19 # define _POSIX_SOURCE 1 20 # define _HPUX_SOURCE 1 21 # define _XOPEN_SOURCE 1 22 #endif 23 24 #include <stdio.h> 25 #ifdef __hpux 26 # define uint hide_HPs_uint 27 #endif 28 #ifdef STDC_HEADERS 29 # include <unistd.h> 30 # ifdef __hpux 31 # undef uint 32 # endif 33 #endif 34 #include <stdlib.h> 35 #include <string.h> 36 #ifdef __hpux 37 # define uint hide_HPs_uint 38 #endif 39 #include <fcntl.h> 40 #ifdef __hpux 41 # undef uint 42 #endif 43 #include <errno.h> 44 #include <stdarg.h> 45 #include <ctype.h> 46 #include "host.h" 47 48 #ifdef COMPILING_ON_WINDOWS 49 typedef char * caddr_t; 50 # undef IGNORE 51 # include <winsock.h> 52 # include "angeldll.h" 53 #else 54 # ifdef __hpux 55 # define uint hide_HPs_uint 56 # endif 57 # include <sys/types.h> 58 # include <sys/socket.h> 59 # ifdef __hpux 60 # undef uint 61 # endif 62 # include <netdb.h> 63 # include <sys/time.h> 64 # include <sys/ioctl.h> 65 # ifdef HAVE_SYS_FILIO_H 66 # include <sys/filio.h> 67 # endif 68 # include <netinet/in.h> 69 # include <arpa/inet.h> 70 #endif 71 72 #include "hsys.h" 73 #include "devices.h" 74 #include "angel_endian.h" 75 #include "buffers.h" 76 #include "hostchan.h" 77 #include "params.h" 78 #include "logging.h" 79 #include "ethernet.h" 80 81 82 #if !defined(COMPILING_ON_WINDOWS) && !defined(STDC_HEADERS) 83 /* These two might not work for windows. */ 84 extern int sys_nerr; 85 extern char * sys_errlist[]; 86 #endif 87 88 #ifndef UNUSED 89 # define UNUSED(x) (x = x) /* Silence compiler warnings */ 90 #endif 91 92 /* 93 * forward declarations of static functions 94 */ 95 static int EthernetOpen(const char *name, const char *arg); 96 static int EthernetMatch(const char *name, const char *arg); 97 static void EthernetClose(void); 98 static int EthernetRead(DriverCall *dc, bool block); 99 static int EthernetWrite(DriverCall *dc); 100 static int EthernetIoctl(const int opcode, void *args); 101 102 /* 103 * the device descriptor for Ethernet 104 */ 105 DeviceDescr angel_EthernetDevice = 106 { 107 "Ethernet", 108 EthernetOpen, 109 EthernetMatch, 110 EthernetClose, 111 EthernetRead, 112 EthernetWrite, 113 EthernetIoctl 114 }; 115 116 /* 117 * descriptor for the socket that we talk down 118 */ 119 static int sock = -1; 120 121 /* 122 * address of the remote target 123 */ 124 static struct sockaddr_in remote, *ia = &remote; 125 126 /* 127 * array of dynamic port numbers on target 128 */ 129 static unsigned short int ports[2]; 130 131 /* 132 * Function: set_address 133 * Purpose: Try to get an address into an understandable form 134 * 135 * Params: 136 * Input: addr The address to parse 137 * 138 * Output: ia Structure to hold the parsed address 139 * 140 * Returns: 141 * OK: 0 142 * Error: -1 143 */ 144 static int set_address(const char *const addr, struct sockaddr_in *const ia) 145 { 146 ia->sin_family = AF_INET; 147 148 /* 149 * Try address as a dotted decimal 150 */ 151 ia->sin_addr.s_addr = inet_addr(addr); 152 153 /* 154 * If that failed, try it as a hostname 155 */ 156 if (ia->sin_addr.s_addr == (u_int)-1) 157 { 158 struct hostent *hp = gethostbyname(addr); 159 160 if (hp == NULL) 161 return -1; 162 163 (void)memcpy((caddr_t)&ia->sin_addr, hp->h_addr, hp->h_length); 164 } 165 166 return 0; 167 } 168 169 /* 170 * Function: open_socket 171 * Purpose: Open a non-blocking UDP socket, and bind it to a port 172 * assigned by the system. 173 * 174 * Params: None 175 * 176 * Returns: 177 * OK: socket descriptor 178 * Error: -1 179 */ 180 static int open_socket(void) 181 { 182 int sfd; 183 #if 0 /* see #if 0 just below -VVV- */ 184 int yesplease = 1; 185 #endif 186 struct sockaddr_in local; 187 188 /* 189 * open the socket 190 */ 191 #ifdef COMPILING_ON_WINDOWS 192 if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) 193 return -1; 194 #else 195 if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 196 { 197 # ifdef DEBUG 198 perror("socket"); 199 # endif 200 return -1; 201 } 202 #endif 203 204 /* 205 * 960731 KWelton 206 * 207 * I don't believe that this should be necessary - if we 208 * use select(), then non-blocking I/O is redundant. 209 * Unfortunately, select() appears to be broken (under 210 * Solaris, with a limited amount of time available for 211 * debug), so this code stays in for the time being 212 */ 213 #if 0 214 /* 215 * enable non-blocking I/O 216 */ 217 if (ioctlsocket(sfd, FIONBIO, &yesplease) < 0) 218 { 219 # ifdef DEBUG 220 perror("ioctl(FIONBIO)"); 221 # endif 222 closesocket(sfd); 223 224 return -1; 225 } 226 #endif /* 0/1 */ 227 228 /* 229 * bind local address to a system-assigned port 230 */ 231 memset((char *)&local, 0, sizeof(local)); 232 local.sin_family = AF_INET; 233 local.sin_port = htons(0); 234 local.sin_addr.s_addr = INADDR_ANY; 235 if (bind(sfd, (struct sockaddr *)&local, sizeof(local)) < 0) 236 { 237 #ifdef DEBUG 238 perror("bind"); 239 #endif 240 closesocket(sfd); 241 242 return -1; 243 } 244 245 /* 246 * all done 247 */ 248 return sfd; 249 } 250 251 /* 252 * Function: fetch_ports 253 * Purpose: Request assigned port numbers from remote target 254 * 255 * Params: None 256 * 257 * Returns: Nothing 258 * 259 * Post-conditions: This routine will *always* return something for the 260 * port numbers. If the remote target does not 261 * respond, then it makes something up - this allows 262 * the standard error message (from ardi.c) to be 263 * generated when the target is dead for whatever 264 * reason. 265 */ 266 static void fetch_ports(void) 267 { 268 int i; 269 char ctrlpacket[10]; 270 CtrlResponse response; 271 272 memset (ctrlpacket, 0, 10); 273 strcpy (ctrlpacket, CTRL_MAGIC); 274 memset (response, 0, sizeof(CtrlResponse)); 275 /* 276 * we will try 3 times to elicit a response from the target 277 */ 278 for (i = 0; i < 3; ++i) 279 { 280 struct timeval tv; 281 fd_set fdset; 282 283 /* 284 * send the magic string to the control 285 * port on the remote target 286 */ 287 ia->sin_port = htons(CTRL_PORT); 288 #ifdef DEBUG 289 printf("CTLR_PORT=0x%04x sin_port=0x%04x\n"); 290 #endif 291 292 if (sendto(sock, ctrlpacket, sizeof(ctrlpacket), 0, 293 (struct sockaddr *)ia, sizeof(*ia)) < 0) 294 { 295 #ifdef DEBUG 296 perror("fetch_ports: sendto"); 297 #endif 298 return; 299 } 300 301 FD_ZERO(&fdset); 302 FD_SET(sock, &fdset); 303 tv.tv_sec = 0; 304 tv.tv_usec = 250000; 305 306 if (select(sock + 1, &fdset, NULL, NULL, &tv) < 0) 307 { 308 #ifdef DEBUG 309 perror("fetch_ports: select"); 310 #endif 311 return; 312 } 313 314 if (FD_ISSET(sock, &fdset)) 315 { 316 /* 317 * there is something there - read it 318 */ 319 if (recv(sock, (char *)&response, sizeof(response), 0) < 0) 320 { 321 #ifdef COMPILING_ON_WINDOWS 322 unsigned int werrno = WSAGetLastError(); 323 324 if (werrno == WSAEWOULDBLOCK || werrno == 0) 325 #else 326 if (errno == EWOULDBLOCK) 327 #endif 328 { 329 --i; 330 continue; 331 } 332 else 333 { 334 #ifdef DEBUG 335 perror("fetch_ports: recv"); 336 #endif 337 return; 338 } 339 } 340 { 341 /* 342 * XXX 343 * 344 * this is *very* unpleasant - try to match the structure 345 * layout 346 */ 347 unsigned short *sptr = (unsigned short *)(response + RESP_DBUG); 348 349 if (strcmp(response, ctrlpacket) == 0) 350 { 351 ports[DBUG_INDEX] = htons(*sptr); 352 sptr++; 353 ports[APPL_INDEX] = htons(*sptr); 354 } 355 356 #ifdef DEBUG 357 printf("fetch_ports: got response, DBUG=%d, APPL=%d\n", 358 ports[DBUG_INDEX], ports[APPL_INDEX]); 359 #endif 360 return; 361 } 362 } 363 } 364 365 /* 366 * we failed to get a response 367 */ 368 #ifdef DEBUG 369 printf("fetch_ports: failed to get a real answer\n"); 370 #endif 371 } 372 373 /* 374 * Function: read_packet 375 * Purpose: read a packet, and pass it back to higher levels 376 * 377 * Params: 378 * In/Out: packet Holder for the read packet 379 * 380 * Returns: 1 - Packet is complete 381 * 0 - No complete packet read 382 * 383 * Post-conditions: Will call panic() if something goes wrong with the OS 384 */ 385 static int read_packet(struct data_packet *const packet) 386 { 387 struct sockaddr_in from; 388 int nbytes, fromlen = sizeof(from); 389 DevChanID devchan; 390 391 /* 392 * try to get the packet 393 */ 394 if ((nbytes = recvfrom(sock, (char *)(packet->data), packet->buf_len, 0, 395 (struct sockaddr *)&from, &fromlen)) < 0) 396 { 397 #ifdef COMPILING_ON_WINDOWS 398 if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) 399 MessageBox(GetFocus(), "Error receiving packet\n", "Angel", MB_OK | MB_ICONSTOP); 400 #else 401 if (errno != EWOULDBLOCK) 402 { 403 # ifdef DEBUG 404 perror("recv"); 405 # endif 406 panic("ethernet recv failure"); 407 } 408 #endif 409 return 0; 410 } 411 412 #ifdef COMPILING_ON_WINDOWS 413 if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR) 414 { 415 progressInfo.nRead += nbytes; 416 (*pfnProgressCallback)(&progressInfo); 417 } 418 #endif 419 420 /* 421 * work out where the packet was from 422 */ 423 if (from.sin_addr.s_addr != remote.sin_addr.s_addr) 424 { 425 /* 426 * not from our target - ignore it 427 */ 428 #ifdef DEBUG 429 printf("read_packet: ignoring packet from %s\n", 430 inet_ntoa(from.sin_addr)); 431 #endif 432 433 return 0; 434 } 435 else if (ntohs(from.sin_port) == ports[DBUG_INDEX]) 436 devchan = DC_DBUG; 437 else if (ntohs(from.sin_port) == ports[APPL_INDEX]) 438 devchan = DC_APPL; 439 else 440 { 441 /* 442 * unknown port number - ignore it 443 */ 444 #ifdef DEBUG 445 printf("read_packet: ignore packet from port %hd\n", 446 htons(from.sin_port)); 447 #endif 448 449 return 0; 450 } 451 452 #if defined(DEBUG) && !defined(DO_TRACE) 453 printf("EthernetRead: %d bytes from %s channel\n", 454 nbytes, (devchan == DC_DBUG) ? "DBUG" : "APPL"); 455 #endif 456 457 #ifdef DO_TRACE 458 printf("[%d on %d]\n", nbytes, devchan); 459 { 460 int i = 0; 461 unsigned char *cptr = packet->data; 462 463 while (i < nbytes) 464 { 465 printf("<%02X ", *(cptr++)); 466 467 if (!(++i % 16)) 468 printf("\n"); 469 } 470 471 if (i % 16) 472 printf("\n"); 473 } 474 #endif 475 476 /* 477 * OK - fill in the details 478 */ 479 packet->type = devchan; 480 packet->len = nbytes; 481 return 1; 482 } 483 484 /**********************************************************************/ 485 486 /* 487 * Function: Ethernet_Open 488 * Purpose: Open the Ethernet device. See the documentation for 489 * DeviceOpen in drivers.h 490 * 491 * Post-conditions: Will have updated struct sockaddr_in remote (*ia) 492 * with the address of the remote target. 493 */ 494 static int EthernetOpen(const char *name, const char *arg) 495 { 496 #ifdef COMPILING_ON_WINDOWS 497 WORD wVersionRequested; 498 WSADATA wsaData; 499 #endif 500 /* 501 * name is passed as e=<blah>, so skip 1st two characters 502 */ 503 const char *etheraddr = name + 2; 504 505 #ifdef DEBUG 506 printf("EthernetOpen: name `%s'\n", name); 507 #endif 508 509 /* Check that the name is a valid one */ 510 if (EthernetMatch(name, arg) != 0) 511 return -1; 512 513 #ifdef COMPILING_ON_WINDOWS 514 wVersionRequested = MAKEWORD(1, 1); 515 if (WSAStartup(wVersionRequested, &wsaData) != 0) 516 /* 517 * Couldn't find a useable winsock.dll. 518 */ 519 return -1; 520 521 if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) 522 { 523 WSACleanup(); 524 525 /* 526 * Couldn't find a winsock.dll with supported version. 527 */ 528 return -1; 529 } 530 #endif 531 532 memset((char *)ia, 0, sizeof(*ia)); 533 if (set_address(etheraddr, ia) < 0) 534 { 535 #ifdef COMPILING_ON_WINDOWS 536 /* 537 * SJ - I'm not sure that this is the correct way to handle this 538 * as Fail calls remote_disable and exits, while panic just exits. 539 * However at the time of writing remote_disable does nothing! 540 */ 541 /* Panic("EthernetOpen: bad name `%s'\n", etheraddr); */ 542 #else 543 Fail("EthernetOpen: bad name `%s'\n", etheraddr); 544 #endif 545 return -1; 546 } 547 548 if ((sock = open_socket()) < 0) 549 return -1; 550 551 /* 552 * fetch the port numbers assigned by the remote target 553 * to its Debug and Application sockets 554 */ 555 fetch_ports(); 556 557 return 0; 558 } 559 560 static int EthernetMatch(const char *name, const char *arg) 561 { 562 /* IGNORE arg */ 563 if (0) 564 arg = arg; 565 566 if (name == NULL) 567 return -1; 568 569 if (tolower(name[0]) != 'e' || name[1] != '=') 570 return -1; 571 572 return 0; 573 } 574 575 static void EthernetClose(void) 576 { 577 if (sock >= 0) 578 { 579 closesocket(sock); 580 sock = -1; 581 } 582 583 #ifdef COMPILING_ON_WINDOWS 584 WSACleanup(); 585 #endif 586 } 587 588 static int EthernetRead(DriverCall *dc, bool block) 589 { 590 fd_set fdset; 591 struct timeval tv; 592 int err; 593 594 FD_ZERO(&fdset); 595 FD_SET(sock, &fdset); 596 597 #ifdef COMPILING_ON_WINDOWS 598 UNUSED(block); 599 tv.tv_sec = tv.tv_usec = 0; 600 #else 601 tv.tv_sec = 0; 602 tv.tv_usec = (block ? 10000 : 0); 603 #endif 604 605 err = select(sock + 1, &fdset, NULL, NULL, &tv); 606 607 if (err < 0) { 608 if (errno == EINTR) { 609 return 0; 610 } 611 panic("ethernet select failure (errno=%i)",errno); 612 return 0; 613 } 614 615 if (FD_ISSET(sock, &fdset)) 616 return read_packet(&dc->dc_packet); 617 else 618 return 0; 619 } 620 621 static int EthernetWrite(DriverCall *dc) 622 { 623 int nbytes; 624 struct data_packet *packet = &dc->dc_packet; 625 626 if (packet->type == DC_DBUG) 627 ia->sin_port = htons(ports[DBUG_INDEX]); 628 else if (packet->type == DC_APPL) 629 ia->sin_port = htons(ports[APPL_INDEX]); 630 else 631 { 632 panic("EthernetWrite: unknown devchan"); 633 return 0; 634 } 635 636 #if defined(DEBUG) && !defined(DO_TRACE) 637 printf("EthernetWrite: %d bytes to %s channel\n", 638 packet->len, (packet->type == DC_DBUG) ? "DBUG" : "APPL"); 639 #endif 640 641 #ifdef DO_TRACE 642 printf("[%d on %d]\n", packet->len, packet->type); 643 { 644 int i = 0; 645 unsigned char *cptr = packet->data; 646 647 while (i < packet->len) 648 { 649 printf(">%02X ", *(cptr++)); 650 651 if (!(++i % 16)) 652 printf("\n"); 653 } 654 655 if (i % 16) 656 printf("\n"); 657 } 658 #endif 659 660 if ((nbytes = sendto(sock, (char *)(packet->data), packet->len, 0, 661 (struct sockaddr *)ia, sizeof(*ia))) != packet->len) 662 { 663 #ifdef COMPILING_ON_WINDOWS 664 if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) 665 #else 666 if (nbytes < 0 && errno != EWOULDBLOCK) 667 #endif 668 { 669 #ifdef DEBUG 670 perror("sendto"); 671 #endif 672 673 #ifdef COMPILING_ON_WINDOWS 674 panic("ethernet send failure\n"); 675 #else 676 /* might not work for Windows */ 677 panic("ethernet send failure [%s]\n", 678 #ifdef STDC_HEADERS 679 strerror(errno)); 680 #else 681 errno < sys_nerr ? sys_errlist[errno] : "unknown errno"); 682 #endif /* STDC_HEADERS */ 683 #endif 684 } 685 #ifdef DEBUG 686 else if (nbytes >= 0) 687 fprintf(stderr, "ethernet send: asked for %d, sent %d\n", packet->len, nbytes); 688 #endif 689 return 0; 690 } 691 692 #ifdef COMPILING_ON_WINDOWS 693 if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR) 694 { 695 progressInfo.nWritten += nbytes; 696 (*pfnProgressCallback)(&progressInfo); 697 } 698 #endif 699 700 return 1; 701 } 702 703 static int EthernetIoctl(const int opcode, void *args) 704 { 705 #ifdef DEBUG 706 printf( "EthernetIoctl: op %d arg %x\n", opcode, args ); 707 #endif 708 709 /* 710 * IGNORE(opcode) 711 */ 712 if (0) 713 { 714 int dummy = opcode; 715 UNUSED(dummy); 716 } 717 UNUSED(args); 718 719 switch ( opcode ) 720 { 721 case DC_RESYNC: 722 { 723 #ifdef DEBUG 724 printf( "EthernetIoctl: resync\n" ); 725 #endif 726 fetch_ports(); 727 return 0; 728 } 729 730 default: 731 { 732 return -1; 733 } 734 } 735 } 736 737 /* EOF etherdrv.c */ 738