18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This module tests the blackhole_dev that is created during the 48c2ecf20Sopenharmony_ci * net subsystem initialization. The test this module performs is 58c2ecf20Sopenharmony_ci * by injecting an skb into the stack with skb->dev as the 68c2ecf20Sopenharmony_ci * blackhole_dev and expects kernel to behave in a sane manner 78c2ecf20Sopenharmony_ci * (in other words, *not crash*)! 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2018, Mahesh Bandewar <maheshb@google.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/printk.h> 158c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/udp.h> 188c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <net/dst.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SKB_SIZE 256 238c2ecf20Sopenharmony_ci#define HEAD_SIZE (14+40+8) /* Ether + IPv6 + UDP */ 248c2ecf20Sopenharmony_ci#define TAIL_SIZE 32 /* random tail-room */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define UDP_PORT 1234 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int __init test_blackholedev_init(void) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct ipv6hdr *ip6h; 318c2ecf20Sopenharmony_ci struct sk_buff *skb; 328c2ecf20Sopenharmony_ci struct ethhdr *ethh; 338c2ecf20Sopenharmony_ci struct udphdr *uh; 348c2ecf20Sopenharmony_ci int data_len; 358c2ecf20Sopenharmony_ci int ret; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci skb = alloc_skb(SKB_SIZE, GFP_KERNEL); 388c2ecf20Sopenharmony_ci if (!skb) 398c2ecf20Sopenharmony_ci return -ENOMEM; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Reserve head-room for the headers */ 428c2ecf20Sopenharmony_ci skb_reserve(skb, HEAD_SIZE); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Add data to the skb */ 458c2ecf20Sopenharmony_ci data_len = SKB_SIZE - (HEAD_SIZE + TAIL_SIZE); 468c2ecf20Sopenharmony_ci memset(__skb_put(skb, data_len), 0xf, data_len); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Add protocol data */ 498c2ecf20Sopenharmony_ci /* (Transport) UDP */ 508c2ecf20Sopenharmony_ci uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr)); 518c2ecf20Sopenharmony_ci skb_set_transport_header(skb, 0); 528c2ecf20Sopenharmony_ci uh->source = uh->dest = htons(UDP_PORT); 538c2ecf20Sopenharmony_ci uh->len = htons(data_len); 548c2ecf20Sopenharmony_ci uh->check = 0; 558c2ecf20Sopenharmony_ci /* (Network) IPv6 */ 568c2ecf20Sopenharmony_ci ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr)); 578c2ecf20Sopenharmony_ci skb_set_network_header(skb, 0); 588c2ecf20Sopenharmony_ci ip6h->hop_limit = 32; 598c2ecf20Sopenharmony_ci ip6h->payload_len = data_len + sizeof(struct udphdr); 608c2ecf20Sopenharmony_ci ip6h->nexthdr = IPPROTO_UDP; 618c2ecf20Sopenharmony_ci ip6h->saddr = in6addr_loopback; 628c2ecf20Sopenharmony_ci ip6h->daddr = in6addr_loopback; 638c2ecf20Sopenharmony_ci /* Ether */ 648c2ecf20Sopenharmony_ci ethh = (struct ethhdr *)skb_push(skb, sizeof(struct ethhdr)); 658c2ecf20Sopenharmony_ci skb_set_mac_header(skb, 0); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_IPV6); 688c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 698c2ecf20Sopenharmony_ci skb->dev = blackhole_netdev; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* Now attempt to send the packet */ 728c2ecf20Sopenharmony_ci ret = dev_queue_xmit(skb); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci switch (ret) { 758c2ecf20Sopenharmony_ci case NET_XMIT_SUCCESS: 768c2ecf20Sopenharmony_ci pr_warn("dev_queue_xmit() returned NET_XMIT_SUCCESS\n"); 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case NET_XMIT_DROP: 798c2ecf20Sopenharmony_ci pr_warn("dev_queue_xmit() returned NET_XMIT_DROP\n"); 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case NET_XMIT_CN: 828c2ecf20Sopenharmony_ci pr_warn("dev_queue_xmit() returned NET_XMIT_CN\n"); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci default: 858c2ecf20Sopenharmony_ci pr_err("dev_queue_xmit() returned UNKNOWN(%d)\n", ret); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void __exit test_blackholedev_exit(void) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci pr_warn("test_blackholedev module terminating.\n"); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cimodule_init(test_blackholedev_init); 978c2ecf20Sopenharmony_cimodule_exit(test_blackholedev_exit); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mahesh Bandewar <maheshb@google.com>"); 1008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 101