1. Registering a family
Registering a family is including four steps: define the family, define operations, register the family, register the operations.
- Define the family, is just creating an instance of genl_family struct.
/* attributes */ enum { DOC_EXMPL_A_UNSPEC, DOC_EXMPL_A_MSG, __DOC_EXMPL_A_MAX, }; #define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1) /* attribute policy */ static struct nla_policy doc_exmpl_genl_policy[DOC_EXMPL_A_MAX + 1] = { [DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING }, }; /* family definition */ static struct genl_family doc_exmpl_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = "DOC_EXMPL", .version = 1, .maxattr = DOC_EXMPL_A_MAX, };
We define a new family and the family recognizes a single attribute, DOC_EXMPL_A_MSG, which is a NULL terminated string. The GENL_ID_GENERATE macro/constant is really just the value 0x0 and it signifies that we want the Generic Netlink controller to assign the channel number when we register the family.
- Define the operations for the family, which we do by creating at least one instance of the genl_ops structure.
/* handler */ static int doc_exmpl_echo(struct sk_buff *skb, struct genl_info *info) { /* message handling code goes here; return 0 on success, negative value on failure */ } /* commands */ enum { DOC_EXMPL_C_UNSPEC, DOC_EXMPL_C_ECHO, __DOC_EXMPL_C_MAX, }; #define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1) /* operation definition */ static struct genl_ops doc_exmpl_genl_ops_echo = { .cmd = DOC_EXMPL_C_ECHO, .flags = 0, .policy = doc_exmpl_genl_policy, .dumpit = NULL, };
Here we defined a single operation, DOC_EXMPL_C_ECHO, which uses the Netlink attribute policy we defined above. Once registered, this particular operation would call the doc_exmpl_echo() function whenever a DOC_EXMPL_C_ECHO message is sent to the DOC_EXMPL family over the Generic Netlink bus.
- Register teh DOC_EXMPL family with the Generic Netlink operation.
int rc; rc = genl_register_family(&doc_exmpl_gnl_family); if (rc != 0) goto failure;
This call registers the new family name with the Generic Netlink mechanism and requests a new channel number which is stored in the genl_family struct, replacing the GENL_ID_GENERATE value.
- Register the operations for the family.
int rc; rc = genl_register_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo); if (rc != 0) goto failure;
This call registers the DOC_EXMPL_C_ECHO operation in association with the DOC_EXMPL family. After this, other Generic Netlink users can now issue DOC_EXMPL_C_ECHO commands and they will be handled as desired.
2. Kernel communication
- Sending message is a three step process: allocate memory for the message buffer, create the message, send the message.
struct sk_buff *skb; skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) goto failure;
NLMSG_GOODSIZE is a good value to use when you don't know the size of the message buffer at the time of allocation. The genlmsg_new() function automatically adds space for the Netlink and Generic Netlink message headers.
int rc; void *msg_head; /* create the message headers */ msg_head = genlmsg_put(skb, pid, seq, type, 0, flags, DOC_EXMPL_C_ECHO, 1); if (msg_head == NULL) { rc = -ENOMEM; goto failure; } /* add a DOC_EXMPL_A_MSG attribute */ rc = nla_put_string(skb, DOC_EXMPL_A_MSG, "Generic Netlink Rocks"); if (rc != 0) goto failure; /* finalize the message */ genlmsg_end(skb, msg_head);
The genlmsg_put() function creates the required Netlink and Generic Netlink message headers, populating them with the given values; The nla_put_string() function is a standard Netlink attribute which adds a string attribute to the end of the Netlink message. The genlmsg_end() function updates the Netlink message header once the message payload has been finalized.
int rc; rc = genlmsg_unicast(skb, pid); if (rc != 0) goto failure;
- Receiving messages Typically, kernel modules act as Generic Netlink servers which means that the act of receiving messages is handled automatically by the Generic Netlink bus. Once the bus receives the message and determines the correct routing, the message is passed directly to the family specific operation callback for processing. If the kernel is acting as a Generic Netlink client, server response messages can be received over the Generic Netlink socket using standard kernel socket interfaces.