/** * rmnet_config_netlink_msg_handler() - Netlink message handler callback * @skb: Packet containing netlink messages * * Standard kernel-expected format for a netlink message handler. Processes SKBs * which contain RmNet data specific netlink messages. */ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) { struct nlmsghdr *nlmsg_header, *resp_nlmsg; struct rmnet_nl_msg_s *rmnet_header, *resp_rmnet; int return_pid, response_data_length; struct sk_buff *skb_response; response_data_length = 0; nlmsg_header = (struct nlmsghdr *) skb->data; rmnet_header = (struct rmnet_nl_msg_s *) nlmsg_data(nlmsg_header); LOGL("%s(): Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d\n", __func__, nlmsg_header->nlmsg_pid, nlmsg_header->nlmsg_seq, nlmsg_header->nlmsg_len, rmnet_header->message_type); return_pid = nlmsg_header->nlmsg_pid; skb_response = nlmsg_new(sizeof(struct nlmsghdr) + sizeof(struct rmnet_nl_msg_s), GFP_KERNEL); if (!skb_response) { LOGH("%s(): Failed to allocate response buffer\n", __func__); return; } resp_nlmsg = nlmsg_put(skb_response, 0, nlmsg_header->nlmsg_seq, NLMSG_DONE, sizeof(struct rmnet_nl_msg_s), 0); resp_rmnet = nlmsg_data(resp_nlmsg); if (!resp_rmnet) BUG(); resp_rmnet->message_type = rmnet_header->message_type; rtnl_lock(); switch (rmnet_header->message_type) { case RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE: _rmnet_netlink_associate_network_device (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE: _rmnet_netlink_unassociate_network_device (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT: _rmnet_netlink_set_link_egress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT: _rmnet_netlink_get_link_egress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT: _rmnet_netlink_set_link_ingress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT: _rmnet_netlink_get_link_ingress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_SET_LOGICAL_EP_CONFIG: _rmnet_netlink_set_logical_ep_config(rmnet_header, resp_rmnet); break; case RMNET_NETLINK_NEW_VND: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; resp_rmnet->return_code = rmnet_create_vnd(rmnet_header->vnd.id); break; default: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; resp_rmnet->return_code = RMNET_CONFIG_UNKNOWN_MESSAGE; break; } rtnl_unlock(); nlmsg_unicast(nl_socket_handle, skb_response, return_pid); }
/** * rmnet_config_netlink_msg_handler() - Netlink message handler callback * @skb: Packet containing netlink messages * * Standard kernel-expected format for a netlink message handler. Processes SKBs * which contain RmNet data specific netlink messages. */ void rmnet_config_netlink_msg_handler(struct sk_buff *skb) { struct nlmsghdr *nlmsg_header, *resp_nlmsg; struct rmnet_nl_msg_s *rmnet_header, *resp_rmnet; int return_pid, response_data_length; struct sk_buff *skb_response; response_data_length = 0; nlmsg_header = (struct nlmsghdr *) skb->data; rmnet_header = (struct rmnet_nl_msg_s *) nlmsg_data(nlmsg_header); LOGL("Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d", nlmsg_header->nlmsg_pid, nlmsg_header->nlmsg_seq, nlmsg_header->nlmsg_len, rmnet_header->message_type); return_pid = nlmsg_header->nlmsg_pid; skb_response = nlmsg_new(sizeof(struct nlmsghdr) + sizeof(struct rmnet_nl_msg_s), GFP_KERNEL); if (!skb_response) { LOGH("%s", "Failed to allocate response buffer"); return; } resp_nlmsg = nlmsg_put(skb_response, 0, nlmsg_header->nlmsg_seq, NLMSG_DONE, sizeof(struct rmnet_nl_msg_s), 0); resp_rmnet = nlmsg_data(resp_nlmsg); if (!resp_rmnet) BUG(); resp_rmnet->message_type = rmnet_header->message_type; rtnl_lock(); switch (rmnet_header->message_type) { case RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE: _rmnet_netlink_associate_network_device (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE: _rmnet_netlink_unassociate_network_device (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED: _rmnet_netlink_get_network_device_associated (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT: _rmnet_netlink_set_link_egress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT: _rmnet_netlink_get_link_egress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT: _rmnet_netlink_set_link_ingress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT: _rmnet_netlink_get_link_ingress_data_format (rmnet_header, resp_rmnet); break; case RMNET_NETLINK_SET_LOGICAL_EP_CONFIG: _rmnet_netlink_set_logical_ep_config(rmnet_header, resp_rmnet); break; case RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG: _rmnet_netlink_unset_logical_ep_config(rmnet_header, resp_rmnet); break; case RMNET_NETLINK_GET_LOGICAL_EP_CONFIG: _rmnet_netlink_get_logical_ep_config(rmnet_header, resp_rmnet); break; case RMNET_NETLINK_NEW_VND: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; resp_rmnet->return_code = rmnet_create_vnd(rmnet_header->vnd.id); break; case RMNET_NETLINK_NEW_VND_WITH_PREFIX: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; resp_rmnet->return_code = rmnet_create_vnd_prefix( rmnet_header->vnd.id, rmnet_header->vnd.vnd_name); break; case RMNET_NETLINK_FREE_VND: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; /* Please check rmnet_vnd_free_dev documentation regarding the below locking sequence */ rtnl_unlock(); resp_rmnet->return_code = rmnet_free_vnd(rmnet_header->vnd.id); rtnl_lock(); break; case RMNET_NETLINK_GET_VND_NAME: _rmnet_netlink_get_vnd_name(rmnet_header, resp_rmnet); break; case RMNET_NETLINK_DEL_VND_TC_FLOW: case RMNET_NETLINK_ADD_VND_TC_FLOW: _rmnet_netlink_add_del_vnd_tc_flow(rmnet_header->message_type, rmnet_header, resp_rmnet); break; default: resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; resp_rmnet->return_code = RMNET_CONFIG_UNKNOWN_MESSAGE; break; } rtnl_unlock(); nlmsg_unicast(nl_socket_handle, skb_response, return_pid); LOGD("%s", "Done processing command"); }