gdbudp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <byteswap.h>
00022 #include <gpxe/iobuf.h>
00023 #include <gpxe/in.h>
00024 #include <gpxe/if_arp.h>
00025 #include <gpxe/if_ether.h>
00026 #include <gpxe/ip.h>
00027 #include <gpxe/udp.h>
00028 #include <gpxe/netdevice.h>
00029 #include <gpxe/nap.h>
00030 #include <gpxe/gdbstub.h>
00031 #include <gpxe/gdbudp.h>
00032 
00033 /** @file
00034  *
00035  * GDB over UDP transport
00036  *
00037  */
00038 
00039 enum {
00040         DEFAULT_PORT = 43770, /* UDP listen port */
00041 };
00042 
00043 struct gdb_transport udp_gdb_transport __gdb_transport;
00044 
00045 static struct net_device *netdev;
00046 static uint8_t dest_eth[ETH_ALEN];
00047 static struct sockaddr_in dest_addr;
00048 static struct sockaddr_in source_addr;
00049 
00050 static void gdbudp_ensure_netdev_open ( struct net_device *netdev ) {
00051         /* The device may have been closed between breakpoints */
00052         assert ( netdev );
00053         netdev_open ( netdev );
00054 
00055         /* Strictly speaking, we may need to close the device when leaving the interrupt handler */
00056 }
00057 
00058 static size_t gdbudp_recv ( char *buf, size_t len ) {
00059         struct io_buffer *iob;
00060         struct ethhdr *ethhdr;
00061         struct arphdr *arphdr;
00062         struct iphdr *iphdr;
00063         struct udp_header *udphdr;
00064         size_t payload_len;
00065 
00066         gdbudp_ensure_netdev_open ( netdev );
00067 
00068         for ( ; ; ) {
00069                 netdev_poll ( netdev );
00070                 while ( ( iob = netdev_rx_dequeue ( netdev ) ) != NULL ) {
00071                         /* Ethernet header */
00072                         if ( iob_len ( iob ) < sizeof ( *ethhdr ) ) {
00073                                 goto bad_packet;
00074                         }
00075                         ethhdr = iob->data;
00076                         iob_pull ( iob, sizeof ( *ethhdr ) );
00077 
00078                         /* Handle ARP requests so the client can find our MAC */
00079                         if ( ethhdr->h_protocol == htons ( ETH_P_ARP ) ) {
00080                                 arphdr = iob->data;
00081                                 if ( iob_len ( iob ) < sizeof ( *arphdr ) + 2 * ( ETH_ALEN + sizeof ( struct in_addr ) ) ||
00082                                                 arphdr->ar_hrd != htons ( ARPHRD_ETHER ) ||
00083                                                 arphdr->ar_pro != htons ( ETH_P_IP ) ||
00084                                                 arphdr->ar_hln != ETH_ALEN ||
00085                                                 arphdr->ar_pln != sizeof ( struct in_addr ) ||
00086                                                 arphdr->ar_op != htons ( ARPOP_REQUEST ) ||
00087                                                 * ( uint32_t * ) arp_target_pa ( arphdr ) != source_addr.sin_addr.s_addr ) {
00088                                         goto bad_packet;
00089                                 }
00090 
00091                                 /* Generate an ARP reply */
00092                                 arphdr->ar_op = htons ( ARPOP_REPLY );
00093                                 memswap ( arp_sender_pa ( arphdr ), arp_target_pa ( arphdr ), sizeof ( struct in_addr ) );
00094                                 memcpy ( arp_target_ha ( arphdr ), arp_sender_ha ( arphdr ), ETH_ALEN );
00095                                 memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, ETH_ALEN );
00096 
00097                                 /* Fix up ethernet header */
00098                                 ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
00099                                 memcpy ( ethhdr->h_dest, ethhdr->h_source, ETH_ALEN );
00100                                 memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
00101 
00102                                 netdev_tx ( netdev, iob );
00103                                 continue; /* no need to free iob */
00104                         }
00105 
00106                         if ( ethhdr->h_protocol != htons ( ETH_P_IP ) ) {
00107                                 goto bad_packet;
00108                         }
00109 
00110                         /* IP header */
00111                         if ( iob_len ( iob ) < sizeof ( *iphdr ) ) {
00112                                 goto bad_packet;
00113                         }
00114                         iphdr = iob->data;
00115                         iob_pull ( iob, sizeof ( *iphdr ) );
00116                         if ( iphdr->protocol != IP_UDP || iphdr->dest.s_addr != source_addr.sin_addr.s_addr ) {
00117                                 goto bad_packet;
00118                         }
00119 
00120                         /* UDP header */
00121                         if ( iob_len ( iob ) < sizeof ( *udphdr ) ) {
00122                                 goto bad_packet;
00123                         }
00124                         udphdr = iob->data;
00125                         if ( udphdr->dest != source_addr.sin_port ) {
00126                                 goto bad_packet;
00127                         }
00128 
00129                         /* Learn the remote connection details */
00130                         memcpy ( dest_eth, ethhdr->h_source, ETH_ALEN );
00131                         dest_addr.sin_addr.s_addr = iphdr->src.s_addr;
00132                         dest_addr.sin_port = udphdr->src;
00133 
00134                         /* Payload */
00135                         payload_len = ntohs ( udphdr->len );
00136                         if ( payload_len < sizeof ( *udphdr ) || payload_len > iob_len ( iob ) ) {
00137                                 goto bad_packet;
00138                         }
00139                         payload_len -= sizeof ( *udphdr );
00140                         iob_pull ( iob, sizeof ( *udphdr ) );
00141                         if ( payload_len > len ) {
00142                                 goto bad_packet;
00143                         }
00144                         memcpy ( buf, iob->data, payload_len );
00145 
00146                         free_iob ( iob );
00147                         return payload_len;
00148 
00149 bad_packet:
00150                         free_iob ( iob );
00151                 }
00152                 cpu_nap();
00153         }
00154 }
00155 
00156 static void gdbudp_send ( const char *buf, size_t len ) {
00157         struct io_buffer *iob;
00158         struct ethhdr *ethhdr;
00159         struct iphdr *iphdr;
00160         struct udp_header *udphdr;
00161 
00162         /* Check that we are connected */
00163         if ( dest_addr.sin_port == 0 ) {
00164                 return;
00165         }
00166 
00167         gdbudp_ensure_netdev_open ( netdev );
00168 
00169         iob = alloc_iob ( sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) + len );
00170         if ( !iob ) {
00171                 return;
00172         }
00173 
00174         /* Payload */
00175         iob_reserve ( iob, sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) );
00176         memcpy ( iob_put ( iob, len ), buf, len );
00177 
00178         /* UDP header */
00179         udphdr = iob_push ( iob, sizeof ( *udphdr ) );
00180         udphdr->src = source_addr.sin_port;
00181         udphdr->dest = dest_addr.sin_port;
00182         udphdr->len = htons ( iob_len ( iob ) );
00183         udphdr->chksum = 0; /* optional and we are not using it */
00184 
00185         /* IP header */
00186         iphdr = iob_push ( iob, sizeof ( *iphdr ) );
00187         memset ( iphdr, 0, sizeof ( *iphdr ) );
00188         iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
00189         iphdr->service = IP_TOS;
00190         iphdr->len = htons ( iob_len ( iob ) ); 
00191         iphdr->ttl = IP_TTL;
00192         iphdr->protocol = IP_UDP;
00193         iphdr->dest.s_addr = dest_addr.sin_addr.s_addr;
00194         iphdr->src.s_addr = source_addr.sin_addr.s_addr;
00195         iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
00196 
00197         /* Ethernet header */
00198         ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
00199         memcpy ( ethhdr->h_dest, dest_eth, ETH_ALEN );
00200         memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
00201         ethhdr->h_protocol = htons ( ETH_P_IP );
00202 
00203         netdev_tx ( netdev, iob );
00204 }
00205 
00206 struct gdb_transport *gdbudp_configure ( const char *name, struct sockaddr_in *addr ) {
00207         struct settings *settings;
00208 
00209         /* Release old network device */
00210         netdev_put ( netdev );
00211 
00212         netdev = find_netdev ( name );
00213         if ( !netdev ) {
00214                 return NULL;
00215         }
00216 
00217         /* Hold network device */
00218         netdev_get ( netdev );
00219 
00220         /* Source UDP port */
00221         source_addr.sin_port = ( addr && addr->sin_port ) ? addr->sin_port : htons ( DEFAULT_PORT );
00222 
00223         /* Source IP address */
00224         if ( addr && addr->sin_addr.s_addr ) {
00225                 source_addr.sin_addr.s_addr = addr->sin_addr.s_addr;
00226         } else {
00227                 settings = netdev_settings ( netdev );
00228                 fetch_ipv4_setting ( settings, &ip_setting, &source_addr.sin_addr );
00229                 if ( source_addr.sin_addr.s_addr == 0 ) {
00230                         netdev_put ( netdev );
00231                         netdev = NULL;
00232                         return NULL;
00233                 }
00234         }
00235 
00236         return &udp_gdb_transport;
00237 }
00238 
00239 static int gdbudp_init ( int argc, char **argv ) {
00240         if ( argc != 1 ) {
00241                 printf ( "udp: missing <interface> argument\n" );
00242                 return 1;
00243         }
00244 
00245         if ( !gdbudp_configure ( argv[0], NULL ) ) {
00246                 printf ( "%s: device does not exist or has no IP address\n", argv[0] );
00247                 return 1;
00248         }
00249         return 0;
00250 }
00251 
00252 struct gdb_transport udp_gdb_transport __gdb_transport = {
00253         .name = "udp",
00254         .init = gdbudp_init,
00255         .send = gdbudp_send,
00256         .recv = gdbudp_recv,
00257 };

Generated on Tue Apr 6 20:00:51 2010 for gPXE by  doxygen 1.5.7.1