Mahesh Bandewar | 509e56b | 2019-07-01 14:39:01 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * This module tests the blackhole_dev that is created during the |
| 4 | * net subsystem initialization. The test this module performs is |
| 5 | * by injecting an skb into the stack with skb->dev as the |
| 6 | * blackhole_dev and expects kernel to behave in a sane manner |
| 7 | * (in other words, *not crash*)! |
| 8 | * |
| 9 | * Copyright (c) 2018, Mahesh Bandewar <maheshb@google.com> |
| 10 | */ |
| 11 | |
| 12 | #include <linux/init.h> |
| 13 | #include <linux/module.h> |
| 14 | #include <linux/printk.h> |
| 15 | #include <linux/skbuff.h> |
| 16 | #include <linux/netdevice.h> |
| 17 | #include <linux/udp.h> |
| 18 | #include <linux/ipv6.h> |
| 19 | |
| 20 | #include <net/dst.h> |
| 21 | |
| 22 | #define SKB_SIZE 256 |
| 23 | #define HEAD_SIZE (14+40+8) /* Ether + IPv6 + UDP */ |
| 24 | #define TAIL_SIZE 32 /* random tail-room */ |
| 25 | |
| 26 | #define UDP_PORT 1234 |
| 27 | |
| 28 | static int __init test_blackholedev_init(void) |
| 29 | { |
| 30 | struct ipv6hdr *ip6h; |
| 31 | struct sk_buff *skb; |
| 32 | struct ethhdr *ethh; |
| 33 | struct udphdr *uh; |
| 34 | int data_len; |
| 35 | int ret; |
| 36 | |
| 37 | skb = alloc_skb(SKB_SIZE, GFP_KERNEL); |
| 38 | if (!skb) |
| 39 | return -ENOMEM; |
| 40 | |
| 41 | /* Reserve head-room for the headers */ |
| 42 | skb_reserve(skb, HEAD_SIZE); |
| 43 | |
| 44 | /* Add data to the skb */ |
| 45 | data_len = SKB_SIZE - (HEAD_SIZE + TAIL_SIZE); |
| 46 | memset(__skb_put(skb, data_len), 0xf, data_len); |
| 47 | |
| 48 | /* Add protocol data */ |
| 49 | /* (Transport) UDP */ |
| 50 | uh = (struct udphdr *)skb_push(skb, sizeof(struct udphdr)); |
| 51 | skb_set_transport_header(skb, 0); |
| 52 | uh->source = uh->dest = htons(UDP_PORT); |
| 53 | uh->len = htons(data_len); |
| 54 | uh->check = 0; |
| 55 | /* (Network) IPv6 */ |
| 56 | ip6h = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr)); |
| 57 | skb_set_network_header(skb, 0); |
| 58 | ip6h->hop_limit = 32; |
| 59 | ip6h->payload_len = data_len + sizeof(struct udphdr); |
| 60 | ip6h->nexthdr = IPPROTO_UDP; |
| 61 | ip6h->saddr = in6addr_loopback; |
| 62 | ip6h->daddr = in6addr_loopback; |
| 63 | /* Ether */ |
| 64 | ethh = (struct ethhdr *)skb_push(skb, sizeof(struct ethhdr)); |
| 65 | skb_set_mac_header(skb, 0); |
| 66 | |
| 67 | skb->protocol = htons(ETH_P_IPV6); |
| 68 | skb->pkt_type = PACKET_HOST; |
| 69 | skb->dev = blackhole_netdev; |
| 70 | |
| 71 | /* Now attempt to send the packet */ |
| 72 | ret = dev_queue_xmit(skb); |
| 73 | |
| 74 | switch (ret) { |
| 75 | case NET_XMIT_SUCCESS: |
| 76 | pr_warn("dev_queue_xmit() returned NET_XMIT_SUCCESS\n"); |
| 77 | break; |
| 78 | case NET_XMIT_DROP: |
| 79 | pr_warn("dev_queue_xmit() returned NET_XMIT_DROP\n"); |
| 80 | break; |
| 81 | case NET_XMIT_CN: |
| 82 | pr_warn("dev_queue_xmit() returned NET_XMIT_CN\n"); |
| 83 | break; |
| 84 | default: |
| 85 | pr_err("dev_queue_xmit() returned UNKNOWN(%d)\n", ret); |
| 86 | } |
| 87 | |
| 88 | return 0; |
| 89 | } |
| 90 | |
| 91 | static void __exit test_blackholedev_exit(void) |
| 92 | { |
| 93 | pr_warn("test_blackholedev module terminating.\n"); |
| 94 | } |
| 95 | |
| 96 | module_init(test_blackholedev_init); |
| 97 | module_exit(test_blackholedev_exit); |
| 98 | |
| 99 | MODULE_AUTHOR("Mahesh Bandewar <maheshb@google.com>"); |
| 100 | MODULE_LICENSE("GPL"); |