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)
270 CtrlResponse response
;
272 memset (ctrlpacket
, 0, 10);
273 strcpy (ctrlpacket
, CTRL_MAGIC
);
274 memset (response
, 0, sizeof(CtrlResponse
));
276 * we will try 3 times to elicit a response from the target
278 for (i
= 0; i
< 3; ++i
)
284 * send the magic string to the control
285 * port on the remote target
287 ia
->sin_port
= htons(CTRL_PORT
);
289 printf("CTLR_PORT=0x%04x sin_port=0x%04x\n");
292 if (sendto(sock
, ctrlpacket
, sizeof(ctrlpacket
), 0,
293 (struct sockaddr
*)ia
, sizeof(*ia
)) < 0)
296 perror("fetch_ports: sendto");
302 FD_SET(sock
, &fdset
);
306 if (select(sock
+ 1, &fdset
, NULL
, NULL
, &tv
) < 0)
309 perror("fetch_ports: select");
314 if (FD_ISSET(sock
, &fdset
))
317 * there is something there - read it
319 if (recv(sock
, (char *)&response
, sizeof(response
), 0) < 0)
321 #ifdef COMPILING_ON_WINDOWS
322 unsigned int werrno
= WSAGetLastError();
324 if (werrno
== WSAEWOULDBLOCK
|| werrno
== 0)
326 if (errno
== EWOULDBLOCK
)
335 perror("fetch_ports: recv");
344 * this is *very* unpleasant - try to match the structure
347 unsigned short *sptr
= (unsigned short *)(response
+ RESP_DBUG
);
349 if (strcmp(response
, ctrlpacket
) == 0)
351 ports
[DBUG_INDEX
] = htons(*sptr
);
353 ports
[APPL_INDEX
] = htons(*sptr
);
357 printf("fetch_ports: got response, DBUG=%d, APPL=%d\n",
358 ports
[DBUG_INDEX
], ports
[APPL_INDEX
]);
366 * we failed to get a response
369 printf("fetch_ports: failed to get a real answer\n");
374 * Function: read_packet
375 * Purpose: read a packet, and pass it back to higher levels
378 * In/Out: packet Holder for the read packet
380 * Returns: 1 - Packet is complete
381 * 0 - No complete packet read
383 * Post-conditions: Will call panic() if something goes wrong with the OS
385 static int read_packet(struct data_packet
*const packet
)
387 struct sockaddr_in from
;
388 int nbytes
, fromlen
= sizeof(from
);
392 * try to get the packet
394 if ((nbytes
= recvfrom(sock
, (char *)(packet
->data
), packet
->buf_len
, 0,
395 (struct sockaddr
*)&from
, &fromlen
)) < 0)
397 #ifdef COMPILING_ON_WINDOWS
398 if (nbytes
== SOCKET_ERROR
&& WSAGetLastError() != WSAEWOULDBLOCK
)
399 MessageBox(GetFocus(), "Error receiving packet\n", "Angel", MB_OK
| MB_ICONSTOP
);
401 if (errno
!= EWOULDBLOCK
)
406 panic("ethernet recv failure");
412 #ifdef COMPILING_ON_WINDOWS
413 if (pfnProgressCallback
!= NULL
&& nbytes
!= SOCKET_ERROR
)
415 progressInfo
.nRead
+= nbytes
;
416 (*pfnProgressCallback
)(&progressInfo
);
421 * work out where the packet was from
423 if (from
.sin_addr
.s_addr
!= remote
.sin_addr
.s_addr
)
426 * not from our target - ignore it
429 printf("read_packet: ignoring packet from %s\n",
430 inet_ntoa(from
.sin_addr
));
435 else if (ntohs(from
.sin_port
) == ports
[DBUG_INDEX
])
437 else if (ntohs(from
.sin_port
) == ports
[APPL_INDEX
])
442 * unknown port number - ignore it
445 printf("read_packet: ignore packet from port %hd\n",
446 htons(from
.sin_port
));
452 #if defined(DEBUG) && !defined(DO_TRACE)
453 printf("EthernetRead: %d bytes from %s channel\n",
454 nbytes
, (devchan
== DC_DBUG
) ? "DBUG" : "APPL");
458 printf("[%d on %d]\n", nbytes
, devchan
);
461 unsigned char *cptr
= packet
->data
;
465 printf("<%02X ", *(cptr
++));
477 * OK - fill in the details
479 packet
->type
= devchan
;
480 packet
->len
= nbytes
;
484 /**********************************************************************/
487 * Function: Ethernet_Open
488 * Purpose: Open the Ethernet device. See the documentation for
489 * DeviceOpen in drivers.h
491 * Post-conditions: Will have updated struct sockaddr_in remote (*ia)
492 * with the address of the remote target.
494 static int EthernetOpen(const char *name
, const char *arg
)
496 #ifdef COMPILING_ON_WINDOWS
497 WORD wVersionRequested
;
501 * name is passed as e=<blah>, so skip 1st two characters
503 const char *etheraddr
= name
+ 2;
506 printf("EthernetOpen: name `%s'\n", name
);
509 /* Check that the name is a valid one */
510 if (EthernetMatch(name
, arg
) != 0)
513 #ifdef COMPILING_ON_WINDOWS
514 wVersionRequested
= MAKEWORD(1, 1);
515 if (WSAStartup(wVersionRequested
, &wsaData
) != 0)
517 * Couldn't find a useable winsock.dll.
521 if ( LOBYTE( wsaData
.wVersion
) != 1 || HIBYTE( wsaData
.wVersion
) != 1 )
526 * Couldn't find a winsock.dll with supported version.
532 memset((char *)ia
, 0, sizeof(*ia
));
533 if (set_address(etheraddr
, ia
) < 0)
535 #ifdef COMPILING_ON_WINDOWS
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!
541 /* Panic("EthernetOpen: bad name `%s'\n", etheraddr); */
543 Fail("EthernetOpen: bad name `%s'\n", etheraddr
);
548 if ((sock
= open_socket()) < 0)
552 * fetch the port numbers assigned by the remote target
553 * to its Debug and Application sockets
560 static int EthernetMatch(const char *name
, const char *arg
)
569 if (tolower(name
[0]) != 'e' || name
[1] != '=')
575 static void EthernetClose(void)
583 #ifdef COMPILING_ON_WINDOWS
588 static int EthernetRead(DriverCall
*dc
, bool block
)
595 FD_SET(sock
, &fdset
);
597 #ifdef COMPILING_ON_WINDOWS
599 tv
.tv_sec
= tv
.tv_usec
= 0;
602 tv
.tv_usec
= (block
? 10000 : 0);
605 err
= select(sock
+ 1, &fdset
, NULL
, NULL
, &tv
);
608 if (errno
== EINTR
) {
611 panic("ethernet select failure (errno=%i)",errno
);
615 if (FD_ISSET(sock
, &fdset
))
616 return read_packet(&dc
->dc_packet
);
621 static int EthernetWrite(DriverCall
*dc
)
624 struct data_packet
*packet
= &dc
->dc_packet
;
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
]);
632 panic("EthernetWrite: unknown devchan");
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");
642 printf("[%d on %d]\n", packet
->len
, packet
->type
);
645 unsigned char *cptr
= packet
->data
;
647 while (i
< packet
->len
)
649 printf(">%02X ", *(cptr
++));
660 if ((nbytes
= sendto(sock
, (char *)(packet
->data
), packet
->len
, 0,
661 (struct sockaddr
*)ia
, sizeof(*ia
))) != packet
->len
)
663 #ifdef COMPILING_ON_WINDOWS
664 if (nbytes
== SOCKET_ERROR
&& WSAGetLastError() != WSAEWOULDBLOCK
)
666 if (nbytes
< 0 && errno
!= EWOULDBLOCK
)
673 #ifdef COMPILING_ON_WINDOWS
674 panic("ethernet send failure\n");
676 /* might not work for Windows */
677 panic("ethernet send failure [%s]\n",
681 errno
< sys_nerr
? sys_errlist
[errno
] : "unknown errno");
682 #endif /* STDC_HEADERS */
686 else if (nbytes
>= 0)
687 fprintf(stderr
, "ethernet send: asked for %d, sent %d\n", packet
->len
, nbytes
);
692 #ifdef COMPILING_ON_WINDOWS
693 if (pfnProgressCallback
!= NULL
&& nbytes
!= SOCKET_ERROR
)
695 progressInfo
.nWritten
+= nbytes
;
696 (*pfnProgressCallback
)(&progressInfo
);
703 static int EthernetIoctl(const int opcode
, void *args
)
706 printf( "EthernetIoctl: op %d arg %x\n", opcode
, args
);
724 printf( "EthernetIoctl: resync\n" );