Reference
flexible struct arrary as a memeber of another struct
Is using flexible array memebers in C bad practice?
My summary on Flexible array
What is a flexible array?
1 2 3 4 5 6 7 8 9 10 11
|
struct ethtool_sfeatures { __u32 cmd; __u32 size; struct ethtool_set_features_block features[]; };
|
struct ethtool_set_features_block features[]
is a flexible array.
is NOT a pointer, it is an in place array which is contiguous with the struct.
How to init a flexible array?
1 2 3 4 5 6 7 8 9
| struct Header { size_t d; long v[]; }; typedef struct Header Header; size_t n = 123;
Header *h = malloc(sizeof(Header) + sizeof(long[n])); h->n = n;
|
Or:
1
| Header *h = malloc(sizeof *h + n * sizeof h->v[0]);
|
Note that sizeof(Header) includes eventual padding bytes, thus, the following allocation is incorrect and may yield a buffer overflow:
1
| Header *h = malloc(sizeof(size_t) + sizeof(long[n]));
|
My example code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include <errno.h> #include <linux/ethtool.h> #include <linux/if.h> #include <linux/sockios.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h>
#define ETHTOOL_DEV_FEATURE_WORDS 2
static void ethnl_features_to_bitmap32(__u32 *dest, __u64 src) { unsigned int i;
for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++) { dest[i] = src >> (32 * i); } }
static int init_struct() { int sockfd; struct ifreq ifr; struct ethtool_sfeatures *cmd = malloc(sizeof *cmd + ETHTOOL_DEV_FEATURE_WORDS * sizeof cmd->features[0]);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf("socket error\n"); return -1; } strcpy(ifr.ifr_name, "net0"); printf("printf ifr_name: %s \n", ifr.ifr_name); cmd->cmd = ETHTOOL_SFEATURES; cmd->size = ETHTOOL_DEV_FEATURE_WORDS; __u32 valid[ETHTOOL_DEV_FEATURE_WORDS]; __u64 features = (1UL << 9); ethnl_features_to_bitmap32(valid, features); for (int i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++) { cmd->features[i].valid = valid[i]; cmd->features[i].requested = 0; } printf("printf ifr_name: %s \n", ifr.ifr_name); ifr.ifr_data = (char *)cmd; printf("printf ifr_name: %s \n", ifr.ifr_name); if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) { printf("ioctl error: %d\n", errno); close(sockfd); free(cmd); return -1; } close(sockfd); free(cmd); return -1; }
static int get_features() { int sockfd; struct ifreq ifr; struct ethtool_gfeatures *cmd = malloc(sizeof *cmd + ETHTOOL_DEV_FEATURE_WORDS * sizeof cmd->features[0]);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf("socket error\n"); return -1; } strcpy(ifr.ifr_name, "enp2s0");
cmd->cmd = ETHTOOL_GFEATURES; cmd->size = ETHTOOL_DEV_FEATURE_WORDS; ifr.ifr_data = (char *)cmd;
if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) { printf("ioctl error: %d\n", errno); close(sockfd); free(cmd); return -1; } close(sockfd); free(cmd); return -1; } int main(int argc, char *argv[]) { init_struct(); return EXIT_SUCCESS; }
|