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.
Related
I'm working with a few kernel modules (4.19.97) and I allocate struct my_sock like the following.
struct my_target {
union thingA { ... } a;
struct thingB *b;
};
struct my_sock {
struct sock sk;
// ...
struct my_target target;
};
struct my_sock *my_s;
my_s = my_sock_alloc();
// ...
my_s->sk.sk_prot->init(sk);
The above ends up calling this callback.
static int my_init(struct sock *sk)
{
// I do the following because I cannot pass in the allocated
// `struct my_sock` into this function.
struct my_sock *ms = my_sk(sk);
// I want to access my_s->my_target or any field within
// `struct my_target` here, but at this point, `ms` is
// pointing to the the first member of `struct my_sock`, and
// not the originally allocated `my_s`.
ms->target.a;
}
static inline struct my_sock* my_sk(const struct sock *s)
{
return container_of(s, struct my_sock, sk);
}
// Here's how my_s gets allocated. Note that this is not the same
// structure as the first member of `struct my_sock`.
struct my_sock* my_sock_alloc(void)
{
struct my_sock *sk = NULL;
sk = kmem_cache_zalloc(my_sk_cachep, GFP_KERNEL);
if (!sk)
return NULL;
return sk;
}
And here's the problem. The kernel has the code for container_of within include/linux/kernel.h which casts a member of a structure out to the containing structure, per the commentary.
When I use my_sk(sk), I get the pointer address of the first member of the containing struct. The problem is that this is a different address than my_s which I allocated in the very first line and I need the pointer to my_s in order to access the target member.
Thoughts as to how I might access my_s->target within the call my_init() (and not make things global)?
since sk is the very first field in struct my_sock, you can just cast the pointer and things should work:
struct my_sock *ms = (struct my_sock *)sk;
the extra work done in container_of is only needed when the "base" struct is not the first field.
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.
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;
};
Found this answer here:
sizeof a struct member
Copied it completely into my code, but my compiler objects that I have a pointer to an incomplete class type.
uint8_t clStructCount = sizeof(((struct ALMConfStr *) 0)->IntelRecsPerPg);
What am I doing wrong? I want to set clStructCount equal to the value of IntelRecsPerPg at runtime; I thought this was the trick to do so.
Thanks!
The definition of your structure needs to be visible at the point where the compiler encounters your sizeof code.
So, this translation unit should work:
struct ALMConfStr {
int IntelRecsPerPg[MagicNumber];
};
// ...
uint8_t clStructCount = sizeof(((struct ALMConfStr *) 0)->IntelRecsPerPg);
whether it's all in one file, or the struct is in a header #included before your sizeof code.
However, this:
struct ALMConfStr;
// ...
uint8_t clStructCount = sizeof(((struct ALMConfStr *) 0)->IntelRecsPerPg);
won't work, because the compiler doesn't know what a struct ALMConfStr consists of, or what an IntelRecsPerPg might be in that context.
From a comment on Useless' answer:
From my header file:
typedef struct ALMConfStruct {
uint8_t updateMode;
uint8_t flashPgSize;
uint8_t flashMaxPagesSize;
uint8_t IntelRecsPerPg;
fptr_t appResetAddr;
uint16_t appEndAddr;
uint8_t comIntf;
}ALMConfStr;
Your struct tag is ALMConfStruct and not ALMConfStr, so
struct ALMConfStr
declares a new incomplete struct type. Remove the struct, or use struct ALMConfStruct in your code to determine the size.
uint8_t clStructCount = sizeof(((ALMConfStr *) 0)->IntelRecsPerPg);
or
uint8_t clStructCount = sizeof(((struct ALMConfStruct *) 0)->IntelRecsPerPg);
I think there is no definition of struct ALMConfStr
or IntelRecsPerPg is not a member of struct ALMConfStr
Say
struct ALMConfStr{
//some member variables
data_type IntelRecsPerPg;
//some more member variables
};
Basically sizeof(((struct ALMConfStr *) 0)->IntelRecsPerPg) tries to get the
sizeof(IntelRecsPerPg)
in the structure assuming that the structure is available at address 0.
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);