libpcap Radiotap header extraction - c

I've got some code that is using the functions ieee80211_radiotap_iterator_init() and ieee80211_radiotap_iterator_next() from radiotap-parser.c,
I'm not sure what I'm doing incorrectly, perhaps someone can educate me? I'm using the sample code from the documentation more or less without modification, it fits very well to what I was trying to achieve:
/* where packet is `const u_char *packet' */
struct ieee80211_radiotap_iterator rti;
struct ieee80211_radiotap_header *rth = ( struct ieee80211_radiotap_header * ) packet;
/* 802.11 frame starts here */
struct wi_frame *fr= ( struct wi_frame * ) ( packet + rth->it_len );
/* Set up the iteration */
int ret = ieee80211_radiotap_iterator_init(&rti, rth, rth->it_len);
/* Loop until we've consumed all the fields */
while(!ret) {
printf("Itteration: %d\n", count++);
ret = ieee80211_radiotap_iterator_next(&rti);
if(ret) {
/*
* The problem is here, I'm dropping into this clause with
* a value of `1` consistently, that doesn't match my platform's
* definition of EINVAL or ENOENT.
*/
continue;
}
switch(rti.this_arg_index) {
default:
printf("Constant: %d\n", *rti.this_arg);
break;
}
}
There's limited scope for having screwed something up in that code, I think, I'm confused by the 1 being returned from ieee80211_radiotap_iterator_next() which according to the implenentation doesn't seem like an error condition in the implementation.
I'm filtering for packets of type "(type mgt) and (not type mgt subtype beacon)", and I'm not even certain if libpcap will include these attributes when the data link is set to DLT_IEEE802_11_RADIO?

First:
I'm filtering for packets of type "(type mgt) and (not type mgt subtype beacon)", and I'm not even certain if libpcap will include these attributes when the data link is set to DLT_IEEE802_11_RADIO?
It will. The filter code generated for DLT_IEEE802_11_RADIO fetches the radiotap header length and skips the radiotap header, so it'll just skip the radiotap header and check the 802.11 header following it.
Second:
the implementation
You linked to two different implementations of ieee80211_radiotap_iterator_next() - the one at radiotap-parser.c, in which ieee80211_radiotap_iterator_next() returns the "next present arg index" on success, and the one from the Linux kernel, in which ieee80211_radiotap_iterator_next() returns 0 on success. If the radiotap iterator code you're using is the one at radiotap-parser.c, pay no attention whatsoever to the one from the Linux kernel, as it doesn't behave the way the one you're using behaves.

Related

Usage of Xilinx built-in UART function #define XUartPs_IsReceiveData (BaseAddress )

