//We need this function in addition to netpoll_wrapper_rx_handler() because pre-3.15 kernel versions //will not call the rx handler for the packets matching the IP/port of our netpoll objects (expecting them //to be handled in rx_hook that we don't use because it provides no way of reading the MAC address). static void hook_receive_skb(void *pContext, struct sk_buff *skb) { int ulen; struct iphdr *iph; struct udphdr *uh; struct netpoll_wrapper *pWrapper = (struct netpoll_wrapper *)pContext; BUG_ON(!pWrapper); if (skb->dev != pWrapper->pDeviceWithHandler) return; if (pWrapper->handle_arp && skb->protocol == htons(ETH_P_ARP)) { netpoll_wrapper_handle_arp(pWrapper, skb); return; } if (!parse_udp_packet(skb, &iph, &uh, &ulen)) return; if (pWrapper->netpoll_obj.local_port && pWrapper->netpoll_obj.local_port == ntohs(uh->dest)) { if ((ip_addr_as_int(pWrapper->netpoll_obj.local_ip) && ip_addr_as_int(pWrapper->netpoll_obj.local_ip) == iph->daddr) || (support_broadcast_packets && iph->daddr == 0xffffffff)) { pWrapper->netpoll_obj.remote_port = ntohs(uh->source); ip_addr_as_int(pWrapper->netpoll_obj.remote_ip) = iph->saddr; memcpy(pWrapper->netpoll_obj.remote_mac, eth_hdr(skb)->h_source, sizeof(pWrapper->netpoll_obj.remote_mac)); if (pWrapper->pReceiveHandler) pWrapper->pReceiveHandler(pWrapper, ntohs(uh->source), (char *)(uh + 1), ulen - sizeof(struct udphdr)); } } }
static void netpoll_wrapper_handle_arp(struct netpoll_wrapper *pWrapper, struct sk_buff *skb) { struct arphdr *arp; unsigned char *arp_ptr; unsigned char *sha; __be32 sip, tip; if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return; skb_reset_network_header(skb); skb_reset_transport_header(skb); arp = arp_hdr(skb); if ((arp->ar_hrd != htons(ARPHRD_ETHER) && arp->ar_hrd != htons(ARPHRD_IEEE802)) || arp->ar_pro != htons(ETH_P_IP) || arp->ar_op != htons(ARPOP_REQUEST)) return; arp_ptr = (unsigned char *)(arp + 1); /* save the location of the src hw addr */ sha = arp_ptr; arp_ptr += skb->dev->addr_len; memcpy(&sip, arp_ptr, 4); arp_ptr += 4; /* If we actually cared about dst hw addr, it would get copied here */ arp_ptr += skb->dev->addr_len; memcpy(&tip, arp_ptr, 4); /* Should we ignore arp? */ if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; if (tip != ip_addr_as_int(pWrapper->netpoll_obj.local_ip)) return; //This ARP request is not for our IP address for (int i = 0; i < ARRAY_SIZE(pWrapper->pending_arp_replies); i++) { if (!pWrapper->pending_arp_replies[i].valid) { pWrapper->pending_arp_replies[i].local_ip = tip; pWrapper->pending_arp_replies[i].remote_ip = sip; memcpy(pWrapper->pending_arp_replies[i].remote_mac, sha, sizeof(pWrapper->pending_arp_replies[i].remote_mac)); pWrapper->pending_arp_replies[i].valid = true; break; } } }
int kgdboe_io_init(const char *device_name, int port, const char *local_ip, bool force_single_core) { int err; u8 ipaddr[4]; spin_lock_init(&exception_lock); s_pKgdboeNetpoll = netpoll_wrapper_create(device_name, port, local_ip); if (!s_pKgdboeNetpoll) return -EINVAL; if (force_single_core) { force_single_cpu_mode(); } else if (!nethook_initialize(s_pKgdboeNetpoll->pDeviceWithHandler)) { printk(KERN_ERR "kgdboe: failed to guarantee cross-CPU network " "API synchronization. Aborting. Try enabling " "single-CPU mode.\n"); return -EINVAL; } err = kgdb_register_io_module(&kgdboe_io_ops); if (err != 0) { netpoll_wrapper_free(s_pKgdboeNetpoll); s_pKgdboeNetpoll = NULL; return err; } netpoll_wrapper_set_callback(s_pKgdboeNetpoll, kgdboe_rx_handler, NULL); memcpy(ipaddr, &ip_addr_as_int(s_pKgdboeNetpoll->netpoll_obj.local_ip), 4); printk(KERN_INFO "kgdboe: Successfully initialized. Use the following " "gdb command to attach:\n"); printk(KERN_INFO "\ttarget remote udp:%d.%d.%d.%d:%d\n", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3], s_pKgdboeNetpoll->netpoll_obj.local_port); return 0; }
//We need this in addition to hook_receive_skb() because not dropping a packet //while stopped in gdb may invoke some processing functions from the network stack that //would like to take resources owned by other cores (that are now stopped). //We don't want to guess and pre-acquire those resources, so we just drop all packets while stopped in kgdb. static rx_handler_result_t netpoll_wrapper_rx_handler(struct sk_buff **pskb) { struct netpoll_wrapper *pWrapper = (struct netpoll_wrapper *)(*pskb)->dev->rx_handler_data; bool drop = false; BUG_ON(!pWrapper); if (pWrapper->drop_other_packets) drop = true; else { int ulen; struct iphdr *iph; struct udphdr *uh; if (parse_udp_packet(*pskb, &iph, &uh, &ulen)) { if (pWrapper->netpoll_obj.local_port && pWrapper->netpoll_obj.local_port == ntohs(uh->dest) && (ip_addr_as_int(pWrapper->netpoll_obj.local_ip) && ip_addr_as_int(pWrapper->netpoll_obj.local_ip) == iph->daddr)) { //Otherwise Linux itself may handle it, reply with ICMP 'port not available' and force GDB to disconnect. drop = true; } } } if (drop) { kfree_skb(*pskb); return RX_HANDLER_CONSUMED; } else return RX_HANDLER_PASS; }