iPXE
Enumerations | Functions | Variables
gdbudp.c File Reference

GDB over UDP transport. More...

#include <stdio.h>
#include <string.h>
#include <byteswap.h>
#include <ipxe/iobuf.h>
#include <ipxe/in.h>
#include <ipxe/if_arp.h>
#include <ipxe/if_ether.h>
#include <ipxe/ip.h>
#include <ipxe/udp.h>
#include <ipxe/netdevice.h>
#include <ipxe/nap.h>
#include <ipxe/gdbstub.h>
#include <ipxe/gdbudp.h>

Go to the source code of this file.

Enumerations

enum  { DEFAULT_PORT = 43770 }

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void gdbudp_ensure_netdev_open (struct net_device *netdev)
static size_t gdbudp_recv (char *buf, size_t len)
static void gdbudp_send (const char *buf, size_t len)
struct gdb_transportgdbudp_configure (const char *name, struct sockaddr_in *addr)
static int gdbudp_init (int argc, char **argv)

Variables

struct gdb_transport
udp_gdb_transport 
__gdb_transport
static struct net_devicenetdev
static uint8_t dest_eth [ETH_ALEN]
static struct sockaddr_in dest_addr
static struct sockaddr_in source_addr

Detailed Description

GDB over UDP transport.

Definition in file gdbudp.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
DEFAULT_PORT 

Definition at line 46 of file gdbudp.c.

     {
        DEFAULT_PORT = 43770, /* UDP listen port */
};

Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void gdbudp_ensure_netdev_open ( struct net_device netdev) [static]

Definition at line 57 of file gdbudp.c.

References assert, and netdev_open().

Referenced by gdbudp_recv(), and gdbudp_send().

                                                                    {
        /* The device may have been closed between breakpoints */
        assert ( netdev );
        netdev_open ( netdev );

        /* Strictly speaking, we may need to close the device when leaving the interrupt handler */
}
static size_t gdbudp_recv ( char *  buf,
size_t  len 
) [static]

Definition at line 65 of file gdbudp.c.