So I am trying to use this built-in UART function (from the Vitis SDK from Xilinix) to determine if there is a valid byte to read over UART. I created this function to return 1 if there was a byte to read or 0 if there wasn't
u32 UartHasMessage(void){
if(XUartPs_IsReceiveData(&XUartPs_Main)){
return 1;
}
else{
return 0;
}
}
However, even when there is a byte to read over UART, this function always returns false.
The weird behavior I am experiencing is when I step through the code using the debugger, I call UartHasMessage() to check if there is a byte to read, and it returns false, but in the next line I call a function to read a byte over UART and that contains the correct byte I sent over the host.
u32 test - UartHasMessage();
UartGetByte(&HostReply);
How come this UartHasMessage always returns false, but then in the next line I am able to read the byte correctly?
Caveat: Without some more information, this is a bit speculative and might be a comment, but it is too large for that.
The information below comes from the Xilinx documentation on various pages ...
XUartPs_RecvByte will block until a byte is ready. So, no need to call XUartPs_IsReceiveData directly (I think that XUartPS_RecvByte calls it internally).
A web search on XUartPs_Main came up with nothing, so we'd need to see the definition you have.
Most Xilinx documentation uses UART_BASEADDRESS:
#define UART_BASEADDR XPAR_XUARTPS_0_BASEADDR
I found a definition:
#define XPAR_XUARTPS_0_BASEADDR 0xE0001000
You might be better off using a more standard method, such as calling the XUartPs_LookupConfig function to get the configuration table entry which has all relevant values.
I'm guessing that you created the XUartPS_Main definition.
But, based on what you posted, (needing &XUartPS_Main instead of XUartPS_Main), it is linked/loaded at the exact address of the UART register bank. Let's assume that address is (e.g.) 0x10000. So, we might have:
u32 XUartPS_Main __attribute__(at(0x10000));
The at is an extension that some build systems support (e.g. arm) that forces the variable to be loaded at a given address. So, let's assume we have that (even if the mechanism is slightly different (e.g.):
__attribute__((section(".ARM.__at_0x10000")))
The definition of XUARTPS_SR_OFFSET is:
#define XUARTPS_SR_OFFSET 0x002CU
Offsets are [typically] byte offsets.
Given:
#define XUartPs_IsReceiveData(BaseAddress) \
!((Xil_In32((BaseAddress) + XUARTPS_SR_OFFSET) & \
(u32)XUARTPS_SR_RXEMPTY) == (u32)XUARTPS_SR_RXEMPTY)
Now if the definition of XUartPS_Main uses u32 [as above], we may have a problem because XUARTPS_SR_OFFSET will be treated as a u32 index and not a byte offset. So, it will access the wrong address.
So, try:
XUartPs_IsReceiveData((unsigned char *) &XUartPs_Main)
But, if it were me, I'd rework things to use Xilinx's standard definitions.
UPDATE:
Hi so XUartPs_main is defined as static XUartPs XUartPs_Main; I use it in a variety of functions such as a function to send bytes over uart and I call it by its address like I did with this function, all my other functions work as expected except this one. Is it possible it is something to do with the way the fifo works? –
29belgrade29
No, not all the API functions are the same.
The struct definition is [I synthesized this from the API doc]:
typedef struct {
u16 DeviceId; // Unique ID of device.
u32 BaseAddress; // Base address of device (IPIF)
u32 InputClockHz;
} XUartPs;
Somewhere in your code you had to initialize this with:
XUartPs_Main = XUartPs_ConfigTable[my_device_id];
Or, with:
XUartPs_Main = *XUartPs_LookupConfig(my_device_id);
If an API function is defined as (e.g.):
void api_dosomething(XUartPs_Config *cfg,...)
Then, you call it with:
api_dosomething(&XUartPs_Main,...);
So, most functions probably take such a pointer.
But, XUartPs_IsReceiveData does not want a pointer to a XUartPs_Config struct. It wants a base address. This is:
XUartPs_Main.BaseAddress
So, you want:
XUartPs_IsReceiveData(XUartPs_Main.BaseAddress)

Parsing a .pcap file in plain C

