So, I have to do library sending IPv4 packets (without libraries with prepared headers) and problem is that I can't access field in struct inside struct while using function, though eclipse does not see error, hint does not show that is possible.
Structs:
struct packet{
struct ipv4hdr * iphdr;
struct icmphdr * icmphdr;
char * data;
};
struct ipv4hdr{
u_int8_t version_length;
u_int8_t type;
u_int16_t total_length;
u_int16_t id;
u_int16_t frag_off;
u_int8_t ttl;
u_int8_t protocol;
u_int16_t checksum;
u_int32_t source;
u_int32_t destination;
};
Pointers to function (that is requirement, both work):
struct packet *(*packetCreate)() = dlsym(lib, "createPacket");
void (*setIP)(struct packet *, u_int8_t, u_int8_t, u_int16_t, char*, u_int8_t, char*) = dlsym(lib, "prepareIP");
Creation of struct packet:
struct packet * createPacket(){
struct packet * pack= malloc(sizeof(struct packet));
return pack;
}
Now, calling fields inside main does show posssible fields:
struct packet * pack = packetCreate();
pack->iphdr->(CTRL+space displays all the fields) //and eclipse automatically corrects all the . to ->
Meanwhile calling created pointer on function does not display fields while using hint and that causes segmentation fault (core dumped):
void prepareIP(struct packet * packet, u_int8_t length, u_int8_t type, u_int16_t id, char* destination, u_int8_t ttl, char *data){
packet->iphdr->type = type; //it is not treated by error, though any field causes crash
//meanwhile hint
packet->iphdr->(CTRL+space gets)ipv4hdr;
}
Question again is why I can't call specific field inside function that points to the original struct and how to do this inside that function
It looks like you forgot to allocate space for struct ipv4hdr * iphdr;.
But maybe this isn't even what you intended. Do you really want iphdr to be a pointer in your struct? It makes mucht more sense, if it was part of the struct, like this:
struct packet{
struct ipv4hdr iphdr; // notice that we do not use pointers here!
struct icmphdr icmphdr; // this looks curious to me - we have either an IP or an ICMP package, why both headers in the same package?
char * data;
};
Related
I have browsed lots of questions regarding to container_of(), but did not find a question asking how to retrieve a struct within a struct using container_of(). If this question is duplicate, please point it out. Sorry for the inconvenience.
I am currently implementing a PCI device driver remove() function combined with another kernel module, with the following setup (I eliminated some other fields to make this question easy to read):
struct my_device {
struct mutex lock;
struct my_dev {
struct cdev cdev;
} my_dev;
struct pci {
struct cdev cdev;
struct pci_dev *pdev;
} pci;
};
Here comes the question: When we have a pointer to pdev within struct pci of type struct pci_dev *, how could we get struct pci, then get struct my_device? Note that in probe(struct pci_dev *dev, const struct pci_device_id *id), I had assigned dev to a previously allocated struct my_device *dev_ptr, i.e. dev_ptr->pci.pdev = dev;
I tried the following:
struct pci *pci_t;
pci_t = container_of(ptr, struct pci, pdev)
but that did not work.
The error message is as follows:
error: call to '__compiletime_assert_243' declared with attribute error: pointer type mismatch in container_of()
Any ideas would be appreciated.
Updates:
I tried the approaches in the comments. Since the remove() function of pci driver has a parameter - struct pci_dev *dev, which represents the corresponding pci device, I did the following:
struct my_device *mydev;
mydev = container_of(&dev, struct my_device, pci.pdev);
But it did not return the pointer to the correct structure to mydev.
This is a simplified definition of the container_of() macro:
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
The offsetof(type, member) macro is as described in the C standard and gives the number of bytes from the start of some structure type type to the start of some member of that type member. ptr should be compatible with a pointer to the type of the member (but the simplified version above does not care). (char *)(ptr) converts the pointer to a byte pointer pointing to the member so that the pointer subtraction (char *)(ptr) - offsetof(type, member) produces a byte pointer to the start of the containing structure type. Finally, the cast (type *) converts that pointer to the proper type.
An example of usage. Given:
struct my_device {
struct mutex lock;
struct my_dev {
struct cdev cdev;
} my_dev;
struct pci {
struct cdev cdev;
struct pci_dev *pdev;
} pci;
};
and a pointer to an allocated struct my_device:
struct my_device *mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
and a pointer to the pci.pdev member:
struct pci_dev **ppdev = &mydev->pci.pdev;
then it is possible to convert that back to a pointer to the containing struct my_device using container_of():
struct my_device *myd = container_of(ppdev, struct my_device, pci.pdev);
OP has something like this:
struct my_device *mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
mydev->pci.pdev = pcidev;
and is trying to get back to the struct my_device from the pointer pcidev as follows:
struct my_device *mydev = container_of(&pcidev, struct my_device, pci.pdev); /* wrong! */
That does not work because &pcidev is the address of the pcidev variable, not the address of the original mydev->pci.pdev member.
The Linux kernel allows a PCI device driver to associate an arbitrary void * value with a PCI device. That is normally done in the PCI device driver's probe() handler, something like this:
pci_set_drvdata(pcidev, mydev);
Then until the PCI device is removed from the driver, or the driver calls pci_set_drvdata with some other value, the pointer can be retrieved by a call to pci_get_drvdata():
struct my_device *mydev = pci_get_drvdata(pcidev);
More generally, pci_set_drvdata() and pci_get_drvdata() are just wrappers around dev_set_drvdata() and dev_get_drvdata() that associate an arbitrary void * value with a struct device. The struct pci_device structure definition contains a member struct device dev;. pci_set_drvdata(pcidev, ptr) is equivalent to dev_set_drvdata(&pcidev->dev, ptr), and pci_get_drvdata(pcidev) is equivalent to dev_get_drvdata(&pcidev->dev).
Often, driver code has a pointer to a struct device that it knows is embedded within a struct pci_dev, and it can use container_of() to get a pointer to the containing struct pci_dev:
/* dptr is pointing the the struct device inside a struct pci_dev. */
static void foo(struct device *dptr)
{
struct pci_dev *pcidev = container_of(dptr, struct pci_dev, dev);
/* ... */
}
If the driver has previously used pci_set_drvdata() or dev_set_drvdata(), it can use pci_get_drvdata() or dev_get_drvdata() to retrieve the set value:
static void foo(struct device *dptr)
{
struct pci_dev *pcidev = container_of(dptr, struct pci_dev, dev);
struct my_device *mydev = pci_get_drvdata(pcidev);
struct my_device *mydev1 = dev_get_drvdata(dptr);
/* (mydev == mydev1) is true */
struct pci_dev *pcidev1 = mydev->pci.pdev;
/* (pcidev == pcidev1) is true assuming mydev->pci.pdev was previously set to pcidev */
/* ... */
}
Although it works, it is probably bad style to mix pci_set_drvdata() with a previous call to dev_get_drvdata() or to mix pci_get_drvdata() with a previous call to dev_set_drvdata().
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am new to C programming and I am learning about pointers.
Can somebody please explain what the below code means?
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
/*The options start here. */
};
struct icmphdr
{
u_int8_t type; /* message type */
u_int8_t code; /* type sub-code */
u_int16_t checksum;
union
{
struct
{
u_int16_t id;
u_int16_t sequence;
} echo; /* echo datagram */
u_int32_t gateway; /* gateway address */
struct
{
u_int16_t __unused;
u_int16_t mtu;
} frag; /* path mtu discovery */
} un;
};
char datagram[4000];
struct iphdr *iph = (struct iphdr *) datagram;
struct icmphdr *icmphd = (struct icmphdr *) (datagram + sizeof (struct iphdr)); // what does this line do?
What does this do? Alphabets is the address of an array and we are adding some integer to it. What does it return on typecasting?
Record is some other structure.
Realy it is not a good practice to start C; but anyway:
char datagram[4000];
means 4000 elements of 8 bit.
struct iphdr *iph = (struct iphdr *) datagram;
this line tries to cast the address of the first element of the datagram array to a iphdr var. As iphdr contains 21 * 8bit, so from the first element till 21st element of datagram array will be accessible through iphdr structure with iph pointer. For example:
iph->tos is equal to datagram[2]
struct icmphdr *icmphd = (struct icmphdr *) (datagram + sizeof (struct iphdr));
this line means a jump from the start of the array till iphdr size; So it means that just exactly after the section of the array that is not accessible through iph pointer, will be accessible with icmphd pointer. As icmphdr is 8 byte, so 8 byte will accessible with icmphdr pointer. In another language, from the 22th element till the 29th element of the datagram array will be accessible through icmphdr structure. For example:
icmphd->code is equal to datagram[22]
icmphd->un.echo.id is equal to datagram[25],datagram[26]
icmphd->un.echo.gateway is equal to datagram[25],datagram[26],datagram[27],datagram[28]
icmphd->un.frag.mtu is equal to datagram[27],datagram[28]
this program tries to map a raw data(datagram) to structured data that have a specific meaning. Maybe you received datagram from a network, and the sender gave you the structure of that data as (iphdr and icmphdr)
I'm trying a test code that connects to a remote host with data given by gethostbyname() function. In examples I found they do the following:
struct hostent* pHostent = gethostbyname(host);
struct sockaddr_in remoteAddr;
// ... code
remoteAddr.sin_addr.s_addr = ((struct in_addr*) (pHostent->h_addr))->s_addr;
// ... more code
I'm trying to understand what's being done here.
Is it legal since data types are different? Maybe a memcpy()
should have been used?
Why does this work? Meaning what data
actually resides in both places?
We can start by looking at the actual struct layouts:
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype
int h_length;
char **h_addr_list;
}
#define h_addr h_addr_list[0]
struct sockaddr_in {
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct in_addr {
uint32_t s_addr; // IPv4 address
};
The gethostbyname() function can give you either IPv4 or IPv6 addresses, depending on the value of h_addrtype. So the h_addr_list need to be able to hold either IPv4 or IPv6 addresses. To accomplish this the addresses are stored as raw memory pointed to by char* pointers. To get the actual address, you need to cast the memory to the correct address type, as you found in your code:
remoteAddr.sin_addr.s_addr = ((struct in_addr*) (pHostent->h_addr))->s_addr;
So to answer your questions:
The pointer types are different, but the data pointed to are the same type.
No, the data is in one place only, it's just referenced to by pointers of different type.
I am attempting to find the MAC address using pcap for a small project. As of right now the structure I am working with looks like this:
struct ethernet_header
{
u_char dhost[6];
u_char shost[6];
u_short type;
};
The call int the code simply loosk like:
void get_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
const struct ethernet_header *ethernet;
const struct ip_header *ip;
ethernet = (struct ethernet_header *)(packet);
ip = (struct ip_header *)(packet + 16);
printf("Destination MAC: %s\n", ethernet->dhost);
}
The error I am receiveing is
error: dereferencing pointer to incomplete type
Now as far as I know the packet var is being initalized properly because it is being used in other sections of the code without a problem. In the case of the ip struct, this also works fine with no errors. I know what is being loaded into that particluar address I just can't figure out whats going on. Anyone have any ideas.
error: dereferencing pointer to incomplete type
You missed including the header file which defines struct ethernet_header in the c file which has the function void get_packet().
The error is because the compiler cannot see the definition of the structure, most likely you are just forward declaring it. However, Since you dereference the pointer to structure the compiler must know the layout of the structure and hence must see the definition of the structure.
So just include it You need to include the header file which contains the definition of the structure in this particular c file.
These 2 lines are vulnerable to this type of error. Compiler is unable to typecast the data in any or both statements. typecast it with correct datatype, it will work.
ethernet = (struct ethernet_header *)(packet);
ip = (struct ip_header *)(packet + 16);
struct sniff_ip {
struct in_addr ip_src, ip_dst;
}
function{
const struct sniff_ip *ip;
ip = (struct sniff_ip*)(packet +SIZE_ETHERNET);
}
My goal here is to change the values of ip_src and ip_dst, but I can't figure out the correct syntax to modify src or dst when it is in a struct within a struct. I know to access a member within a struct is normally ip->member or (*ip).member , but this doesn't seem to be working for me here. What are the correct procedure(s) for accessing members in the event they are in a struct within a struct?
Edit: I want to change the ip addresses (values) for both src and dst. When using lines such as
"ip->ip_src="
or
"ip->ip_src.s_addr=" , I get the error that
"assignment of read-only location '*ip'
You simply combine the operator in the correct places:
ip->ip_src.s_addr
struct in_addr other_addr;
ip->ip_src = other_addr;
You problem is:
const struct sniff_ip *ip;
instead of:
struct sniff_ip const *ip = ...;
In your current declaration, you have ip, a pointer to a const data of type struct sniff_ip.