References arphdr::ar_hln, arphdr::ar_hrd, arphdr::ar_op, arphdr::ar_pln, arphdr::ar_pro, arp_sender_ha(), arp_sender_pa(), arp_target_ha(), arp_target_pa(), ARPHRD_ETHER, ARPOP_REPLY, ARPOP_REQUEST, cpu_nap(), io_buffer::data, udp_header::dest, iphdr::dest, dest_addr, dest_eth, ETH_ALEN, ETH_P_ARP, ETH_P_IP, free_iob(), gdbudp_ensure_netdev_open(), ethhdr::h_dest, ethhdr::h_protocol, ethhdr::h_source, htons, iob_len(), iob_pull, iob_push, IP_UDP, udp_header::len, net_device::ll_addr, memcpy(), memswap(), netdev_poll(), netdev_rx_dequeue(), netdev_tx(), ntohs, NULL, iphdr::protocol, in_addr::s_addr, sockaddr_in::sin_addr, sockaddr_in::sin_port, source_addr, udp_header::src, and iphdr::src.

                                                    {
        struct io_buffer *iob;
        struct ethhdr *ethhdr;
        struct arphdr *arphdr;
        struct iphdr *iphdr;
        struct udp_header *udphdr;
        size_t payload_len;

        gdbudp_ensure_netdev_open ( netdev );

        for ( ; ; ) {
                netdev_poll ( netdev );
                while ( ( iob = netdev_rx_dequeue ( netdev ) ) != NULL ) {
                        /* Ethernet header */
                        if ( iob_len ( iob ) < sizeof ( *ethhdr ) ) {
                                goto bad_packet;
                        }
                        ethhdr = iob->data;
                        iob_pull ( iob, sizeof ( *ethhdr ) );

                        /* Handle ARP requests so the client can find our MAC */
                        if ( ethhdr->h_protocol == htons ( ETH_P_ARP ) ) {
                                arphdr = iob->data;
                                if ( iob_len ( iob ) < sizeof ( *arphdr ) + 2 * ( ETH_ALEN + sizeof ( struct in_addr ) ) ||
                                                arphdr->ar_hrd != htons ( ARPHRD_ETHER ) ||
                                                arphdr->ar_pro != htons ( ETH_P_IP ) ||
                                                arphdr->ar_hln != ETH_ALEN ||
                                                arphdr->ar_pln != sizeof ( struct in_addr ) ||
                                                arphdr->ar_op != htons ( ARPOP_REQUEST ) ||
                                                * ( uint32_t * ) arp_target_pa ( arphdr ) != source_addr.sin_addr.s_addr ) {
                                        goto bad_packet;
                                }

                                /* Generate an ARP reply */
                                arphdr->ar_op = htons ( ARPOP_REPLY );
                                memswap ( arp_sender_pa ( arphdr ), arp_target_pa ( arphdr ), sizeof ( struct in_addr ) );
                                memcpy ( arp_target_ha ( arphdr ), arp_sender_ha ( arphdr ), ETH_ALEN );
                                memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, ETH_ALEN );

                                /* Fix up ethernet header */
                                ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
                                memcpy ( ethhdr->h_dest, ethhdr->h_source, ETH_ALEN );
                                memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );

                                netdev_tx ( netdev, iob );
                                continue; /* no need to free iob */
                        }

                        if ( ethhdr->h_protocol != htons ( ETH_P_IP ) ) {
                                goto bad_packet;
                        }

                        /* IP header */
                        if ( iob_len ( iob ) < sizeof ( *iphdr ) ) {
                                goto bad_packet;
                        }
                        iphdr = iob->data;
                        iob_pull ( iob, sizeof ( *iphdr ) );
                        if ( iphdr->protocol != IP_UDP || iphdr->dest.s_addr != source_addr.sin_addr.s_addr ) {
                                goto bad_packet;
                        }

                        /* UDP header */
                        if ( iob_len ( iob ) < sizeof ( *udphdr ) ) {
                                goto bad_packet;
                        }
                        udphdr = iob->data;
                        if ( udphdr->dest != source_addr.sin_port ) {
                                goto bad_packet;
                        }

                        /* Learn the remote connection details */
                        memcpy ( dest_eth, ethhdr->h_source, ETH_ALEN );
                        dest_addr.sin_addr.s_addr = iphdr->src.s_addr;
                        dest_addr.sin_port = udphdr->src;

                        /* Payload */
                        payload_len = ntohs ( udphdr->len );
                        if ( payload_len < sizeof ( *udphdr ) || payload_len > iob_len ( iob ) ) {
                                goto bad_packet;
                        }
                        payload_len -= sizeof ( *udphdr );
                        iob_pull ( iob, sizeof ( *udphdr ) );
                        if ( payload_len > len ) {
                                goto bad_packet;
                        }
                        memcpy ( buf, iob->data, payload_len );

                        free_iob ( iob );
                        return payload_len;

bad_packet:
                        free_iob ( iob );
                }
                cpu_nap();
        }
}
static void gdbudp_send ( const char *  buf,
size_t  len 
) [static]

Definition at line 163 of file gdbudp.c.

References alloc_iob(), udp_header::chksum, iphdr::chksum, udp_header::dest, iphdr::dest, dest_addr, dest_eth, ETH_ALEN, ETH_P_IP, gdbudp_ensure_netdev_open(), ethhdr::h_dest, ethhdr::h_protocol, ethhdr::h_source, htons, iob_len(), iob_push, iob_put, iob_reserve, IP_TOS, IP_TTL, IP_UDP, IP_VER, udp_header::len, iphdr::len, net_device::ll_addr, memcpy(), memset(), netdev_tx(), iphdr::protocol, in_addr::s_addr, iphdr::service, sockaddr_in::sin_addr, sockaddr_in::sin_port, source_addr, udp_header::src, iphdr::src, tcpip_chksum(), iphdr::ttl, and iphdr::verhdrlen.

                                                        {
        struct io_buffer *iob;
        struct ethhdr *ethhdr;
        struct iphdr *iphdr;
        struct udp_header *udphdr;

        /* Check that we are connected */
        if ( dest_addr.sin_port == 0 ) {
                return;
        }

        gdbudp_ensure_netdev_open ( netdev );

        iob = alloc_iob ( sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) + len );
        if ( !iob ) {
                return;
        }

        /* Payload */
        iob_reserve ( iob, sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) );
        memcpy ( iob_put ( iob, len ), buf, len );

        /* UDP header */
        udphdr = iob_push ( iob, sizeof ( *udphdr ) );
        udphdr->src = source_addr.sin_port;
        udphdr->dest = dest_addr.sin_port;
        udphdr->len = htons ( iob_len ( iob ) );
        udphdr->chksum = 0; /* optional and we are not using it */

        /* IP header */
        iphdr = iob_push ( iob, sizeof ( *iphdr ) );
        memset ( iphdr, 0, sizeof ( *iphdr ) );
        iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
        iphdr->service = IP_TOS;
        iphdr->len = htons ( iob_len ( iob ) ); 
        iphdr->ttl = IP_TTL;
        iphdr->protocol = IP_UDP;
        iphdr->dest.s_addr = dest_addr.sin_addr.s_addr;
        iphdr->src.s_addr = source_addr.sin_addr.s_addr;
        iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );

        /* Ethernet header */
        ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
        memcpy ( ethhdr->h_dest, dest_eth, ETH_ALEN );
        memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
        ethhdr->h_protocol = htons ( ETH_P_IP );

        netdev_tx ( netdev, iob );
}
struct gdb_transport* gdbudp_configure ( const char *  name,
struct sockaddr_in addr 
) [read]

