2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
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
15 * etherdrv.c - Ethernet Driver for Angel.
19 # define _POSIX_SOURCE 1
20 # define _HPUX_SOURCE 1
21 # define _XOPEN_SOURCE 1
26 # define uint hide_HPs_uint
37 # define uint hide_HPs_uint
48 #ifdef COMPILING_ON_WINDOWS
49 typedef char * caddr_t;
52 # include "angeldll.h"
55 # define uint hide_HPs_uint
57 # include <sys/types.h>
58 # include <sys/socket.h>
63 # include <sys/time.h>
64 # include <sys/ioctl.h>
65 # ifdef HAVE_SYS_FILIO_H
66 # include <sys/filio.h>
68 # include <netinet/in.h>
69 # include <arpa/inet.h>
74 #include "angel_endian.h"
82 #if !defined(COMPILING_ON_WINDOWS) && !defined(STDC_HEADERS)
83 /* These two might not work for windows. */
85 extern char * sys_errlist[];
89 # define UNUSED(x) (x = x) /* Silence compiler warnings */
93 * forward declarations of static functions
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);
103 * the device descriptor for Ethernet
105 DeviceDescr angel_EthernetDevice =
117 * descriptor for the socket that we talk down
119 static int sock = -1;
122 * address of the remote target
124 static struct sockaddr_in remote, *ia = &remote;
127 * array of dynamic port numbers on target
129 static unsigned short int ports[2];
132 * Function: set_address
133 * Purpose: Try to get an address into an understandable form
136 * Input: addr The address to parse
138 * Output: ia Structure to hold the parsed address
144 static int set_address(const char *const addr, struct sockaddr_in *const ia)
146 ia->sin_family = AF_INET;
149 * Try address as a dotted decimal
151 ia->sin_addr.s_addr = inet_addr(addr);
154 * If that failed, try it as a hostname
156 if (ia->sin_addr.s_addr == (u_int)-1)
158 struct hostent *hp = gethostbyname(addr);
163 (void)memcpy((caddr_t)&ia->sin_addr, hp->h_addr, hp->h_length);
170 * Function: open_socket
171 * Purpose: Open a non-blocking UDP socket, and bind it to a port
172 * assigned by the system.
177 * OK: socket descriptor
180 static int open_socket(void)
183 #if 0 /* see #if 0 just below -VVV- */
186 struct sockaddr_in local;
191 #ifdef COMPILING_ON_WINDOWS
192 if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
195 if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
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
215 * enable non-blocking I/O
217 if (ioctlsocket(sfd, FIONBIO, &yesplease) < 0)
220 perror("ioctl(FIONBIO)");
229 * bind local address to a system-assigned port
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)
252 * Function: fetch_ports
253 * Purpose: Request assigned port numbers from remote target
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
266 static void fetch_ports(void)
269 const char ctrlpacket[] = CTRL_MAGIC;
270 CtrlResponse response;
273 * we will try 3 times to elicit a response from the target
275 for (i = 0; i < 3; ++i)
281 * send the magic string to the control
282 * port on the remote target
284 ia->sin_port = htons(CTRL_PORT);
286 printf("CTLR_PORT=0x%04x sin_port=0x%04x\n");
289 if (sendto(sock, ctrlpacket, sizeof(ctrlpacket), 0,
290 (struct sockaddr *)ia, sizeof(*ia)) < 0)
293 perror("fetch_ports: sendto");
299 FD_SET(sock, &fdset);
303 if (select(sock + 1, &fdset, NULL, NULL, &tv) < 0)
306 perror("fetch_ports: select");
311 if (FD_ISSET(sock, &fdset))
314 * there is something there - read it
316 if (recv(sock, (char *)&response, sizeof(response), 0) < 0)
318 #ifdef COMPILING_ON_WINDOWS
319 unsigned int werrno = WSAGetLastError();
321 if (werrno == WSAEWOULDBLOCK || werrno == 0)
323 if (errno == EWOULDBLOCK)
332 perror("fetch_ports: recv");
341 * this is *very* unpleasant - try to match the structure
344 unsigned short *sptr = (unsigned short *)(response + RESP_DBUG);
346 if (strcmp(response, ctrlpacket) == 0)
348 ports[DBUG_INDEX] = htons(*sptr);
350 ports[APPL_INDEX] = htons(*sptr);
354 printf("fetch_ports: got response, DBUG=%d, APPL=%d\n",
355 ports[DBUG_INDEX], ports[APPL_INDEX]);
363 * we failed to get a response
366 printf("fetch_ports: failed to get a real answer\n");
371 * Function: read_packet
372 * Purpose: read a packet, and pass it back to higher levels
375 * In/Out: packet Holder for the read packet
377 * Returns: 1 - Packet is complete
378 * 0 - No complete packet read
380 * Post-conditions: Will call panic() if something goes wrong with the OS
382 static int read_packet(struct data_packet *const packet)
384 struct sockaddr_in from;
385 int nbytes, fromlen = sizeof(from);
389 * try to get the packet
391 if ((nbytes = recvfrom(sock, (char *)(packet->data), packet->buf_len, 0,
392 (struct sockaddr *)&from, &fromlen)) < 0)
394 #ifdef COMPILING_ON_WINDOWS
395 if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
396 MessageBox(GetFocus(), "Error receiving packet\n", "Angel", MB_OK | MB_ICONSTOP);
398 if (errno != EWOULDBLOCK)
403 panic("ethernet recv failure");
409 #ifdef COMPILING_ON_WINDOWS
410 if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR)
412 progressInfo.nRead += nbytes;
413 (*pfnProgressCallback)(&progressInfo);
418 * work out where the packet was from
420 if (from.sin_addr.s_addr != remote.sin_addr.s_addr)
423 * not from our target - ignore it
426 printf("read_packet: ignoring packet from %s\n",
427 inet_ntoa(from.sin_addr));
432 else if (ntohs(from.sin_port) == ports[DBUG_INDEX])
434 else if (ntohs(from.sin_port) == ports[APPL_INDEX])
439 * unknown port number - ignore it
442 printf("read_packet: ignore packet from port %hd\n",
443 htons(from.sin_port));
449 #if defined(DEBUG) && !defined(DO_TRACE)
450 printf("EthernetRead: %d bytes from %s channel\n",
451 nbytes, (devchan == DC_DBUG) ? "DBUG" : "APPL");
455 printf("[%d on %d]\n", nbytes, devchan);
458 unsigned char *cptr = packet->data;
462 printf("<%02X ", *(cptr++));
474 * OK - fill in the details
476 packet->type = devchan;
477 packet->len = nbytes;
481 /**********************************************************************/
484 * Function: Ethernet_Open
485 * Purpose: Open the Ethernet device. See the documentation for
486 * DeviceOpen in drivers.h
488 * Post-conditions: Will have updated struct sockaddr_in remote (*ia)
489 * with the address of the remote target.
491 static int EthernetOpen(const char *name, const char *arg)
493 #ifdef COMPILING_ON_WINDOWS
494 WORD wVersionRequested;
498 * name is passed as e=<blah>, so skip 1st two characters
500 const char *etheraddr = name + 2;
503 printf("EthernetOpen: name `%s'\n", name);
506 /* Check that the name is a valid one */
507 if (EthernetMatch(name, arg) != 0)
510 #ifdef COMPILING_ON_WINDOWS
511 wVersionRequested = MAKEWORD(1, 1);
512 if (WSAStartup(wVersionRequested, &wsaData) != 0)
514 * Couldn't find a useable winsock.dll.
518 if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
523 * Couldn't find a winsock.dll with supported version.
529 memset((char *)ia, 0, sizeof(*ia));
530 if (set_address(etheraddr, ia) < 0)
532 #ifdef COMPILING_ON_WINDOWS
534 * SJ - I'm not sure that this is the correct way to handle this
535 * as Fail calls remote_disable and exits, while panic just exits.
536 * However at the time of writing remote_disable does nothing!
538 /* Panic("EthernetOpen: bad name `%s'\n", etheraddr); */
540 Fail("EthernetOpen: bad name `%s'\n", etheraddr);
545 if ((sock = open_socket()) < 0)
549 * fetch the port numbers assigned by the remote target
550 * to its Debug and Application sockets
557 static int EthernetMatch(const char *name, const char *arg)
566 if (tolower(name[0]) != 'e' || name[1] != '=')
572 static void EthernetClose(void)
580 #ifdef COMPILING_ON_WINDOWS
585 static int EthernetRead(DriverCall *dc, bool block)
592 FD_SET(sock, &fdset);
594 #ifdef COMPILING_ON_WINDOWS
596 tv.tv_sec = tv.tv_usec = 0;
599 tv.tv_usec = (block ? 10000 : 0);
602 err = select(sock + 1, &fdset, NULL, NULL, &tv);
605 if (errno == EINTR) {
608 panic("ethernet select failure (errno=%i)",errno);
612 if (FD_ISSET(sock, &fdset))
613 return read_packet(&dc->dc_packet);
618 static int EthernetWrite(DriverCall *dc)
621 struct data_packet *packet = &dc->dc_packet;
623 if (packet->type == DC_DBUG)
624 ia->sin_port = htons(ports[DBUG_INDEX]);
625 else if (packet->type == DC_APPL)
626 ia->sin_port = htons(ports[APPL_INDEX]);
629 panic("EthernetWrite: unknown devchan");
633 #if defined(DEBUG) && !defined(DO_TRACE)
634 printf("EthernetWrite: %d bytes to %s channel\n",
635 packet->len, (packet->type == DC_DBUG) ? "DBUG" : "APPL");
639 printf("[%d on %d]\n", packet->len, packet->type);
642 unsigned char *cptr = packet->data;
644 while (i < packet->len)
646 printf(">%02X ", *(cptr++));
657 if ((nbytes = sendto(sock, (char *)(packet->data), packet->len, 0,
658 (struct sockaddr *)ia, sizeof(*ia))) != packet->len)
660 #ifdef COMPILING_ON_WINDOWS
661 if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
663 if (nbytes < 0 && errno != EWOULDBLOCK)
670 #ifdef COMPILING_ON_WINDOWS
671 panic("ethernet send failure\n");
673 /* might not work for Windows */
674 panic("ethernet send failure [%s]\n",
678 errno < sys_nerr ? sys_errlist[errno] : "unknown errno");
679 #endif /* STDC_HEADERS */
683 else if (nbytes >= 0)
684 fprintf(stderr, "ethernet send: asked for %d, sent %d\n", packet->len, nbytes);
689 #ifdef COMPILING_ON_WINDOWS
690 if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR)
692 progressInfo.nWritten += nbytes;
693 (*pfnProgressCallback)(&progressInfo);
700 static int EthernetIoctl(const int opcode, void *args)
703 printf( "EthernetIoctl: op %d arg %x\n", opcode, args );
721 printf( "EthernetIoctl: resync\n" );