I'm trying to create my own pcap files parser. According to Wireshark's docs:
Global Header
This header starts the libpcap file and will be followed by the first packet header:
typedef struct pcap_hdr_s {
guint32 magic_number; /* magic number */
guint16 version_major; /* major version number */
guint16 version_minor; /* minor version number */
gint32 thiszone; /* GMT to local correction */
guint32 sigfigs; /* accuracy of timestamps */
guint32 snaplen; /* max length of captured packets, in octets */
guint32 network; /* data link type */
} pcap_hdr_t;
magic_number: used to detect the file format itself and the byte ordering. The writing application writes 0xa1b2c3d4 with it's native byte ordering format into this field. The reading application will read either 0xa1b2c3d4 (identical) or 0xd4c3b2a1 (swapped). If the reading application reads the swapped 0xd4c3b2a1 value, it knows that all the following fields will have to be swapped too. For nanosecond-resolution files, the writing application writes 0xa1b23c4d, with the two nibbles of the two lower-order bytes swapped, and the reading application will read either 0xa1b23c4d (identical) or 0x4d3cb2a1 (swapped).
version_major, version_minor: the version number of this file format (current version is 2.4)
thiszone: the correction time in seconds between GMT (UTC) and the local timezone of the following packet header timestamps. Examples: If the timestamps are in GMT (UTC), thiszone is simply 0. If the timestamps are in Central European time (Amsterdam, Berlin, ...) which is GMT + 1:00, thiszone must be -3600. In practice, time stamps are always in GMT, so thiszone is always 0.
sigfigs: in theory, the accuracy of time stamps in the capture; in practice, all tools set it to 0
snaplen: the "snapshot length" for the capture (typically 65535 or even more, but might be limited by the user), see: incl_len vs. orig_len below
network: link-layer header type, specifying the type of headers at the beginning of the packet (e.g. 1 for Ethernet, see tcpdump.org's link-layer header types page for details); this can be various types such as 802.11, 802.11 with various radio information, PPP, Token Ring, FDDI, etc.
/!\ Note: if you need a new encapsulation type for libpcap files (the value for the network field), do NOT use ANY of the existing values! I.e., do NOT add a new encapsulation type by changing an existing entry; leave the existing entries alone. Instead, send mail to tcpdump-workers#lists.tcpdump.org , asking for a new link-layer header type value, and specifying the purpose of the new value.
The first integer in the file should be either 0xA1B2C3D4 or 0xD4C3B2A1, but my code's output:
#include <stdio.h>
typedef unsigned int guint32;
typedef unsigned short guint16;
int main()
{
FILE * file = fopen("test.pcap", "rb");
guint32 magic_number;
fscanf(file, "%d", &magic_number);
printf("%x\n", magic_number);
return 0;
}
Is 0x8. Why is that?
The magic number are the first 4 bytes of the file. With fscanf(...%d you don't read these 4 bytes but you instead try to interpret the beginning of the file as the ASCII representation of a number, i.e. "1234" instead of "\x01\x02\x03\x04". Thus instead of fscanf you need to use fread to read exactly 4 bytes.
fread((void*)&magic_number, 4, 1, file)

How to determine the size of a PIM within an AUTOSAR Runnable?

How can I determine the size of a PIM (Per Instance Memory) in c from inside a Runnable (without looking it up in the generated RTE and adding a fix value)?
Situation:
Runnable Foo has access to two PIMs Pim1 and Pim2. In the example the data from Pim1 shall be copied to Pim2.
Not only because of security and safety I need to check the size of both PIMs in order NOT to overwrite illegal data areas.
I know that the size of the PIM is configured in the SW-C description (SWCD). But as the SWCD may be changed after code implementation and in order to keep the code of the Runnable more generic, the size checking should not be based on fix values.
I also considered the problem of the sizeof for an array:
How to find the 'sizeof'(a pointer pointing to an array)?
For the PIMs the following code is generated by the RTE-Generator:
In Rte_Type.h
typedef uint8 Rte_DT_DtImplRec1_0;
typedef uint16 Rte_DT_DtImplRec1_1;
typedef struct
{
Rte_DT_DtImplRec1_0 var1;
Rte_DT_DtImplRec1_1 var2;
Rte_DT_DtImplRec1_2 var3;
} DtImplRec1;
typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5];
In Rte.c
VAR(DtImplRec1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim1;
VAR(DtImplAry1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim2;
In Rte_FOO.h
#define Rte_Pim_Pim1() (&Rte_FOO_Pim1)
#ifdef RTE_PTR2ARRAYBASETYPE_PASSING
# define Rte_Pim_Pim2() (&((*RtePim_Pim2())[0]))
#else
# define Rte_Pim_Pim2() RtePim_Pim2()
#endif
#define RtePim_Pim2() (&Rte_FOO_Pim2)
Note that the define for array PIMs might also be changing, depending on the RTE_PTR2ARRAYBASETYPE_PASSING “switch”.
The following “access” is generated for the FOO template:
DtImplRec1 *Rte_Pim_Pim1(void);
Rte_DT_DtImplAry1_0 *Rte_Pim_Pim2(void)
The code for the Foo-Runnable may look like this:
FUNC(void, FOO_CODE) Foo(void)
{
DtImplRec1 *pim1 = Rte_Pim_Pim1();
Rte_DT_DtImplAry1_0 *pim2 = Rte_Pim_Pim2();
uint8 sizeOfPim1a = sizeof(Rte_Pim_Pim1()); /* always returns 4 as the size of the pointer */
uint8 sizeOfPim1b = sizeof(*Rte_Pim_Pim1()); /* evaluates to 6 */
uint8 sizeOfPim1c = sizeof(DtImplRec1); /* evaluates to 6 */
uint8 sizeOfPim1d = sizeof(Rte_FOO_Pim1); /* evaluates to 6 */
uint8 sizeOfPim2a = sizeof(Rte_Pim_Pim2()); /* always returns 4 as the size of the pointer */
uint8 sizeOfPim2b = sizeof(*Rte_Pim_Pim2()); /* evaluates to 1 */
uint8 sizeOfPim2c = sizeof(Rte_DT_DtImplAry1_0); /* evaluates to 1: sizeof(uint8) */
uint8 finalSize = MIN(sizeOfPim1b, sizeOfPim2b);
memcpy( pim2, pim1, finalSize ); /* (use of) memcpy is not the topic here */
}
To make my problem more "visible", here is a Callback-Runnable example for writing a DID via diagnostics:
FUNC(Std_ReturnType, FOO_CODE)
DataServices_Data_FFFF_WriteData(P2CONST(uint8, AUTOMATIC, RTE_APPL_DATA) Data, Dcm_OpStatusType OpStatus, P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, RTE_APPL_DATA) ErrorCode)
{
Std_ReturnType ret = E_NOT_OK;
#define sizeOfPim1 (5) /* how to determine the PIM size here if we do not know anything about it here? (PIM structure can change without modifying the code here) */
#define sizeOfDidFFFF (5) /* This is even another problem: How to determine the size of a DID. I will create another discussion thread for this question. */
/* Instead of this if-condition, an assert during compile-time would also be appropriate */
if( sizeOfPim1 == sizeOfDidFFFF )
{
/* We have to make sure that we do not copy more bytes as of the size of Pim1 */
memcpy( Rte_Pim_Pim1(), Data, sizeOfPim1 ); /* (use of) memcpy is not the topic here */
ret = E_OK;
}
return ret;
}
I don't have here any AUTOSAR environment to test this, so, please, if you try any of this, just let me know if it works. Besides, I am not an expert and it is quite a long time I don't write AUTOSAR code, so I will probably be missing something. I also don't want to publicize any RTE generator from any vendor, so I will cite only the standard.
Use sizeof(DtImplAry1)
You define that type and give it as input to the RTE generator, so you know the name. If your SWC doesn't make explicit use of that type the RTE generator could not include it in your .h, but you could add it manually to you SWC arxml. I think all tools out there allow to do this without having to edit the arxml by hand, just look for the option to include additional SWC types in your tool.
Use Instance API to access SWC data
The standard specifies a variable of type Rte_CDS_FOO to hold all pointers to PIMs of the SWC (among other things) if you enable the API (look for it in your tool).
Besides, a variable Rte_Inst_FOO should be available to you, declared as extern in your header. You could do sizeof(*Rte_Inst_FOO->Pim_Pim2).
EDIT: reply to some of your comments
I guess the reason you don't find the CDS is because of this (from Specification of RTE, 4.2.2, 5.4 RTE Data Structures):
The [CDS and Instance handler] definitions only apply to RTE generators operating in compatibility mode – in this mode the instance handle and the component data structure have to be defined even for those (object-code) software components for which multiple instantiation is forbidden to ensure compatibility.
Also,
[SWS_Rte_03793] If a software component does not support multiple instantiation,the name of the component data instance shall be Rte_Inst_cts, where cts is the component type symbol of the AtomicSwComponentType. (SRS_Rte_00011)
So, when the RTE-generator adheres to this compatibility mode, those variables must be there. If you are using a vendor specific solution, well, try to tag the question with that vendor name also, hopefully somebody can answer.
Assert at compile time
I am not going to ask why you are doing this, but IMHO I think it does not sound right, does it makes sense for the receiving buffer to be smaller that the data to copy?. Maybe it is better to assert at compile time if the buffer is smaller than your struct. Or you could define your array instead to be a struct and cast it if needed (if your are following MISRA rules, maybe you will have problems with it, just check). Just for reference, compile time assertions can use sizeof.
You have several problems here:
a) your sizeof(*pim1) returns 6 because of padding, because you start with an uint8, the second is uint16, and I guess the 3rd ist also uint16.
That's, why you should rather sort them by type size/alignment .. biggest to smallest
uint32
uint16
uint8
Even though, the elements might not be ordered anymore, but it also decreases finally the gaps in memory created by the linker.
b) the pim2 is an array, you can not get the array len/size from the pointer.
But, you should have the Rte definition of DtImplAry1.
typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5]; // <-- taken in through Rte_Foo_Type.h (includes Rte_Type.h
uint32 ary_len = sizeof(DtImplAry1) / sizeof(DtImplAry1[0]);