Definition at line 213 of file gdbudp.c.

References DEFAULT_PORT, fetch_ipv4_setting(), find_netdev(), htons, netdev_get(), netdev_put(), netdev_settings(), NULL, in_addr::s_addr, sockaddr_in::sin_addr, sockaddr_in::sin_port, and source_addr.

Referenced by gdbudp_init().

                                                                                      {
        struct settings *settings;

        /* Release old network device */
        netdev_put ( netdev );

        netdev = find_netdev ( name );
        if ( !netdev ) {
                return NULL;
        }

        /* Hold network device */
        netdev_get ( netdev );

        /* Source UDP port */
        source_addr.sin_port = ( addr && addr->sin_port ) ? addr->sin_port : htons ( DEFAULT_PORT );

        /* Source IP address */
        if ( addr && addr->sin_addr.s_addr ) {
                source_addr.sin_addr.s_addr = addr->sin_addr.s_addr;
        } else {
                settings = netdev_settings ( netdev );
                fetch_ipv4_setting ( settings, &ip_setting, &source_addr.sin_addr );
                if ( source_addr.sin_addr.s_addr == 0 ) {
                        netdev_put ( netdev );
                        netdev = NULL;
                        return NULL;
                }
        }

        return &udp_gdb_transport;
}
static int gdbudp_init ( int  argc,
char **  argv 
) [static]

Definition at line 246 of file gdbudp.c.

References gdbudp_configure(), NULL, and printf().

                                                 {
        if ( argc != 1 ) {
                printf ( "udp: missing <interface> argument\n" );
                return 1;
        }

        if ( !gdbudp_configure ( argv[0], NULL ) ) {
                printf ( "%s: device does not exist or has no IP address\n", argv[0] );
                return 1;
        }
        return 0;
}

Variable Documentation

struct gdb_transport udp_gdb_transport __gdb_transport
Initial value:
 {
        .name = "udp",
        .init = gdbudp_init,
        .send = gdbudp_send,
        .recv = gdbudp_recv,
}

Definition at line 50 of file gdbudp.c.

struct net_device* netdev [static]

Definition at line 52 of file gdbudp.c.

