Getting list of network devices inside the Linux kernel - linux

I've been looking through net/core/dev.c and other files to try to find out how to get the list of network devices that are currently configured and it's proving to be a little difficult to find.
The end goal is to be able to get network device statistics using dev_get_stats in dev.c, but I need to know the current interfaces so I can grab the net_device struct to pass in. I'm having to do this inside the kernel as I'm writing a module which adds in a new /proc/ entry which relates to some statistics from the current network devices so from what I can gather this must be done inside the kernel.
If someone could point me to how to get the interfaces it would be much appreciated.

This ought to do the trick:
#include <linux/netdevice.h>
struct net_device *dev;
read_lock(&dev_base_lock);
dev = first_net_device(&init_net);
while (dev) {
printk(KERN_INFO "found [%s]\n", dev->name);
dev = next_net_device(dev);
}
read_unlock(&dev_base_lock);

Given a struct net *net identifying the net namespace that you are interested in, you should grab the dev_base_lock and use for_each_netdev():
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
/* Inspect dev */
}
read_unlock(&dev_base_lock);
(In newer kernels, you can use RCU instead, but that is probably an overcomplication in this case).
To obtain the net namespace to use, you should be registering your proc file with register_pernet_subsys():
static const struct file_operations foostats_seq_fops = {
.owner = THIS_MODULE,
.open = foostats_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = foostats_seq_release,
};
static int foo_proc_init_net(struct net *net)
{
if (!proc_net_fops_create(net, "foostats", S_IRUGO,
&foostats_seq_fops))
return -ENOMEM;
return 0;
}
static void foo_proc_exit_net(struct net *net)
{
proc_net_remove(net, "foostats");
}
static struct pernet_operations foo_proc_ops = {
.init = foo_proc_init_net,
.exit = foo_proc_exit_net,
};
register_pernet_subsys(&foo_proc_ops)
In your foostats_seq_open() function, you take a reference on the net namespace, and drop it in the release function:
static int foostats_seq_open(struct inode *inode, struct file *file)
{
int err;
struct net *net;
err = -ENXIO;
net = get_proc_net(inode);
if (net == NULL)
goto err_net;
err = single_open(file, foostats_seq_show, net);
if (err < 0)
goto err_open;
return 0;
err_open:
put_net(net);
err_net:
return err;
}
static int foostats_seq_release(struct inode *inode, struct file *file)
{
struct net *net = ((struct seq_file *)file->private_data)->private;
put_net(net);
return single_release(inode, file);
}
The foostats_seq_show() function can then obtain the net, walk the devices, gather the statistics and produce the output:
static int sockstat6_seq_show(struct seq_file *seq, void *v)
{
struct net *net = seq->private;
struct net_device *dev;
int foostat, barstat;
read_lock(&dev_base_lock);
for_each_netdev(net, dev) {
/* Inspect dev */
}
read_unlock(&dev_base_lock);
seq_printf(seq, "Foo: %d\n", foostat);
seq_printf(seq, "Bar: %d\n", barstat);
return 0;
}

Related

how to get struct device's private data in the Linux's chrdev ->open() function?

