how to define a struct msghdr to send UDP packet in linux kernel without copying data from user space - linux-kernel

I'm trying to send a Hello message from linux kernel after a UDP connect (which calls the function ip4_datagram_connect). Since the protocol number in this message needs to be different than UDP (This is a custom protocol which I'm building with UDP as the base code), I can't use the netpoll API.
So I'm trying to use the functions (picked up from udp_sendmsg())-
ip_make_skb(struct sock *sk,
struct flowi4 *fl4,
int getfrag(void *from, char *to, int offset,
int len, int odd, struct sk_buff *skb),
void *from, int length, int transhdrlen,
struct ipcm_cookie *ipc, struct rtable **rtp,
unsigned int flags)
to generate the sk_buff and
int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
to send out the generated sk_buff.
My problem is, the function ip_make_skb requires the pointers *from and length which in the udp_sendmsg function are the pointer to and the length of the data in the user space(+ length of udphdr) and then ip_make_skb() copies the data from the userspace. Since I'm just sending a Hello message from the kernel, this is a wasteful step for me (I don't need any data from the user space).
So can I just set the *from pointer to some dummy location and length to zero(+sizeof(struct udphdr))? If yes, what kind of value for *from will be appropriate?
Or is this completely wrong and I should do something else?
Edit 1: For now, I'm doing this
void *from = "Hello";
This will give me a valid pointer in the memory, but I feel it's a dirty way to do this. Tt works though.

Related

What is the purpose of the function "blk_rq_map_user" in the NVME disk driver?

I am trying to understand the nvme linux drivers. I am now tackling the function nvme_user_submit_cmd, which I report partially here:
static int nvme_submit_user_cmd(struct request_queue *q,
struct nvme_command *cmd, void __user *ubuffer,
unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
u32 meta_seed, u32 *result, unsigned timeout)
{
bool write = nvme_is_write(cmd);
struct nvme_ns *ns = q->queuedata;
struct gendisk *disk = ns ? ns->disk : NULL;
struct request *req;
struct bio *bio = NULL;
void *meta = NULL;
int ret;
req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
[...]
if (ubuffer && bufflen) {
ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
GFP_KERNEL);
[...]
The ubufferis a pointer to some data in the virtual address space (since this comes from an ioctl command from a user application).
Following blk_rq_map_user I was expecting some sort of mmap mechanism to translate the userspace address into a physical address, but I can't wrap my head around what the function is doing. For reference here's the call chain:
blk_rq_map_user -> import_single_range -> blk_rq_map_user_iov
Following those function just created some more confusion for me and I'd like some help.
The reason I think that this function is doing a sort of mmap is (apart from the name) that this address will be part of the struct request in the struct request queue, which will eventually be processed by the NVME disk driver (https://lwn.net/Articles/738449/) and my guess is that the disk wants the physical address when fulfilling the requests.
However I don't understand how is this mapping done.
ubuffer is a user virtual address, which means it can only be used in the context of a user process, which it is when submit is called. To use that buffer after this call ends, it has to be mapped to one or more physical addresses for the bios/bvecs. The unmap call frees the mapping after the I/O completes. If the device can't directly address the user buffer due to hardware constraints then a bounce buffer will be mapped and a copy of the data will be made.
Edit: note that unless a copy is needed, there is no kernel virtual address mapped to the buffer because the kernel never needs to touch the data.

Create array of struct scatterlist from buffer

I am trying to build an array of type "struct scatterlist", from a buffer pointed by a virtual kernel address (I know the byte size of the buffer, but it may be large). Ideally I would like to have function like init_sg_array_from_buf:
void my_function(void *buffer, int buffer_length)
{
struct scatterlist *sg;
int sg_count;
sg_count = init_sg_array_from_buf(buffer, buffer_length, sg);
}
Which function in the scatterlist api, does something similar? Currently the only possibility I see, is to manually determine the amount of pages, spanned by the buffer. Windows has a kernel macro called "ADDRESS_AND_SIZE_TO_SPAN_PAGES", but I didn't even manage to find something like this in the linux kernel.

Linux Char Driver

Can anyone tell me how a Char Driver is bind to the corresponding physical device?
Also, I would like to know where inside a char driver we are specifying the physical device related information, which can be used by kernel to do the binding.
Thanks !!
A global array — bdev_map for block and cdev_map for character devices — is used to implement a hash table, which employs the device major number as hash key.
while registering for char driver following calls get in invoked to get major and minor numbers.
int register_chrdev_region(dev_t from, unsigned count, const char *name)
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name);
After a device number range has been obtained, the device needs to be activated by adding it to the character device database.
void cdev_init(struct cdev *cdev, const struct file_operations *fops);
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
Here on cdev structure initialize with file operation and respected character device.
Whenever a device file is opened, the various filesystem implementations invoke the init_special_inode function to create the inode for a block or character device file.
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) {
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
}
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",
mode);
}
now the default_chr_fpos chrdev_open() method will get invoked. which will look up for the inode->rdev device in cdev_map array and will get a instance of cdev structure. with the reference to cdev it will bind the file->f_op to cdev file operation and invoke the open method for character driver.
In a character driver like I2C client driver, We specify the slave address in the client structure's "addr" field and then call i2c_master_send() or i2c_master_receive() on this client . This calls will ultimately go to the main adapter controlling that line and the adapter then communicates with the device specified by the slave address.
And the binding of drivers operations is done mainly with cdev_init() and cdev_add() functions.
Also driver may choose to provide probe() function and let kernel find and bind all the devices which this driver is capable of supporting.

