2 * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <gpxe/iobuf.h>
24 #include <gpxe/if_arp.h>
25 #include <gpxe/if_ether.h>
28 #include <gpxe/netdevice.h>
30 #include <gpxe/gdbstub.h>
31 #include <gpxe/gdbudp.h>
35 * GDB over UDP transport
40 DEFAULT_PORT
= 43770, /* UDP listen port */
43 struct gdb_transport udp_gdb_transport __gdb_transport
;
45 static struct net_device
*netdev
;
46 static uint8_t dest_eth
[ETH_ALEN
];
47 static struct sockaddr_in dest_addr
;
48 static struct sockaddr_in source_addr
;
50 static void gdbudp_ensure_netdev_open ( struct net_device
*netdev
) {
51 /* The device may have been closed between breakpoints */
53 netdev_open ( netdev
);
55 /* Strictly speaking, we may need to close the device when leaving the interrupt handler */
58 static size_t gdbudp_recv ( char *buf
, size_t len
) {
59 struct io_buffer
*iob
;
60 struct ethhdr
*ethhdr
;
61 struct arphdr
*arphdr
;
63 struct udp_header
*udphdr
;
66 gdbudp_ensure_netdev_open ( netdev
);
69 netdev_poll ( netdev
);
70 while ( ( iob
= netdev_rx_dequeue ( netdev
) ) != NULL
) {
72 if ( iob_len ( iob
) < sizeof ( *ethhdr
) ) {
76 iob_pull ( iob
, sizeof ( *ethhdr
) );
78 /* Handle ARP requests so the client can find our MAC */
79 if ( ethhdr
->h_protocol
== htons ( ETH_P_ARP
) ) {
81 if ( iob_len ( iob
) < sizeof ( *arphdr
) + 2 * ( ETH_ALEN
+ sizeof ( struct in_addr
) ) ||
82 arphdr
->ar_hrd
!= htons ( ARPHRD_ETHER
) ||
83 arphdr
->ar_pro
!= htons ( ETH_P_IP
) ||
84 arphdr
->ar_hln
!= ETH_ALEN
||
85 arphdr
->ar_pln
!= sizeof ( struct in_addr
) ||
86 arphdr
->ar_op
!= htons ( ARPOP_REQUEST
) ||
87 * ( uint32_t * ) arp_target_pa ( arphdr
) != source_addr
.sin_addr
.s_addr
) {
91 /* Generate an ARP reply */
92 arphdr
->ar_op
= htons ( ARPOP_REPLY
);
93 memswap ( arp_sender_pa ( arphdr
), arp_target_pa ( arphdr
), sizeof ( struct in_addr
) );
94 memcpy ( arp_target_ha ( arphdr
), arp_sender_ha ( arphdr
), ETH_ALEN
);
95 memcpy ( arp_sender_ha ( arphdr
), netdev
->ll_addr
, ETH_ALEN
);
97 /* Fix up ethernet header */
98 ethhdr
= iob_push ( iob
, sizeof ( *ethhdr
) );
99 memcpy ( ethhdr
->h_dest
, ethhdr
->h_source
, ETH_ALEN
);
100 memcpy ( ethhdr
->h_source
, netdev
->ll_addr
, ETH_ALEN
);
102 netdev_tx ( netdev
, iob
);
103 continue; /* no need to free iob */
106 if ( ethhdr
->h_protocol
!= htons ( ETH_P_IP
) ) {
111 if ( iob_len ( iob
) < sizeof ( *iphdr
) ) {
115 iob_pull ( iob
, sizeof ( *iphdr
) );
116 if ( iphdr
->protocol
!= IP_UDP
|| iphdr
->dest
.s_addr
!= source_addr
.sin_addr
.s_addr
) {
121 if ( iob_len ( iob
) < sizeof ( *udphdr
) ) {
125 if ( udphdr
->dest
!= source_addr
.sin_port
) {
129 /* Learn the remote connection details */
130 memcpy ( dest_eth
, ethhdr
->h_source
, ETH_ALEN
);
131 dest_addr
.sin_addr
.s_addr
= iphdr
->src
.s_addr
;
132 dest_addr
.sin_port
= udphdr
->src
;
135 payload_len
= ntohs ( udphdr
->len
);
136 if ( payload_len
< sizeof ( *udphdr
) || payload_len
> iob_len ( iob
) ) {
139 payload_len
-= sizeof ( *udphdr
);
140 iob_pull ( iob
, sizeof ( *udphdr
) );
141 if ( payload_len
> len
) {
144 memcpy ( buf
, iob
->data
, payload_len
);
156 static void gdbudp_send ( const char *buf
, size_t len
) {
157 struct io_buffer
*iob
;
158 struct ethhdr
*ethhdr
;
160 struct udp_header
*udphdr
;
162 /* Check that we are connected */
163 if ( dest_addr
.sin_port
== 0 ) {
167 gdbudp_ensure_netdev_open ( netdev
);
169 iob
= alloc_iob ( sizeof ( *ethhdr
) + sizeof ( *iphdr
) + sizeof ( *udphdr
) + len
);
175 iob_reserve ( iob
, sizeof ( *ethhdr
) + sizeof ( *iphdr
) + sizeof ( *udphdr
) );
176 memcpy ( iob_put ( iob
, len
), buf
, len
);
179 udphdr
= iob_push ( iob
, sizeof ( *udphdr
) );
180 udphdr
->src
= source_addr
.sin_port
;
181 udphdr
->dest
= dest_addr
.sin_port
;
182 udphdr
->len
= htons ( iob_len ( iob
) );
183 udphdr
->chksum
= 0; /* optional and we are not using it */
186 iphdr
= iob_push ( iob
, sizeof ( *iphdr
) );
187 memset ( iphdr
, 0, sizeof ( *iphdr
) );
188 iphdr
->verhdrlen
= ( IP_VER
| ( sizeof ( *iphdr
) / 4 ) );
189 iphdr
->service
= IP_TOS
;
190 iphdr
->len
= htons ( iob_len ( iob
) );
192 iphdr
->protocol
= IP_UDP
;
193 iphdr
->dest
.s_addr
= dest_addr
.sin_addr
.s_addr
;
194 iphdr
->src
.s_addr
= source_addr
.sin_addr
.s_addr
;
195 iphdr
->chksum
= tcpip_chksum ( iphdr
, sizeof ( *iphdr
) );
197 /* Ethernet header */
198 ethhdr
= iob_push ( iob
, sizeof ( *ethhdr
) );
199 memcpy ( ethhdr
->h_dest
, dest_eth
, ETH_ALEN
);
200 memcpy ( ethhdr
->h_source
, netdev
->ll_addr
, ETH_ALEN
);
201 ethhdr
->h_protocol
= htons ( ETH_P_IP
);
203 netdev_tx ( netdev
, iob
);
206 struct gdb_transport
*gdbudp_configure ( const char *name
, struct sockaddr_in
*addr
) {
207 struct settings
*settings
;
209 /* Release old network device */
210 netdev_put ( netdev
);
212 netdev
= find_netdev ( name
);
217 /* Hold network device */
218 netdev_get ( netdev
);
220 /* Source UDP port */
221 source_addr
.sin_port
= ( addr
&& addr
->sin_port
) ? addr
->sin_port
: htons ( DEFAULT_PORT
);
223 /* Source IP address */
224 if ( addr
&& addr
->sin_addr
.s_addr
) {
225 source_addr
.sin_addr
.s_addr
= addr
->sin_addr
.s_addr
;
227 settings
= netdev_settings ( netdev
);
228 fetch_ipv4_setting ( settings
, &ip_setting
, &source_addr
.sin_addr
);
229 if ( source_addr
.sin_addr
.s_addr
== 0 ) {
230 netdev_put ( netdev
);
236 return &udp_gdb_transport
;
239 static int gdbudp_init ( int argc
, char **argv
) {
241 printf ( "udp: missing <interface> argument\n" );
245 if ( !gdbudp_configure ( argv
[0], NULL
) ) {
246 printf ( "%s: device does not exist or has no IP address\n", argv
[0] );
252 struct gdb_transport udp_gdb_transport __gdb_transport
= {