I'm a beginnig learner of linux driver, so far I've studied how to write an basic char device driver and platform driver. I'm pricticing on the led example, I want to improve it from basic char device driver model to platform driver model.
In the earlier practice, I define a global int gpio_num[MAX_LED_NUM] array to keep the led's gpio. It's easy because I can indentify the led by device's minor number, and operate the corresponding led by referencing gpio_num[minor];
But in this improvement, I don't want to use global array to keep led's gpio because I can't predict how many leds on the board. So I malloc a structure for every platform device in the probe function to keep their own gpio, and call device_create() to create device node. It seems good so far because how many leds are there, there are how many structures and device nodes in the /dev directory, and there is no global variables.
In order to seperate led operation functions from char device driver, I define the led operaions functions in the platform driver part(driver.c) and pass the function sets to the char device driver part(leds.c). for example , I define the alpha_led_init(struct drv_priv *priv) in the driver.c, and call it from char device's open function(in leds.c) .
in order to call alpha_led_init(struct drv_priv *priv), the open function needs the parameter *priv(the private data of platform device which contains led_gpio). I've pass the private data to the char device by using device_create()'s third parameter. But how can I get it from the open function ? I can't get the struct device *pdev in the open function, so I can't call dev_get_drvdata(pdev) to get the platform device's private data , so there's no way to call alpha_led_init(struct drv_priv *priv).
Is my program model very bad? Any good way to pass platform device's private data to char device ? Any help or advice would be appreciating.
Below is my practicing code, for simplicity, some header files're omitted.
alpha_led.h
#ifndef __ALPHA_LED_H__
#define __ALPHA_LED_H__
#define LED_OFF (1)
#define LED_ON (0)
#define LED_MAX_NUM (10)
struct drv_priv
{
int led_gpio;
};
struct alpha_led_operations
{
int inited;
int (*alpha_led_init)(struct drv_priv *pdev);
};
#endif
driver.c
#include "alpha_led.h"
static int led_count;
static int alpha_led_init(struct drv_priv *priv)
{
int err;
char name[64];
if(!priv)
return -1;
memset(name, 0, sizeof(name));
snprintf(name, sizeof(name), "alpha-led-pin-%d", priv->led_gpio);
err = gpio_request(priv->led_gpio, name);
if(err)
return -1;
err = gpio_direction_output(priv->led_gpio, LED_OFF);
if(err) {
gpio_free(priv->led_gpio);
return -1;
}
return 0;
}
static int alpha_led_probe(struct platform_device *pdev)
{
int err, gpio;
const char *status = NULL;
struct drv_priv *priv = NULL;
struct device_node *np = pdev->dev.of_node;
if(!np)
return -1;
err = of_property_read_string(np, "status", &status);
if(err || (strcmp(status, "okay") != 0))
return -1;
gpio = of_get_named_gpio(np, "led-gpio", 0);
if(gpio < 0)
return -1;
// I malloc a drv_priv structure for every platform device to keep their private data
priv = devm_kzalloc(&pdev->dev, sizeof(struct drv_priv), GFP_KERNEL);
if(!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
// for every platform device, the gpio number is their private data.
priv->led_gpio = gpio;
// I call self-defined function in leds.c to create device node in /dev directory
// and pass the platform device's private data(priv) to the device_create()
return create_led_device_node(led_count++, np->name, priv);
}
static int alpha_led_remove(struct platform_device *pdev)
{
// get the platform device's private data
struct drv_priv *priv = platform_get_drvdata(pdev);
gpio_free(priv->led_gpio);
}
static const struct of_device_id alpha_led_of_match[] = {
{ .compatible = "alientek-alpha,led" },
{}
};
static struct platform_driver alpha_led_driver = {
.probe = alpha_led_probe,
.remove = alpha_led_remove,
.driver = {
.name = "alpha-led",
.of_match_table = alpha_led_of_match,
}
};
static int __init platform_driver_led_init(void)
{
int rc;
struct alpha_led_operations *ops;
rc = platform_driver_register(&alpha_led_driver);
// pass the lower led control functions to leds.c
ops = get_alpha_led_ops();
ops->alpha_led_init = alpha_led_init;
ops->inited = 1;
return 0;
}
static void __exit platform_driver_led_exit(void)
{
platform_driver_unregister(&alpha_led_driver);
}
module_init(platform_driver_led_init);
module_exit(platform_driver_led_exit);
MODULE_AUTHOR("David");
MODULE_LICENSE("GPL");
leds.c
#include "alpha_led.h"
#define LED_DEV_NAME ("alpha-led")
#define LED_CLASS_NAME ("alpha-led-class")
static int led_major;
static struct cdev led_cdev;
static struct class *led_class;
static int led_open(struct inode *inode, struct file *filp);
static int led_close(struct inode *inode, struct file *filp);
static struct alpha_led_operations alpha_led_ops;
static const struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_close,
};
static int led_open(struct inode *inode, struct file *filp)
{
int err, minor;
if(!inode || !filp)
return -1;
if(!alpha_led_ops.inited)
return -1;
if(!alpha_led_ops.alpha_led_init)
return -1;
//Question: here I want to call alpha_led_init(struct drv_priv *priv) defined in the driver.c
//But how can I get the parameter priv ? I know I have set it in the device_create(), but how can I fetch it here?
//Or Am writing a very bad platform driver model?
return alpha_led_ops.alpha_led_init(...);
}
static int led_close(struct inode *inode, struct file *filp)
{
return 0;
}
static int __init chrdev_led_init(void)
{
dev_t devid;
int i, rc, major, minor;
struct device *pdev;
if (led_major) {
devid = MKDEV(led_major, 0);
rc = register_chrdev_region(devid, LED_MAX_NUM, LED_DEV_NAME);
} else {
rc = alloc_chrdev_region(&devid, 0, LED_MAX_NUM, LED_DEV_NAME);
led_major = MAJOR(devid);
}
if(rc < 0)
goto chrdev_failed;
cdev_init(&led_cdev, &led_fops);
rc = cdev_add(&led_cdev, devid, LED_MAX_NUM);
if(rc < 0)
goto cdev_failed;
led_class = class_create(THIS_MODULE, LED_CLASS_NAME);
if(IS_ERR(led_class))
goto class_failed;
return 0;
class_failed:
cdev_del(&led_cdev);
cdev_failed:
unregister_chrdev_region(devid, LED_MAX_NUM);
chrdev_failed:
return -1;
}
static void __exit chrdev_led_exit(void)
{
class_destroy(led_class);
cdev_del(&led_cdev);
unregister_chrdev_region(MKDEV(led_major, 0), LED_MAX_NUM);
}
int create_led_device_node(int minor, const char *name, void *priv)
{
struct device *dev = NULL;
if(minor >= LED_MAX_NUM)
return NULL;
//device_create take the platform device's private data(priv) as it's own private data.
if(name)
dev = device_create(led_class, NULL, MKDEV(led_major, minor), priv, "%s", name);
else
dev = device_create(led_class, NULL, MKDEV(led_major, minor), priv, "led-%d", minor);
if(!dev)
return -1;
return 0;
}
void destroy_led_device_node(int minor)
{
device_destroy(led_class, MKDEV(led_major, minor));
}
struct alpha_led_operations * get_alpha_led_ops(void)
{
return &alpha_led_ops;
}
EXPORT_SYMBOL(create_led_device_node);
EXPORT_SYMBOL(destroy_led_device_node);
EXPORT_SYMBOL(get_alpha_led_ops);
module_init(chrdev_led_init);
module_exit(chrdev_led_exit);
MODULE_AUTHOR("David");
MODULE_LICENSE("GPL");