Referenced by a3c90x_probe(), a3c90x_remove(), alloc_etherdev(), alloc_ipoibdev(), alloc_netdev(), alloc_rndis(), aoe_open(), aoecmd_tx(), aoedev_ata_command(), apply_netdev_settings(), atl1e_check_link(), atl1e_clean_rx_irq(), atl1e_down(), atl1e_probe(), atl1e_remove(), atl1e_up(), autoboot(), axge_check_link(), axge_in_complete(), axge_intr_complete(), axge_out_complete(), axge_probe(), axge_remove(), b44_probe(), b44_remove(), close_all_netdevs(), del_ipv4_miniroute(), dhcp_deliver(), dm96xx_in_complete(), dm96xx_intr_complete(), dm96xx_link_nsr(), dm96xx_out_complete(), dm96xx_probe(), dm96xx_remove(), ecm_in_complete(), ecm_intr_complete(), ecm_out_complete(), ecm_probe(), ecm_remove(), efab_probe(), efab_remove(), efi_pxe_dhcp(), efi_snp_hii_package_list(), efi_snp_load_file(), efi_snp_set_mode(), efi_snp_set_state(), efi_undi_fill_header(), efi_undi_get_init_info(), efi_undi_initialize(), efi_undi_receive(), efi_undi_station_address(), efx_probe(), ena_probe(), ena_remove(), eoib_complete_recv(), eoib_create(), eoib_destroy(), eoib_discard(), eoib_duplicate(), eoib_link_state_changed(), exanic_expired(), exanic_probe_port(), find_netdev(), find_netdev_by_index(), find_netdev_by_ll_addr(), find_netdev_by_location(), flexboot_nodnic_eth_complete_recv(), flexboot_nodnic_eth_complete_send(), flexboot_nodnic_poll_eq(), flexboot_nodnic_register_netdev(), flexboot_nodnic_state_change_netdev(), flexboot_nodnic_unregister_netdev(), forcedeth_probe(), forcedeth_remove(), free_netdev(), free_rndis(), hermon_eth_complete_recv(), hermon_eth_complete_send(), hermon_probe(), hermon_register_netdev(), hermon_state_change_netdev(), hermon_unregister_netdev(), hunt_probe(), hunt_remove(), hunt_set_mac(), ibft_fill_target_nic_association(), ibft_install(), ibft_netdev_is_required(), icplus_probe(), icplus_remove(), ifcommon_exec(), ifec_pci_probe(), ifec_pci_remove(), ifpoller_wait(), igbvf_probe(), igbvf_remove(), igbvf_reset(), intel_probe(), intel_remove(), intelx_probe(), intelx_remove(), intelxl_probe(), intelxl_remove(), intelxvf_probe(), intelxvf_remove(), ipoib_complete_recv(), ipoib_discard_remac(), ipoib_link_state_changed(), ipoib_probe(), ipoib_remove(), ipv4_settings(), ipv6_create_all_routes(), ipv6_dump_miniroute(), ipv6_fetch(), ipv6_sock_aton(), ipv6_sock_ntoa(), jme_alloc_and_feed_iob(), jme_probe(), jme_process_receive(), jme_remove(), jme_tx_clean(), lan78xx_fetch_mac(), lan78xx_probe(), lan78xx_remove(), last_opened_netdev(), last_opened_snpdev(), legacy_irq(), legacy_probe(), legacy_remove(), myri10ge_pci_probe(), myri10ge_pci_remove(), myson_probe(), myson_remove(), natsemi_probe(), natsemi_remove(), ncm_in_complete(), ncm_intr_complete(), ncm_out_complete(), ncm_probe(), ncm_remove(), ndp_fetch(), ndp_prefix_fetch_ip6(), neighbour_destroy(), neighbour_discover(), neighbour_discovered(), neighbour_expired(), net80211_alloc(), net80211_ll_pull(), net_discard(), net_poll(), netdev_config_close(), netdev_fetch(), netdev_get(), netdev_link_block_expired(), netdev_redirect(), netdev_store(), netfront_probe(), netfront_remove(), netvsc_reset(), nii_start(), nii_stop(), nstat(), pcnet32_probe(), pcnet32_remove(), peerdisc_socket_tx(), phantom_probe(), phantom_remove(), pnic_probe(), pnic_remove(), pxe_exec(), pxebs_exec(), pxenv_start_undi(), realtek_probe(), realtek_remove(), register_rndis(), rhine_probe(), rhine_remove(), rndis_describe(), rndis_rx(), rndis_rx_data(), rndis_rx_err(), rndis_rx_message(), rndis_rx_query_oid(), rndis_rx_status(), rndis_tx_complete_err(), rndis_tx_defer(), route(), skeleton_probe(), skeleton_remove(), smsc75xx_in_complete(), smsc75xx_probe(), smsc75xx_remove(), smsc95xx_fetch_mac(), smsc95xx_in_complete(), smsc95xx_probe(), smsc95xx_remove(), smsc95xx_vm3_fetch_mac(), smscusb_eeprom_fetch_mac(), smscusb_intr_complete(), smscusb_mii_check_link(), smscusb_otp_fetch_mac(), smscusb_out_complete(), smscusb_set_address(), smscusb_set_filter(), snpnet_start(), tcpip_mtu(), tg3_remove_one(), txnic_alloc(), txnic_complete_rqe(), txnic_complete_sqe(), txnic_free(), txnic_lmac_probe(), txnic_lmac_update_link(), undinet_probe(), undinet_remove(), unregister_rndis(), vdestroy_exec(), velocity_probe(), velocity_remove(), virtnet_probe_legacy(), virtnet_probe_modern(), vlan_create(), vlan_find(), vlan_notify(), vlan_remove_first(), vlan_rx(), vmxnet3_probe(), vmxnet3_remove(), vxge_irq(), vxge_xmit_compl(), xsmp_tx_xve_params(), xve_close(), xve_open(), and xve_update_mtu().

Definition at line 53 of file gdbudp.c.

Referenced by gdbudp_recv(), and gdbudp_send().

struct sockaddr_in dest_addr [static]

Definition at line 54 of file gdbudp.c.

Referenced by gdbudp_recv(), and gdbudp_send().

struct sockaddr_in source_addr [static]

Definition at line 55 of file gdbudp.c.

Referenced by gdbudp_configure(), gdbudp_recv(), and gdbudp_send().