4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * @file generic-netlink.c
23 * @desc User space code for ktgrabber logic
25 * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
30 #include <data_usage.h>
32 #include <sys/socket.h> /*for netlink.h*/
33 #include <linux/netlink.h>
34 #include <linux/genetlink.h>
35 #include <linux/rtnetlink.h>
37 #include <netinet/in.h>
38 #include <sys/types.h>
44 #include "net-cls-cgroup.h"
46 #include "generic-netlink.h"
51 #include "transmission.h"
53 #define NESTED_MCAST_MAX 256
54 #define MAX_PAYLOAD 1024 /* maximum payload size */
57 * @desc accepts opaque pointer
60 inline int netlink_get_command(struct genl *nl_ans)
65 uint32_t netlink_get_family(struct genl *nl_ans)
67 return nl_ans->n.nlmsg_type;
70 static void fill_traf_stat_list(char *buffer, __u16 count,
71 traffic_stat_tree *stats)
73 struct traffic_event *cur = (struct traffic_event *)buffer;
76 struct traffic_stat *to_insert;
77 struct classid_iftype_key *key;
79 to_insert = g_new(struct traffic_stat, 1);
81 _D("Can't allocate %d bytes for traffic_stat\n", sizeof(struct traffic_stat));
85 key = g_new(struct classid_iftype_key, 1);
88 _D("Can't allocate %d bytes for classid_iftype_key\n", sizeof(struct classid_iftype_key));
89 g_free((gpointer)to_insert);
93 to_insert->bytes = cur->bytes;
94 to_insert->ifindex = cur->ifindex;
95 key->classid = cur->sk_classid ?
96 cur->sk_classid : RSML_UNKNOWN_CLASSID;
97 key->iftype = get_iftype(cur->ifindex);
98 g_tree_insert((GTree *) stats, (gpointer)key, to_insert);
105 * Send netlink message to kernel
107 static int send_message(int fd, const char *message, int msg_len)
109 struct sockaddr_nl nl_addr;
112 memset(&nl_addr, 0, sizeof(nl_addr));
113 nl_addr.nl_family = AF_NETLINK;
116 sendto(fd, message, msg_len, 0, (struct sockaddr *)&nl_addr,
117 sizeof(nl_addr))) < msg_len) {
118 if (ret <= 0 && errno != EAGAIN)
120 else if (errno == EAGAIN)
130 * Probe the controller in genetlink to find the family id
131 * for the TRAF_STAT family
134 uint32_t get_family_id(int sock, pid_t pid,
137 uint32_t family_id = 0;
138 uint32_t UNUSED group_id = get_family_group_id(sock, pid, family_name, NULL,
143 static int extract_group_id(const struct rtattr *rt_na, const char *group_name,
146 struct rtattr *multicast_group_family[__CTRL_ATTR_MCAST_GRP_MAX] = {0};
148 struct rtattr *rt_nested;
154 rt_nested = RTA_DATA(rt_na); /* nested */
155 rt_len = RTA_PAYLOAD(rt_na);
157 fill_attribute_list(multicast_group_family,
158 CTRL_ATTR_MCAST_GRP_MAX, rt_nested, rt_len);
160 if (!multicast_group_family[CTRL_ATTR_MCAST_GRP_NAME] ||
161 !multicast_group_family[CTRL_ATTR_MCAST_GRP_ID])
164 name = RTA_DATA(multicast_group_family[CTRL_ATTR_MCAST_GRP_NAME]);
166 if (strcmp(name, group_name))
169 *group_id = *((__u32 *)RTA_DATA(
170 multicast_group_family[CTRL_ATTR_MCAST_GRP_ID]));
171 return RESOURCED_ERROR_NONE;
176 * check subattribute CTRL_ATTR_MCAST_GROUPS
177 * if it exists we are dealing with broadcast generic
179 * message format is following
180 * CTRL_ATTR_MCAST_GROUPS
182 * CTRL_ATTR_MCAST_GRP_NAME
183 * CTRL_ATTR_MCAST_GRP_ID
185 * CTRL_ATTR_MCAST_GRP_NAME
186 * CTRL_ATTR_MCAST_GRP_ID
189 static uint32_t get_mcast_group_id(struct rtattr *mc_na, const char *group_name)
191 struct rtattr *rt_na = RTA_DATA(mc_na); /* nested */
192 int rt_len = RTA_PAYLOAD(mc_na);
196 struct rtattr *multicast_general_family[NESTED_MCAST_MAX + 1] = {0};
198 fill_attribute_list(multicast_general_family, NESTED_MCAST_MAX,
202 for (i = 0; i < NESTED_MCAST_MAX; ++i) {
203 /* if this group is valid */
204 if (!multicast_general_family[i])
207 ret = extract_group_id(multicast_general_family[i], group_name,
209 if (ret == RESOURCED_ERROR_NONE)
216 uint32_t get_family_group_id(int sock, pid_t pid,
217 char *family_name, char *group_name,
220 struct genl family_req;
223 struct nlattr *na = 0;
224 int rep_len = 0, ret;
225 struct rtattr *general_family[__CTRL_ATTR_MAX] = {0};
226 struct rtattr *rt_na;
229 ret_value_msg_if(sock < 0, 0, "Please provide valid socket!");
231 family_req.n.nlmsg_type = GENL_ID_CTRL;
232 family_req.n.nlmsg_flags = NLM_F_REQUEST;
233 family_req.n.nlmsg_seq = seq++;
234 family_req.n.nlmsg_pid = pid;
235 family_req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
236 family_req.g.cmd = CTRL_CMD_GETFAMILY;
238 na = (struct nlattr *)GENLMSG_DATA(&family_req);
239 na->nla_type = CTRL_ATTR_FAMILY_NAME;
241 na->nla_len = strlen(family_name) + 1 + NLA_HDRLEN;
242 strcpy(NLA_DATA(na), family_name);
244 family_req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
246 ret = send_message(sock, (char *)&family_req, family_req.n.nlmsg_len);
248 ret_value_msg_if(ret < 0, 0, "Failed to send GETFAMILY command");
250 rep_len = recv(sock, &ans, sizeof(ans), 0);
252 ret_value_msg_if(rep_len < 0, 0,
253 "Failed to receive answer for GETFAMILY command");
255 /* Validate response message */
256 if (!NLMSG_OK((&ans.n), rep_len)) {
257 _E("Invalid reply message\n");
261 ret_value_msg_if(ans.n.nlmsg_type == NLMSG_ERROR, 0,
262 "Invalid netlink message format");
264 rt_na = (struct rtattr *)GENLMSG_DATA(&ans);
266 fill_attribute_list(general_family, CTRL_ATTR_MAX, rt_na, rep_len);
268 /* family id for netlink is 16 bits long for multicast is 32 bit */
269 if (general_family[CTRL_ATTR_FAMILY_ID])
270 *family_id = *(__u16 *)RTA_DATA(
271 general_family[CTRL_ATTR_FAMILY_ID]);
273 /* group name wasn't requested */
277 if (!general_family[CTRL_ATTR_MCAST_GROUPS])
280 return get_mcast_group_id(general_family[CTRL_ATTR_MCAST_GROUPS],
285 static void show_result(const struct genl *ans)
287 /*parse reply message */
288 struct nlattr *na = NULL;
292 _D ("Please provide valid argument!");
296 na = (struct nlattr *)GENLMSG_DATA(ans);
297 result = (char *)NLA_DATA(na);
299 _D("Initialization result: %s\n", result);
301 _D("Failed to show initialization result!");
303 #else /* Release build */
304 static void show_result(const struct genl *ans)
309 static resourced_ret_c send_common_cmd(int sock, const pid_t pid,
310 const uint32_t family_id, const __u8 cmd)
315 ret_value_msg_if(sock < 0, RESOURCED_ERROR_NONE,
316 "Please provide valid socket!");
318 r = send_command(sock, pid, family_id, cmd);
320 ret_value_errno_msg_if(r < 0, RESOURCED_ERROR_FAIL,
321 "Failed to send command");
323 /* Read message from kernel */
324 r = recv(sock, &ans, sizeof(ans), MSG_DONTWAIT);
326 ret_value_errno_msg_if(r < 0, RESOURCED_ERROR_FAIL,
327 "Cant receive message from kernel");
329 ret_value_msg_if(ans.n.nlmsg_type == NLMSG_ERROR, RESOURCED_ERROR_FAIL,
330 "Netlink format error");
332 ret_value_msg_if(!NLMSG_OK((&ans.n), r), RESOURCED_ERROR_FAIL,
333 "Invalid reply message received via Netlink");
336 return RESOURCED_ERROR_NONE;
339 static resourced_ret_c run_net_activity(const __u8 cmd)
345 sock = create_netlink(NETLINK_GENERIC, 0);
347 ret_value_msg_if(sock < 0, RESOURCED_ERROR_FAIL,
348 "Failed to create netlink socket");
350 family_id = get_family_id(sock, pid, "NET_ACTIVITY");
352 _E("Invalid family id number");
354 return RESOURCED_ERROR_FAIL;
356 /* send without handling response */
357 ret = send_command(sock, pid, family_id, cmd);
359 if (ret != RESOURCED_ERROR_NONE) {
360 ETRACE_ERRNO_MSG("Failed to send \
361 net_activity command %u", cmd);
362 /* send_command return errno */
363 ret = RESOURCED_ERROR_FAIL;
371 resourced_ret_c start_net_activity(void)
373 return run_net_activity(NET_ACTIVITY_C_START);
376 resourced_ret_c stop_net_activity(void)
378 return run_net_activity(NET_ACTIVITY_C_STOP);
382 void send_start(int sock, const pid_t pid, const int family_id)
384 send_common_cmd(sock, pid, family_id, TRAF_STAT_C_START);
387 int send_command(int sock, const pid_t pid, const int family_id, __u8 cmd)
391 struct sockaddr_nl nladdr;
392 const char *message = "INIT";
393 const int mlength = sizeof(message) + 1;
395 ret_value_msg_if(sock < 0, RESOURCED_ERROR_NONE,
396 "Please provide valid socket!");
398 /* Send command needed */
399 req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
400 req.n.nlmsg_type = family_id;
401 req.n.nlmsg_flags = NLM_F_REQUEST;
402 req.n.nlmsg_seq = 60;
403 req.n.nlmsg_pid = pid;
406 /* compose message */
407 na = (struct nlattr *)GENLMSG_DATA(&req);
409 na->nla_len = mlength + NLA_HDRLEN; /* message length */
410 memcpy(NLA_DATA(na), message, mlength);
411 req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
414 memset(&nladdr, 0, sizeof(nladdr));
415 nladdr.nl_family = AF_NETLINK;
417 return sendto(sock, (char *)&req, req.n.nlmsg_len, 0,
418 (struct sockaddr *)&nladdr, sizeof(nladdr));
421 int send_restriction(int sock, const pid_t pid, const int family_id,
422 const u_int32_t classid, const int ifindex,
423 const enum traffic_restriction_type restriction_type,
424 const int send_limit, const int rcv_limit,
425 const int snd_warning_threshold, const int rcv_warning_threshold)
428 struct traffic_restriction rst = {
429 .sk_classid = classid,
430 .type = restriction_type,
432 .send_limit = send_limit,
433 .rcv_limit = rcv_limit,
434 .snd_warning_threshold = snd_warning_threshold,
435 .rcv_warning_threshold = rcv_warning_threshold,
439 struct sockaddr_nl nladdr;
440 int mlength = 0, r = 0;
443 _D("Can't use socket\n");
447 /* Send command needed */
448 req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
449 req.n.nlmsg_type = family_id;
450 req.n.nlmsg_flags = NLM_F_REQUEST;
451 req.n.nlmsg_seq = 60;
452 req.n.nlmsg_pid = pid;
453 req.g.cmd = TRAF_STAT_C_SET_RESTRICTIONS;
456 na = (struct nlattr *)GENLMSG_DATA(&req);
457 na->nla_type = TRAF_STAT_DATA_RESTRICTION;
458 mlength = sizeof(struct traffic_restriction); /* * classid_count; */
459 na->nla_len = mlength + NLA_HDRLEN;
461 memcpy(NLA_DATA(na), &rst, sizeof(struct traffic_restriction));
462 req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
466 memset(&nladdr, 0, sizeof(nladdr));
467 nladdr.nl_family = AF_NETLINK;
469 /*use send_message */
470 r = sendto(sock, (char *)&req, req.n.nlmsg_len, 0,
471 (struct sockaddr *)&nladdr, sizeof(nladdr));
472 _D("Restriction send to kernel, result: %d", r);
476 static void _process_answer(struct netlink_serialization_params *params)
478 struct genl *nl_ans = params->ans;
479 traffic_stat_tree *stats = params->stat_tree;
482 struct nlattr *first_na, *second_na;
486 remains = GENLMSG_PAYLOAD(&nl_ans->n);
490 /* parse reply message */
491 first_na = (struct nlattr *)GENLMSG_DATA(nl_ans);
493 /* inline nla_next() */
494 first_len = NLA_ALIGN(first_na->nla_len);
496 second_na = (struct nlattr *) ((char *) first_na + first_len);
497 remains -= first_len;
499 /* but we need data_attr->nla_len */
500 buffer = (char *) malloc((size_t)remains);
504 if (first_na->nla_type == TRAF_STAT_COUNT) {
505 count = *(__u16 *) NLA_DATA(first_na);
506 memcpy(buffer, (char *) NLA_DATA(second_na),
509 _D("Expected attribute %d got %d", TRAF_STAT_COUNT, first_na->nla_type);
513 fill_traf_stat_list(buffer, count, stats);
518 netlink_serialization_command *netlink_create_command(
519 struct netlink_serialization_params *params)
521 static netlink_serialization_command command = {0,};
522 const int netlink_command = netlink_get_command(params->ans);
524 command.params = *params;
526 if (netlink_command == TRAF_STAT_C_GET_CONN_IN) {
527 command.deserialize_answer = _process_answer;
528 command.params.stat_tree = params->carg->in_tree;
529 } else if (netlink_command == TRAF_STAT_C_GET_PID_OUT) {
530 command.deserialize_answer = _process_answer;
531 command.params.stat_tree = params->carg->out_tree;
533 _E("Unknown command!");
540 resourced_ret_c process_netlink_restriction_msg(const struct genl *ans,
541 struct traffic_restriction *restriction, uint8_t *command)
544 struct rtattr *attr_list[__RESTRICTION_NOTI_A_MAX] = {0};
546 int len = GENLMSG_PAYLOAD(&ans->n);
548 if (!restriction || !command)
549 return RESOURCED_ERROR_INVALID_PARAMETER;
552 return RESOURCED_ERROR_INVALID_PARAMETER;
554 *command = ans->g.cmd;
556 /* parse reply message */
557 na = (struct rtattr *)GENLMSG_DATA(ans);
559 fill_attribute_list(attr_list, __RESTRICTION_NOTI_A_MAX - 1,
562 ret_value_msg_if(!attr_list[RESTRICTION_A_CLASSID], RESOURCED_ERROR_FAIL,
563 "Restriction netlink message doesn't contain mandatory classid.");
565 restriction->sk_classid = *(uint32_t *)RTA_DATA(
566 attr_list[RESTRICTION_A_CLASSID]);
568 if (attr_list[RESTRICTION_A_IFINDEX])
569 restriction->ifindex = *(int *)RTA_DATA(
570 attr_list[RESTRICTION_A_IFINDEX]);
572 return RESOURCED_ERROR_NONE;
575 enum net_activity_recv recv_net_activity(int sock, struct net_activity_info
576 *activity_info, const uint32_t net_activity_family_id)
578 int ans_len, traffic_type;
579 struct traffic_event *event;
580 struct nlattr *na = 0;
584 ans_len = recv(sock, &ans, sizeof(ans),
587 if (ans_len <= 0 || !NLMSG_OK((&ans.n), ans_len)) {
588 ETRACE_ERRNO_MSG("Failed to read netlink socket %d",
590 return RESOURCED_NET_ACTIVITY_STOP;
593 _D("Reading multicast netlink message len %d", ans_len);
595 family_id = netlink_get_family(&ans);
597 if (family_id != net_activity_family_id) {
598 _D("Received family_id %d", family_id);
599 return RESOURCED_NET_ACTIVITY_CONTINUE;
602 na = (struct nlattr *)GENLMSG_DATA(&ans);
604 traffic_type = na->nla_type;
606 event = (struct traffic_event *) NLA_DATA(na);
607 activity_info->type = traffic_type;
608 activity_info->bytes = event->bytes;
609 activity_info->iftype = get_iftype(event->ifindex);
610 activity_info->appid = get_app_id_by_classid(event->sk_classid, true);
612 return RESOURCED_NET_ACTIVITY_OK;