Kernel driver combining a platform_driver with a i2c_driver

I am writing a kernel driver for a LCD. This LCD uses eight GPIO lines (d0...d7) to send data to display, some gpio control signals (on/off, enable backlight, and r/w) and a potentiometer to control the display contrast, connected to I2C bus.
I wrote a platform_driver that uses "probe" and "remove" callbacks to register/unregister a misc device that creates a /dev/lcd character device with can be used from userspace to send a buffer to be printed on the screen. I am able to read GPIOS properly defined on the DTS and also to manage those GPIOS to print strings on the LCD. This is the skeleton:
#define MODULE_NAME "lcd"
static void lcd_hw_setup(void)
{ ... }
static int lcd_open(struct inode *inode, struct file *file)
{ ... }
static ssize_t lcd_write (struct file *file, const char *buf, size_t count, loff_t *ppos)
{ ... }
static int lcd_close(struct inode *inode, struct file *file)
{ ... }
/* declare & initialize file_operations structure */
static const struct file_operations lcd_dev_fops = {
.owner = THIS_MODULE,
.open = lcd_open,
.write = lcd_write,
.release = lcd_close
};
/* declare & initialize miscdevice structure */
static struct miscdevice lcd_misc = {
.minor = MISC_DYNAMIC_MINOR, /* major = 10 assigned by the misc framework */
.name = MODULE_NAME, /* /dev/lcd */
.fops = &lcd_dev_fops,
};
static int lcd_probe(struct platform_device *pdev)
{
struct device *dev;
pr_info(MODULE_NAME ": lcd_probe init\n");
/* Register the misc device with the kernel */
misc_register(&lcd_misc);
dev = &pdev->dev;
/* gpiod_get calls to get gpios from DTS */
lcd_hw_setup();
pr_info(MODULE_NAME ": lcd_probe ok\n");
return 0;
}
static int lcd_remove(struct platform_device *pdev)
{
pr_info(MODULE_NAME ": lcd_remove\n");
/* Release gpio resources */
...
/* Unregister the device with the kernel */
misc_deregister(&lcd_misc);
return 0;
}
/* declare a list of devices supported by this driver */
static const struct of_device_id lcd_of_ids[] = {
{ .compatible = "my-lcd" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, lcd_of_ids);
/* declare & initialize platform_driver structure */
static struct platform_driver lcd_pdrv = {
.probe = lcd_probe,
.remove = lcd_remove,
.driver = {
.name = "my-lcd", /* match with compatible */
.of_match_table = lcd_of_ids,
.owner = THIS_MODULE,
},
};
/* register platform driver */
module_platform_driver(lcd_pdrv);
That works really fine.
Now I need to send to the I2C potentiometer a initialization value to set the display contrast. That requires calling i2c_smbus_write_byte_data. I need access to a i2c_client struct for that.
I found some I2C examples that create a i2c_driver which provides probe and remove callbacks, and receive a pointer to that i2c_client struct in the probe function. But I don't find a way to relate that i2c_driver with my platform_driver. They seem to be completely independent drivers.
My questions:
Can a platform_driver and a i2c_driver be combined in a single kernel module? I mean, can I add a module_platform_driver and module_i2c_driver calls in a single kernel module?
Or maybe I have to create a second driver just to control the I2C potentiometer. In this particular case there is a dependency between both kernel modules. How that dependency should be managed?
Please some help with this would be really helpful. Thanks a lot!
As an initial work around I have developed a second driver (an i2c_driver) just to call the i2c_smbus_write_byte_data function from the probe callback. It works, but I would like to know if this is the proper way to fix this issue. Thanks!

i2c kernel driver - Binding between sysfs kobject and i2c_client

I am working on an I2C kernel driver and would like to provide a sysfs file interface in a new folder - /sys/devices/MySensor. However, when I do this I don't know how to associate the i2c client with the new kobject.
Consequently, when my device attribute functions are called, the device object passed in does not allow me to retrieve the registered i2c client.
I declare my attribute as follows:
static ssize_t my_sensor_do_something(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client;
struct my_sensor_data *data;
int size = 0;
client = to_i2c_client(dev);
my_sensor_dbgmsg("Client Address:0x%02x\n", client->addr);
data = i2c_get_clientdata(client);
return 0
}
static DEVICE_ATTR(do_something, S_IRUGO, my_sensor_do_something, NULL);
static struct attribute *my_sensor_attributes[] = {
&dev_attr_do_something.attr,
NULL
};
static const struct attribute_group my_sensor_attr_group = {
.attrs = my_sensor_attributes,
};
Then, in my probe function, create my subfolder
struct device *my_dev = root_device_register("my_sensor");
err = sysfs_create_group(&my_dev->kobj, &my_sensor_attr_group);
The sub-folder and do_something file is created in /sys/kernel/, however when do_something() is called, the attempt to retrieve the I2C client fails - client->addr is 0 and i2c_get_client_data returns null.
For info, the i2c device is defined in a device tree and I can successfully add device attributes to the existing folder
err = sysfs_create_group(client->dev.kobj, &my_sensor_attr_group);
/sys/bus/i2c/devices/i2c-7/7-004c/
Apologies if this question is vague or lacking sufficient detail. I'm relatively new to this.
Does anyone have an idea what I am missing when I create a new sysfs folder, to associate this with my registered i2c client?
Thanks
You can put the client on my_dev at initialization time.
dev_set_drvdata(my_dev, client);
Then in the my_sensor_do_something function, use dev_get_drvdata to take the client out
client = dev_get_drvdata(dev);
The complete example is as follows
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
static ssize_t my_sensor_do_something(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client;
void *data;
client = dev_get_drvdata(dev);
data = i2c_get_clientdata(client);
pr_info("Client Address:0x%02x Data:%p\n", client->addr, data);
return 0;
}
static DEVICE_ATTR(do_something, 0444, my_sensor_do_something, NULL);
static struct attribute *my_sensor_attributes[] = {
&dev_attr_do_something.attr,
NULL
};
static const struct attribute_group my_sensor_attr_group = {
.attrs = my_sensor_attributes,
};
static struct device *my_dev;
static void my_sensor_create(struct i2c_client *client)
{
int err;
my_dev = root_device_register("my_sensor");
dev_set_drvdata(my_dev, client);
err = sysfs_create_group(&my_dev->kobj, &my_sensor_attr_group);
if (err)
pr_info("sysfs_create_group failure.\n");
}
struct test_device {
struct i2c_client *client;
};
static int test_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct test_device *dev;
dev = kzalloc(sizeof(struct test_device), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
dev->client = client;
i2c_set_clientdata(client, dev);
my_sensor_create(client);
return 0;
}
static int test_i2c_remove(struct i2c_client *client)
{
struct test_client *dev = i2c_get_clientdata(client);
if (my_dev)
root_device_unregister(my_dev);
kfree(dev);
return 0;
}
static const struct i2c_device_id test_i2c_id[] = {
{"test_i2c_client", 0},
{}
};
static struct i2c_driver test_i2c_driver = {
.driver = { .name = "test_i2c_client", },
.probe = test_i2c_probe,
.remove = test_i2c_remove,
.id_table = test_i2c_id,
};
static int __init test_i2c_init_driver(void)
{
return i2c_add_driver(&test_i2c_driver);
}
static void __exit test_i2c_exit_driver(void)
{
i2c_del_driver(&test_i2c_driver);
}
module_init(test_i2c_init_driver);
module_exit(test_i2c_exit_driver);
MODULE_LICENSE("GPL");

How are the steps to access GPIOs in linux kernel modules?

I am struggling to find out, what steps are necessary to access a gpio-pin from a linux kernel module.
Maybe someone can explain it to me by a simple example. I like to use pin 4(input) and 33(output). My steps so far:
1.) Device Tree(dts): I leave the dts file untouched - Do I need to setup the pin 4 and 33 via pin control?
2.) kernel module: some pseudo code
gpio_is_valid(4)
gpio_request_one(4, GPIOF_DIR_IN | GPIOF_EXPORT_DIR_FIXED , "myPin4")
gpio_export(4, false)
gpio_get_value(4)
gpio_is_valid(33)
gpio_request_one(33, GPIOF_DIR_OUT | GPIOF_INIT_LOW | GPIOF_OPEN_SOURCE | GPIOF_EXPORT_DIR_FIXED , "myPin33")
gpio_export(33, false)
gpio_set_value(33, 1)
How to do it in a proper way?
I would suggest the combination of an own device tree file + a platform driver + character driver
0.) RTF
check how device trees(dts) are working
check how a platform device works
check how a character device works
gain some knowledge about gpios and dts
#gpio mappings
#subsystems using gpios
#Specifying GPIO information for devices
Read the informations provided by your SOC manufacturer.
The state-of-the-art way to access the gpios is via struct gpio_desc variables. They are created form the device tree.
1.) approach
To toggle a pin under linux you need to make shure, that 3 units are working togehter.
The pin-controller(pinctrl) defines how the output is driven. Open source, pull up etc.
The pin-multiplexer(pinmux) defines different functions for the pin.
The gpio-controller(gpioctrl) translates the gpio number. p.E.: 44 -> GPIO A 11
These components are implemented by the SOC manufacturer. For each platform there are differences. An example for the SAMA5D35xxx follows.
#the device tree
Define the pin controller
pinctrl#fffff200 {
pinctrl_myPins: myPins {
atmel,pins = <AT91_PIOA 2 AT91_PERIPH_GPIO AT91_PINCTRL_NONE // pin 1
AT91_PIOD 19 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>; // pin 2
};
};
Create a node witch is linked to the own platform device:
myPins {
compatible = "myPlatformDevice";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_myPins>;
pin1 = <&pioA 2 GPIO_ACTIVE_HIGH>;
pin2 = <&pioD 19 GPIO_ACTIVE_HIGH>;
};
#create platform + char driver (pseudo code):
// ----------------------
// kernel message support(via dmesg)
// ----------------------
#define KMSG_DEBUG(fmt,args...) printk(KERN_DEBUG "myDrv" ": "fmt"\n", ##args)
#define KMSG_PERR(fmt,args...) printk(KERN_ERR "myDrv" ": "fmt"\n", ##args)
#define KMSG_PINFO(fmt,args...) printk(KERN_INFO "myDrv" ": "fmt"\n", ##args)
// ----------------------
// trace support via defining dMyDrvTrace
// ----------------------
#ifndef dMyDrvTrace
#define TRACE(...)
#else
#define TRACE(fmt,args...) printk(KERN_INFO "myDrv" ": [%s] "fmt"\n", __FUNCTION__, ##args)
#endif
typedef struct SMyDrvDrvData {
struct platform_device *pdev; //!< next device
// here goes the local/private data
int gpiod_pin1;
int gpiod_pin2;
u32 pin1;
u32 pin2;
} TMyDrvDrvData;
static struct dentry * gmyPlattformDrvDebugfsRootDir; //!< root dir at debugfs
static int myPlattformDrv_probe(struct platform_device *pdev);
static int myPlattformDrv_remove(struct platform_device *pdev);
#if defined(CONFIG_OF)
//! filter for the device tree class
static struct of_device_id gMyPlattformDrvdtsFilter[] = {
{.compatible = "myPlatformDevice"},
{}
};
MODULE_DEVICE_TABLE(of, gMyPlattformDrvdtsFilter);
#else
#define gmyPlattformDrvdtsFilter (NULL)
#endif
static struct platform_device *MyPlattformDrv_devs[] = {
};
static struct platform_driver myPlattformDrv_driver = {
.driver = {
.name = dMyPlattformDrvdriver,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(gMyPlattformDrvdtsFilter),
},
.probe = myPlattformDrv_probe,
.remove = myPlattformDrv_remove,
};
// char device
static dev_t gMyCharDev;
static struct class *gMyCharDevClass;
static struct cdev gMyCharDev_cdev;
static int dev_open (struct inode *, struct file *);
static int dev_release (struct inode *, struct file *);
static ssize_t dev_read (struct file *, char *, size_t, loff_t *);
static ssize_t dev_write (struct file *, const char *, size_t, loff_t *);
static const struct file_operations gMyCharDevOps =
{
.read = dev_read,
.open = dev_open,
.write = dev_write,
.release = dev_release
};
//! looks up for the gpio name and request it
static int get_gpio(struct platform_device *pdev, const char * name, int * pGPIOnum)
{
int n,i;
int r;
struct device_node * pDN;
TRACE("look at %s for %s ...", pdev->name, name);
// reset return value
*pGPIOnum = 0;
// parse device tree
// get device tree entries associated with the device
pDN = of_find_node_by_name(NULL, pdev->name);
// parse pins
n = of_gpio_named_count(pDN, name);
if (n <= 0) {
TRACE("no gpios found");
return -1;
}
for (i = 0; i < n; i++) {
// get pin number
*pGPIOnum = of_get_named_gpio(pDN,name, i);
if (*pGPIOnum == -EPROBE_DEFER) {
return r;
}
// check if pin number is valid
if (gpio_is_valid(*pGPIOnum)) {
// yes
// request pin
r = devm_gpio_request(&pdev->dev, *pGPIOnum, name);
if (r) {
return r;
} else {
r = gpio_direction_output(*pGPIOnum, 0);
}
if (r) return r;
}
}
}
return 0;
}
//! probes the platform driver
static int myPlattformDrv_probe(struct platform_device *pdev)
{
struct TMyDrvDrvData *priv;
int i,j,r,gpioNum, ret;
KMSG_PINFO("probe my driver ...");
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
KMSG_PERR("Failed to allocate memory for the private data structure");
return -ENOMEM;
}
priv->pdev = pdev;
platform_set_drvdata(pdev, priv);
TRACE("setup gpios ...");
r = get_gpio(pdev, "pin1", &gpioNum);
if (r) {
KMSG_PERR("Failed to find gpio \"pin1\" in device tree");
}
// save number
priv->gpiod_pin1 = gpioNum;
// create "pin1" debugfs entry
debugfs_create_u32("pin1", S_IRUGO, gmyPlattformDrvDebugfsRootDir, &priv->Pin1);
r = get_gpio(pdev, "pin2", &gpioNum);
if (r) {
KMSG_PERR("Failed to find gpio \"pin2\" in device tree");
}
// save number
priv->gpiod_pin2 = gpioNum;
// create "pin2" debugfs entry
debugfs_create_u32("pin1", S_IRUGO, gmyPlattformDrvDebugfsRootDir, &priv->Pin2);
// create device class
TRACE("create myCharDev char device class");
// create char dev region
ret = alloc_chrdev_region(&gMyCharDev, 0, 1, "myCharDev");
if( ret < 0) {
KMSG_PERR("alloc_chrdev_region error %i", ret);
goto error;
}
// create device class
if((gMyCharDevClass = class_create(THIS_MODULE, dSEK4DevClass)) == NULL)
{
KMSG_PERR("class_create error");
goto error_classCreate;
}
if(NULL == device_create(gMyCharDevClass, NULL, gMyCharDev, NULL, "myCharDev"))
{
KMSG_PERR("device_create error");
goto error_deviceCreate;
}
cdev_init(&gMyCharDev_cdev, &gMyCharDevOps);
ret = cdev_add(&gMyCharDev_cdev, gMyCharDev, 1);
if(-1 == ret) {
KMSG_PERR("cdev_add error %i", ret);
goto error_device_add;
return -1;
}
TRACE("added myCharDev char device");
return 0;
// error handling block
error_std:
error_device_add:
device_destroy(gMyCharDevClass, gMyCharDev);
error_deviceCreate:
class_destroy(gMyCharDevClass);
error_classCreate:
unregister_chrdev_region(gMyCharDev, 1);
error:
return -1;
}

