Created
August 10, 2015 06:42
-
-
Save upa/e95c5807500e801ac32d to your computer and use it in GitHub Desktop.
/dev/hiroshi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* /dev/hiroshi */ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/errno.h> | |
#include <linux/fs.h> | |
#include <asm/uaccess.h> | |
#include <linux/netdevice.h> | |
#include <net/dst.h> | |
#include <uapi/linux/if_ether.h> | |
#ifndef DEBUG | |
#define DEBUG | |
#endif | |
#define func_enter() printk ("entering %s\n", __func__); | |
MODULE_AUTHOR ("[email protected]"); | |
MODULE_LICENSE ("GPL"); | |
static int devmajor = 77; | |
static char * devname = "hiroshi"; | |
#define HIROSHI "/dev/hiroshi" | |
inline static int | |
k_atoi (char *str) | |
{ | |
int res = 0, i; | |
for (i = 0; str[i] != '\0'; ++i) | |
res = res*10 + str[i] - '0'; | |
return res; | |
} | |
static int | |
hiroshi_open (struct inode * inode, struct file * fp) | |
{ | |
func_enter (); | |
return 0; | |
} | |
static int | |
hiroshi_release (struct inode * inode, struct file * fp) | |
{ | |
func_enter (); | |
return 0; | |
} | |
static ssize_t | |
hiroshi_read (struct file * fp, char * buf, size_t count, loff_t * ppos) | |
{ | |
func_enter (); | |
return count; | |
} | |
static ssize_t | |
hiroshi_write (struct file * fp, const char __user * buf, size_t count, | |
loff_t * ppos) | |
{ | |
/* build MPLS packet with specified label. | |
* string format is [DEVICE] [LABEL]. | |
* ex) eth0 20 | |
*/ | |
struct net_device * dev; // output device | |
struct sk_buff * skb; | |
struct ethhdr * eth; | |
int n, label; | |
u32 mpls, * mplsh; | |
char kbuf[16]; | |
char * dp, * lp; | |
netdev_tx_t ret; | |
func_enter (); | |
memset (kbuf, 0, sizeof (kbuf)); | |
copy_from_user (kbuf, buf, count < 16 ? count : 16); | |
for (n = 0, dp = kbuf, lp = NULL; n < (count < 16 ? count : 16); n++) { | |
if (kbuf[n] == ' ') { | |
kbuf[n] = '\0'; | |
lp = &(kbuf[n + 1]); | |
kbuf[count - 1] = '\0'; | |
break; | |
} | |
} | |
if (!lp) { | |
printk (KERN_ERR "%s: failed to parse \"%s\"", HIROSHI, kbuf); | |
} | |
label = k_atoi (lp); | |
dev = dev_get_by_name_rcu (get_net_ns_by_pid (1), dp); | |
if (!dev) { | |
printk (KERN_ERR "%s: device %s does is not found", | |
HIROSHI, dp); | |
return count; | |
} | |
skb = netdev_alloc_skb (dev, sizeof (struct ethhdr) + 4); | |
if (!skb) { | |
printk (KERN_ERR "%s: failed to alloc akb.\n", HIROSHI); | |
} | |
skb_put (skb, sizeof (struct ethhdr) + 4); | |
skb_reset_mac_header (skb); | |
/* setup ether header */ | |
eth = (struct ethhdr *) skb->data; | |
eth->h_source[0] = 0x01; | |
eth->h_source[1] = 0x01; | |
eth->h_source[2] = 0x01; | |
eth->h_source[3] = 0x01; | |
eth->h_source[4] = 0x01; | |
eth->h_source[5] = 0x01; | |
eth->h_dest[0] = 0x01; | |
eth->h_dest[1] = 0x01; | |
eth->h_dest[2] = 0x01; | |
eth->h_dest[3] = 0x02; | |
eth->h_dest[4] = 0x02; | |
eth->h_dest[5] = 0x02; | |
eth->h_proto = htons (ETH_P_MPLS_UC); | |
/* setup mpls header */ | |
skb_reset_network_header (skb); | |
mpls = 0; | |
mpls = label; | |
mpls <<= 12; /* set label */ | |
mpls |= 0x00F; /* exp 0 stack 0, 16 hop */ | |
mplsh = (u32 *) (eth + 1); | |
*mplsh = htonl (mpls); | |
skb->dev = dev; | |
skb_dst_drop (skb); | |
//ret = dev->netdev_ops->ndo_start_xmit (skb, dev); | |
ret = dev_queue_xmit (skb); | |
if (ret != NETDEV_TX_OK) { | |
printk (KERN_ERR "%s: failed to xmit mpls pakcet\n", HIROSHI); | |
} else { | |
printk (KERN_INFO | |
"%s: send packet label %u success via %s %s\n", | |
HIROSHI, label, dp, lp); | |
} | |
return count; | |
} | |
static struct file_operations hiroshi_fops = { | |
.owner = THIS_MODULE, | |
.read = hiroshi_read, | |
.write = hiroshi_write, | |
.open = hiroshi_open, | |
.release = hiroshi_release, | |
}; | |
static int | |
__init hiroshi_init_module (void) | |
{ | |
int ret; | |
ret = register_chrdev (devmajor, devname, &hiroshi_fops); | |
if (ret) { | |
printk (KERN_ERR "%s: failed to register /dev/hiroshi\n", | |
HIROSHI); | |
return -1; | |
} | |
printk (KERN_INFO "%s loaded.\n", HIROSHI); | |
return 0; | |
} | |
module_init (hiroshi_init_module); | |
static void | |
__exit hiroshi_exit_module (void) | |
{ | |
unregister_chrdev (devmajor, devname); | |
printk (KERN_INFO "%s unloaded.\n", HIROSHI); | |
return; | |
} | |
module_exit (hiroshi_exit_module); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment