1 /* 2 * Copyright (C) 2008 Stefan Hajnoczi <stefanha (at) gmail.com>. 3 * 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. 8 * 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. 13 * 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. 17 */ 18 19 #include <stdio.h> 20 #include <string.h> 21 #include <byteswap.h> 22 #include <gpxe/iobuf.h> 23 #include <gpxe/in.h> 24 #include <gpxe/if_arp.h> 25 #include <gpxe/if_ether.h> 26 #include <gpxe/ip.h> 27 #include <gpxe/udp.h> 28 #include <gpxe/netdevice.h> 29 #include <gpxe/nap.h> 30 #include <gpxe/gdbstub.h> 31 #include <gpxe/gdbudp.h> 32 33 /** @file 34 * 35 * GDB over UDP transport 36 * 37 */ 38 39 enum { 40 DEFAULT_PORT = 43770, /* UDP listen port */ 41 }; 42 43 struct gdb_transport udp_gdb_transport __gdb_transport; 44 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; 49 50 static void gdbudp_ensure_netdev_open ( struct net_device *netdev ) { 51 /* The device may have been closed between breakpoints */ 52 assert ( netdev ); 53 netdev_open ( netdev ); 54 55 /* Strictly speaking, we may need to close the device when leaving the interrupt handler */ 56 } 57 58 static size_t gdbudp_recv ( char *buf, size_t len ) { 59 struct io_buffer *iob; 60 struct ethhdr *ethhdr; 61 struct arphdr *arphdr; 62 struct iphdr *iphdr; 63 struct udp_header *udphdr; 64 size_t payload_len; 65 66 gdbudp_ensure_netdev_open ( netdev ); 67 68 for ( ; ; ) { 69 netdev_poll ( netdev ); 70 while ( ( iob = netdev_rx_dequeue ( netdev ) ) != NULL ) { 71 /* Ethernet header */ 72 if ( iob_len ( iob ) < sizeof ( *ethhdr ) ) { 73 goto bad_packet; 74 } 75 ethhdr = iob->data; 76 iob_pull ( iob, sizeof ( *ethhdr ) ); 77 78 /* Handle ARP requests so the client can find our MAC */ 79 if ( ethhdr->h_protocol == htons ( ETH_P_ARP ) ) { 80 arphdr = iob->data; 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 ) { 88 goto bad_packet; 89 } 90 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 ); 96 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 ); 101 102 netdev_tx ( netdev, iob ); 103 continue; /* no need to free iob */ 104 } 105 106 if ( ethhdr->h_protocol != htons ( ETH_P_IP ) ) { 107 goto bad_packet; 108 } 109 110 /* IP header */ 111 if ( iob_len ( iob ) < sizeof ( *iphdr ) ) { 112 goto bad_packet; 113 } 114 iphdr = iob->data; 115 iob_pull ( iob, sizeof ( *iphdr ) ); 116 if ( iphdr->protocol != IP_UDP || iphdr->dest.s_addr != source_addr.sin_addr.s_addr ) { 117 goto bad_packet; 118 } 119 120 /* UDP header */ 121 if ( iob_len ( iob ) < sizeof ( *udphdr ) ) { 122 goto bad_packet; 123 } 124 udphdr = iob->data; 125 if ( udphdr->dest != source_addr.sin_port ) { 126 goto bad_packet; 127 } 128 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; 133 134 /* Payload */ 135 payload_len = ntohs ( udphdr->len ); 136 if ( payload_len < sizeof ( *udphdr ) || payload_len > iob_len ( iob ) ) { 137 goto bad_packet; 138 } 139 payload_len -= sizeof ( *udphdr ); 140 iob_pull ( iob, sizeof ( *udphdr ) ); 141 if ( payload_len > len ) { 142 goto bad_packet; 143 } 144 memcpy ( buf, iob->data, payload_len ); 145 146 free_iob ( iob ); 147 return payload_len; 148 149 bad_packet: 150 free_iob ( iob ); 151 } 152 cpu_nap(); 153 } 154 } 155 156 static void gdbudp_send ( const char *buf, size_t len ) { 157 struct io_buffer *iob; 158 struct ethhdr *ethhdr; 159 struct iphdr *iphdr; 160 struct udp_header *udphdr; 161 162 /* Check that we are connected */ 163 if ( dest_addr.sin_port == 0 ) { 164 return; 165 } 166 167 gdbudp_ensure_netdev_open ( netdev ); 168 169 iob = alloc_iob ( sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) + len ); 170 if ( !iob ) { 171 return; 172 } 173 174 /* Payload */ 175 iob_reserve ( iob, sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) ); 176 memcpy ( iob_put ( iob, len ), buf, len ); 177 178 /* UDP header */ 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 */ 184 185 /* IP header */ 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 ) ); 191 iphdr->ttl = IP_TTL; 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 ) ); 196 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 ); 202 203 netdev_tx ( netdev, iob ); 204 } 205 206 struct gdb_transport *gdbudp_configure ( const char *name, struct sockaddr_in *addr ) { 207 struct settings *settings; 208 209 /* Release old network device */ 210 netdev_put ( netdev ); 211 212 netdev = find_netdev ( name ); 213 if ( !netdev ) { 214 return NULL; 215 } 216 217 /* Hold network device */ 218 netdev_get ( netdev ); 219 220 /* Source UDP port */ 221 source_addr.sin_port = ( addr && addr->sin_port ) ? addr->sin_port : htons ( DEFAULT_PORT ); 222 223 /* Source IP address */ 224 if ( addr && addr->sin_addr.s_addr ) { 225 source_addr.sin_addr.s_addr = addr->sin_addr.s_addr; 226 } else { 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 ); 231 netdev = NULL; 232 return NULL; 233 } 234 } 235 236 return &udp_gdb_transport; 237 } 238 239 static int gdbudp_init ( int argc, char **argv ) { 240 if ( argc != 1 ) { 241 printf ( "udp: missing <interface> argument\n" ); 242 return 1; 243 } 244 245 if ( !gdbudp_configure ( argv[0], NULL ) ) { 246 printf ( "%s: device does not exist or has no IP address\n", argv[0] ); 247 return 1; 248 } 249 return 0; 250 } 251 252 struct gdb_transport udp_gdb_transport __gdb_transport = { 253 .name = "udp", 254 .init = gdbudp_init, 255 .send = gdbudp_send, 256 .recv = gdbudp_recv, 257 }; 258