Error when dealing with memory - mremap_chunk: Assertion

It seems like my previous post but issue here is different ..
This is the C structure for problem -
typedef struct ip_esp_private { /* keep track of things privately */
u_int32_t type;
u_int32_t ivlen;
u_int32_t icvlen;
u_int32_t keylen; /* length of "Encryption key */
u_int32_t akeylen; /*length of authn key */
u_int32_t key[0]; /* encryption key and authentication key both */
} esp_private;
The values are provided to structure contents at run time as follows -
case 'k': /* Key */
length = stringargument(arg, &temp);
priv->keylen = length;
priv = (esp_private *)realloc(priv,
sizeof(esp_private)+/*length*/priv->keylen);
/*This one is edited */
// if(priv->akeylen)
// memmove(&priv->key[priv->keylen],
// &priv->key[0],priv->akeylen);
/*These three are commented*/
memcpy(&priv->key[0], temp, priv->keylen);
pack->private = priv;
pack->modified |= ESP_MOD_KEY;
break;
case 'K': /* Authentication Key */
length = stringargument(arg, &temp);
priv->akeylen = length; // marked line(explained below)
priv = (esp_private *)realloc(priv,
sizeof(esp_private)+/*length*/priv->keylen+priv->akeylen);
/*this one edited too */
memcpy(&priv->key[priv->keylen/sizeof(u_int32_t)],
temp,priv->akeylen);
pack->private = priv;
pack->modified |= ESP_MOD_KEY;
Now there is a function which uses the value of authentication key.
The relevant part of the function is -
if (!epriv->akeylen) {
key = &fakekey;
keylen = 1;
} else {
key = (u_int8_t *)malloc(epriv->akeylen);
memcpy(key,&epriv->key[epriv->keylen/sizeof(u_int32_t)]
,epriv->akeylen);
Now when I tried to run the following program , getting this error about which I have no idea.
sendip: malloc.c:3574: mremap_chunk: Assertion `((size + offset)
& (mp_.pagesize-1)) == 0' failed.
I think may be there is a error in function part but what exactly it is I am not sure,
because when I comment the marked line (mentioned above) the akeylen is null
so taking that fakekey value and program runs fine.
Edit 1:
I have edited the code at three places (also edited in the above code ).
Now program works but an inconsistent output occurs.
Input :
Encryption key - qwerty
Authentication key - abcdef
Output:
Encryption key - qwerab
Authentication key - abcdef
The situation is more clear now .
The problem it means is surely there at realloc statements .
Please suggest on this.
Initially I added length at both realloc statements but now I changed it to priv->keylen at first place and priv->keylen+priv->akeylen at secone place.
But something still needs to be improved
Why this is overwriting ???
Since the key[0] struct hack appears to contain space for both keys, you'll need to allocate memory for both, too. In both cases ('k' and 'K' )
priv = realloc(priv, sizeof *priv +priv->keylen+priv->akeylen);
When concatenating the two keys, it is easiest to cast the u_int32_t key into a character pointer and do arithmatic on that one:
memcpy ( priv->key, source1, sizeofsource1);
/* and */
memcpy ( ((char*) priv->key) +priv->keylen, source2, sizeofsource2);
[and similar for the memmove()]
The rest of the casts in your program can be removed.
If you get assertion failures from within malloc, the problem is outside. The assertion is not about the parameters passed to malloc, but about the state of the memory, which is corrupted. This means that you previously wrote to a memory area you were not supposed to write. So even if you provided a proper traceback (using gdb for instance), this would not point you to the source of the problem. There are a number of tools for debugging memory problems. One of the most widely used tools is valgrind. It will make your program horribly slow and show you tons of possible problems by looking at every single memory access. Another more lightweight tool is mudflap, which is to be linked against. A very basic approach to narrowing down the problem is to add assert(condition) statements to your code and hope that you fail earlier. Sometimes you can solve this problem by looking at every single memory access in your code and ensure that it is not out of bounds (or if you are unsure, add an assertion statement).

alternative to container_of()

I am a newbie trying to code a serial driver(PCI based ) and I don't want to use the container_of() for lack of downward compatibility.The kernel version I may compile the module
would be < 2.6.x so I want to make it compatible with most of the old and new versions.
i want to access the structure member(s) of a serial card driver.the structure is a custom one containing the atomic variable for example - use_count and the related operation on it-- atomic_inc(&serial_card->use_count).I dont want to access them by using the container_of() function which will give me the containing structure
Is there any alternate to container_of() function.If I am not wrong the text LINux device drivers by Allesandro Roubini describes a way on page no 174 | Chapter 6: Advanced Char Driver Operations.
But I am still fixed about how to assign something like struct scull_dev *dev = &scull_s_device.
if the structure itself contains a variable of type struct pc_device *dev,the above statement populates a similar variable and that is assigned to dev,
in my case i have declared a structure and related function as below
struct serial_card
{
unsigned int id; // to identify the each card
//atomic_t use_count; // variable used to check whether the device is already opened or not
wait_queue_head_t rx_queue[64]; // queue in which the process are stored
unsigned int data_ready[64]; // queue in which the process is ready
unsigned int rx_chan; // used by interrupt handler
unsigned int base, len; // holds physical base address , holds the total area ( for each card )
unsigned int *base; // holds virtual address
/*struct cdev cdev; // kernel uses this structure to represent the EACH char device
not using the new method to represent char devices in kernel instead using the old method of register_chrdev();*/
struct pci_dev *device; // pci_dev structure for EACH device.
//struct semaphore sem; //Semaphore needed to handle the co-ordination of processes,use incase need arises
};
static struct serial_card *serial_cards; // pointer to array of structures [ depending on number of cards ],NO_OF_CARDS #defined in header file
static int serialcard_open(struct inode *inode,struct file *filep)
{
//getting the structure details of type struct serialcard,using the pointer inode->i_cdev and field type cdev
//struct serial_card *serial_cards = container_of(inode->i_cdev, struct serial_card, cdev);
// read the current value of use_count
static int Device_Open = 0;
if ( Device_Open ) //Device_Open is static varibale used here for checking the no of times a device is opened
{
printk("cPCIserial: Open attempt rejected\n");
return -EBUSY;
}
Device_Open++;
// using the card so increment use_count
//atomic_inc(&serial_cards->use_count);
//filep->private_data = serial_cards;
return 0;
}
the complete description on page 174 - 175 is as follows
Single-Open Devices
The brute-force way to provide access control is to permit a device to be opened by
only one process at a time (single openness). This technique is best avoided because it
inhibits user ingenuity. A user might want to run different processes on the same
device, one reading status information while the other is writing data. In some cases,
users can get a lot done by running a few simple programs through a shell script, as
long as they can access the device concurrently. In other words, implementing a singleopen
behavior amounts to creating policy, which may get in the way of what your
users want to do. Allowing only a single process to open a device has undesirable properties, but it is also the easiest access control to implement for a device driver, so it’s shown here.
The source code is extracted from a device called scullsingle.
The scullsingle device maintains an atomic_t variable called scull_s_available; that
variable is initialized to a value of one, indicating that the device is indeed available.
The open call decrements and tests scull_s_available and refuses access if somebody
else already has the device open:
static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev = &scull_s_device; /* device information */
if (! atomic_dec_and_test (&scull_s_available)) {
atomic_inc(&scull_s_available);
return -EBUSY; /* already open */
}
/* then, everything else is copied from the bare scull device */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev);
filp->private_data = dev;
return 0; /* success */
}
The release call, on the other hand, marks the device as no longer busy:
static int scull_s_release(struct inode *inode, struct file *filp)
{
atomic_inc(&scull_s_available); /* release the device */
return 0;
}
Normally, we recommend that you put the open flag scull_s_available within the
device structure (Scull_Dev here) because, conceptually, it belongs to the device. The
scull driver, however, uses standalone variables to hold the flag so it can use the same
device structure and methods as the bare scull device and minimize code duplication.
Please let me know any alternative for this
thanks and regards
perhaps I am missing the point, but "cotainer_of" is not a function, but a macro. If you have porting concerns, you can safely define it by yourserlf if the system headers don't implement it. Here a basic implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif
Or here's the implementation - more accurate - from recent linux headers:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
In that code the containerof is used to store and retrieve the correct dev structure easily. The correct structure can be retrieved inside the read and write functions also without accessing to the private_data.
I do not know why you do not want to use private->data and containerof, but you can always retrieve your minor number from the struct file pointer.
int minor=MINOR(filp->f_dentry_d_inode->i__rdev);
then accessing to your multiple devices vector using something like
struct scull_dev* dev = &scull_devices[minor]:
and using it.
You will need to use filp->privatedata to store "per-open" information that you also use in read/write. You will need to decide what to store to ensure that the right information is available.
Probably you want two structures. One "device structure" and one "open structure". The open structure can get dynamically allocated in "open" and stored at private_data. In release, it gets freed. It should have the members such that you can use them in read/write to get access to the data you need.
The device structure is going to be per "card". In your driver init, you probably want to loop on the number of cards and create a new device structure (serial_card) for each. You can make them a static array, or dynamically allocate, it doesn't matter. I would store the minor number in the structure as well. The minor number is chosen by you, so start with 1 and go through #cards. You can reserve "0" for a system level interface, if you want, or just start at 0 for the cards.
In open, you will get the minor number that the user opened. Go through your serial_card list looking for a match. If you don't find it, error out of open. Otherwise, you have your info and can use it to allocate a "open structure", populate it, and store it in filp->private_data.
#Giuseppe Guerrini Some compiler just cannot recognize the linux implementation of container_of.
The basic define is fine, but I wonder if there is any safety or compatibility risk at this implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif

Resources