Which is the correct way to register a new net_device?

i'm trying to register a new net_device in linux...i can alloc and register it correctly and ifconfig shows it. The problem arrives when i try to put the interface up:
ifconfig my_dev up
A kernel freeze occurs...the problem is present only on x86 machines and i can't figure out the reason...on a pcc machine all works well. The code is very simple:
static struct net_device *my_dev;
static int veth_dev_init(struct net_device *dev);
static int veth_open(struct net_device *dev);
static int veth_close(struct net_device *dev);
static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static struct veth_priv
{
...
};
static struct net_device_ops veth_ops =
{
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
.ndo_stop = veth_close,
.ndo_do_ioctl = veth_ioctl
};
static int __init veth_init()
{
my_dev = alloc_netdev(sizeof(struct veth_priv), "my_dev", ether_setup);
if (my_dev == NULL)
return -ENOMEM;
my_dev->netdev_ops = &veth_ops;
register_netdev(my_dev);
return 0;
}
static void __exit veth_exit()
{
unregister_netdev(my_dev);
free_netdev(my_dev);
}
module_init(veth_init);
module_exit(veth_exit);
The first four functions veth_dev_init, veth_open, veth_close and veth_ioctl simply return 0.
Maybe is there a missing field in veth_ops structure?
Thank you all!
Yea, you missed one element in struct net_device_ops
Add .ndo_start_xmit also, And the function must return NETDEV_TX_OK or NETDEV_TX_BUSY.
use as follows
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
return NETDEV_TX_OK;
}
And also change the open as
static int veth_open(struct net_device *dev)
{
memcpy(dev->dev_addr, "\0ABCD0", ETH_ALEN);
netif_start_queue(dev);
return 0;
}
Then in veth_ops
static struct net_device_ops veth_ops = {
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
.ndo_stop = veth_close,
.ndo_start_xmit = veth_xmit,
.ndo_do_ioctl = veth_ioctl,
};
Then after inserting the module
give ifconfig my_dev 192.168.10.98 ...

Resources