What is the use of 'i2c_get_clientdata" and "i2c_set_clientdata"

I have been studying I2C driver (client) code for a while.
I have seen this function "i2c_get_clientdata" and "i2c_set_clientdata" every where.
I have seen the this question here .
Use of pointer to structure instead of creating static local copy
Some times i think like it is like "container_of" macro to get a pointer to the structure.
But still i didn't understood properly why to use it and when to use it.
Below i am posting a sample code where I see its usage.
If any one could help me understand why it is used there and when we shall use it when we write our own drivers.
struct max6875_data {
struct i2c_client *fake_client;
struct mutex update_lock;
u32 valid;
u8 data[USER_EEPROM_SIZE];
unsigned long last_updated[USER_EEPROM_SLICES];
};
static ssize_t max6875_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct max6875_data *data = i2c_get_clientdata(client);
int slice, max_slice;
if (off > USER_EEPROM_SIZE)
return 0;
if (off + count > USER_EEPROM_SIZE)
count = USER_EEPROM_SIZE - off;
/* refresh slices which contain requested bytes */
max_slice = (off + count - 1) >> SLICE_BITS;
for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
max6875_update_slice(client, slice);
memcpy(buf, &data->data[off], count);
return count;
}
Those functions are used to get/set the void *driver_data pointer that is part of the struct device, itself part of struct i2c_client.
This is a void pointer that is for the driver to use. One would use this pointer mainly to pass driver related data around.
That is what is happening in your example. The max6875_read is a callback getting a structu kobject. That kobject is an i2c_client which is enough to communicate with the underlying device using the driver_data pointer here allows to get back the driver related data (instead of using global variables for example).

WSASend : Send int or struct

I would like to use MS function to send data.
I didnt find examples where they send other type of data other than const char * .
I tried to send a int, or other, but I failed.
WSASend() and send() both function only take a Char* parameters.
How should i proceed ?
Thanks
Its just a pointer to a buffer, this buffer may contains anything you want.
This char pointer is actually an address to a bytes array, this function requires a length parameter too.
An integer is a 2/4 (short/long) bytes value,
Then if you want to send an integer variable (for example) you have to pass its address, and its length.
WSASend and send are simple functions that send a memory block.
I assume you are talking about C, you have to understand that C's char variables are bytes - 8 bits block, char variables contain any value between 0 and 255.
A pointer to a char var is an address to a byte (which maybe the first cell of a bytes array).
I think thats what confuses you.
I hope you understand.
The const char* parameter indicates that the function is taking a pointer to bytes. Witch really seems to be the result of the original socket api designers being pedantic - C has a generic type to handle any kind of pointer without explicit casts: void*.
You could make a convenience wrapper for send like this - which would allow you to send any (contiguous) thing you can make a pointer to:
int MySend(SOCKET s, const void* buf, int len,int flags)
{
return send(s,(const char*)buf,len,flags);
}
Using void* in place of char* actually makes the api safer, as it can now detect when you do something stupid:
int x=0x1234;
send(s,(const char*)x,sizeof(x),0); // looks right, but is wrong.
mysend(s,x,sizeof(x),0); // this version correctly fails
mysend(s,&x,sizeof(x),0); // correct - pass a pointer to the buffer to send.
WSASend is a bit more tricky to make a convenience wapper for as you have to pass it an array of structs that contain the char*'s - but again its a case of defining an equivalent struct with const void*'s in place of the const char*'s and then casting the data structures to the WSA types in the convenience wrapper. Get it right once, and the rest of the program becomes much easier to determine correct as you don't need casts everywhere hiding potential bugs.

Resources