tizen 2.3 release
[kernel/api/system-resource.git] / src / network / generic-netlink.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 /*
21  * @file generic-netlink.c
22  *
23  * @desc User space code for ktgrabber logic
24  *
25  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
26  *
27  */
28
29 #include <errno.h>
30 #include <data_usage.h>
31 #include <glib.h>
32 #include <sys/socket.h> /*for netlink.h*/
33 #include <linux/netlink.h>
34 #include <linux/genetlink.h>
35 #include <linux/rtnetlink.h>
36 #include <net/if.h>
37 #include <netinet/in.h>
38 #include <sys/types.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <Ecore.h>
43
44 #include "net-cls-cgroup.h"
45 #include "const.h"
46 #include "generic-netlink.h"
47 #include "genl.h"
48 #include "iface.h"
49 #include "macro.h"
50 #include "trace.h"
51 #include "transmission.h"
52
53 #define NESTED_MCAST_MAX       256
54 #define MAX_PAYLOAD 1024        /* maximum payload size */
55
56 /**
57  * @desc accepts opaque pointer
58  * extracts command id
59  */
60 inline int netlink_get_command(struct genl *nl_ans)
61 {
62         return nl_ans->g.cmd;
63 }
64
65 uint32_t netlink_get_family(struct genl *nl_ans)
66 {
67         return nl_ans->n.nlmsg_type;
68 }
69
70 static void fill_traf_stat_list(char *buffer, __u16 count,
71                         traffic_stat_tree *stats)
72 {
73         struct traffic_event *cur = (struct traffic_event *)buffer;
74
75         while (count) {
76                 struct traffic_stat *to_insert;
77                 struct classid_iftype_key *key;
78
79                 to_insert = g_new(struct traffic_stat, 1);
80                 if (!to_insert) {
81                         _D("Can't allocate %d bytes for traffic_stat\n", sizeof(struct traffic_stat));
82                         return;
83                 }
84
85                 key = g_new(struct classid_iftype_key, 1);
86
87                 if (!key) {
88                         _D("Can't allocate %d bytes for classid_iftype_key\n", sizeof(struct classid_iftype_key));
89                         g_free((gpointer)to_insert);
90                         return;
91                 }
92
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);
99                 --count;
100                 ++cur;
101         }
102 }
103
104 /*
105  * Send netlink message to kernel
106  */
107 static int send_message(int fd, const char *message, int msg_len)
108 {
109         struct sockaddr_nl nl_addr;
110         int ret = 0;
111
112         memset(&nl_addr, 0, sizeof(nl_addr));
113         nl_addr.nl_family = AF_NETLINK;
114
115         while ((ret =
116                 sendto(fd, message, msg_len, 0, (struct sockaddr *)&nl_addr,
117                        sizeof(nl_addr))) < msg_len) {
118                 if (ret <= 0 && errno != EAGAIN)
119                         return ret;
120                 else if (errno == EAGAIN)
121                         continue;
122
123                 message += ret;
124                 msg_len -= ret;
125         }
126         return 0;
127 }
128
129 /*
130  * Probe the controller in genetlink to find the family id
131  * for the TRAF_STAT family
132  */
133
134 uint32_t get_family_id(int sock, pid_t pid,
135         char *family_name)
136 {
137         uint32_t family_id = 0;
138         uint32_t UNUSED group_id = get_family_group_id(sock, pid, family_name, NULL,
139                 &family_id);
140         return family_id;
141 }
142
143 static int extract_group_id(const struct rtattr *rt_na, const char *group_name,
144         uint32_t *group_id)
145 {
146         struct rtattr *multicast_group_family[__CTRL_ATTR_MCAST_GRP_MAX] = {0};
147         char *name;
148         struct rtattr *rt_nested;
149         int rt_len;
150
151         if (!rt_na)
152                 return -EINVAL;
153
154         rt_nested = RTA_DATA(rt_na); /* nested */
155         rt_len = RTA_PAYLOAD(rt_na);
156
157         fill_attribute_list(multicast_group_family,
158                 CTRL_ATTR_MCAST_GRP_MAX, rt_nested, rt_len);
159
160         if (!multicast_group_family[CTRL_ATTR_MCAST_GRP_NAME] ||
161             !multicast_group_family[CTRL_ATTR_MCAST_GRP_ID])
162                 return -EINVAL;
163
164         name = RTA_DATA(multicast_group_family[CTRL_ATTR_MCAST_GRP_NAME]);
165
166         if (strcmp(name, group_name))
167                 return -EINVAL;
168
169         *group_id = *((__u32 *)RTA_DATA(
170                 multicast_group_family[CTRL_ATTR_MCAST_GRP_ID]));
171         return RESOURCED_ERROR_NONE;
172 }
173
174
175 /*
176  * check subattribute CTRL_ATTR_MCAST_GROUPS
177  * if it exists we are dealing with broadcast generic
178  * netlink message
179  * message format is following
180  * CTRL_ATTR_MCAST_GROUPS
181  *  ATTR1
182  *    CTRL_ATTR_MCAST_GRP_NAME
183  *    CTRL_ATTR_MCAST_GRP_ID
184  *  ATTR2
185  *    CTRL_ATTR_MCAST_GRP_NAME
186  *    CTRL_ATTR_MCAST_GRP_ID
187  *  ...
188  */
189 static uint32_t get_mcast_group_id(struct rtattr *mc_na, const char *group_name)
190 {
191         struct rtattr *rt_na = RTA_DATA(mc_na); /* nested */
192         int rt_len = RTA_PAYLOAD(mc_na);
193         int i, ret;
194         uint32_t group_id;
195
196         struct rtattr *multicast_general_family[NESTED_MCAST_MAX + 1] = {0};
197
198         fill_attribute_list(multicast_general_family, NESTED_MCAST_MAX,
199                             rt_na, rt_len);
200
201         /* for each group */
202         for (i = 0; i < NESTED_MCAST_MAX; ++i) {
203                 /* if this group is valid */
204                 if (!multicast_general_family[i])
205                         continue;
206
207                 ret = extract_group_id(multicast_general_family[i], group_name,
208                         &group_id);
209                 if (ret == RESOURCED_ERROR_NONE)
210                         return group_id;
211         }
212
213         return 0;
214 }
215
216 uint32_t get_family_group_id(int sock, pid_t pid,
217                         char *family_name, char *group_name,
218                         uint32_t *family_id)
219 {
220         struct genl family_req;
221         struct genl ans;
222
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;
227         static uint32_t seq;
228
229         ret_value_msg_if(sock < 0, 0, "Please provide valid socket!");
230
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;
237
238         na = (struct nlattr *)GENLMSG_DATA(&family_req);
239         na->nla_type = CTRL_ATTR_FAMILY_NAME;
240
241         na->nla_len = strlen(family_name) + 1 + NLA_HDRLEN;
242         strcpy(NLA_DATA(na), family_name);
243
244         family_req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
245
246         ret = send_message(sock, (char *)&family_req, family_req.n.nlmsg_len);
247
248         ret_value_msg_if(ret < 0, 0, "Failed to send GETFAMILY command");
249
250         rep_len = recv(sock, &ans, sizeof(ans), 0);
251
252         ret_value_msg_if(rep_len < 0, 0,
253                 "Failed to receive answer for GETFAMILY command");
254
255         /* Validate response message */
256         if (!NLMSG_OK((&ans.n), rep_len)) {
257                 _E("Invalid reply message\n");
258                 return 0;
259         }
260
261         ret_value_msg_if(ans.n.nlmsg_type == NLMSG_ERROR, 0,
262                 "Invalid netlink message format");
263
264         rt_na = (struct rtattr *)GENLMSG_DATA(&ans);
265
266         fill_attribute_list(general_family, CTRL_ATTR_MAX, rt_na, rep_len);
267
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]);
272
273         /* group name wasn't requested */
274         if (!group_name)
275                 return 0;
276
277         if (!general_family[CTRL_ATTR_MCAST_GROUPS])
278                 return 0;
279
280         return get_mcast_group_id(general_family[CTRL_ATTR_MCAST_GROUPS],
281                 group_name);
282 }
283
284 #ifdef DEBUG_ENABLED
285 static void show_result(const struct genl *ans)
286 {
287         /*parse reply message */
288         struct nlattr *na = NULL;
289         char *result = NULL;
290
291         if (!ans) {
292                 _D ("Please provide valid argument!");
293                 return;
294         }
295
296         na = (struct nlattr *)GENLMSG_DATA(ans);
297         result = (char *)NLA_DATA(na);
298         if (result)
299                 _D("Initialization result: %s\n", result);
300         else
301                 _D("Failed to show initialization result!");
302 }
303 #else /* Release build */
304 static void show_result(const struct genl *ans)
305 {
306 }
307 #endif
308
309 static resourced_ret_c send_common_cmd(int sock, const pid_t pid,
310         const uint32_t family_id, const __u8 cmd)
311 {
312         struct genl ans;
313         int r;
314
315         ret_value_msg_if(sock < 0, RESOURCED_ERROR_NONE,
316                 "Please provide valid socket!");
317
318         r = send_command(sock, pid, family_id, cmd);
319
320         ret_value_errno_msg_if(r < 0, RESOURCED_ERROR_FAIL,
321                 "Failed to send command");
322
323         /* Read message from kernel */
324         r = recv(sock, &ans, sizeof(ans), MSG_DONTWAIT);
325
326         ret_value_errno_msg_if(r < 0, RESOURCED_ERROR_FAIL,
327                 "Cant receive message from kernel");
328
329         ret_value_msg_if(ans.n.nlmsg_type == NLMSG_ERROR, RESOURCED_ERROR_FAIL,
330                 "Netlink format error");
331
332         ret_value_msg_if(!NLMSG_OK((&ans.n), r), RESOURCED_ERROR_FAIL,
333                 "Invalid reply message received via Netlink");
334
335         show_result(&ans);
336         return RESOURCED_ERROR_NONE;
337 }
338
339 static resourced_ret_c run_net_activity(const __u8 cmd)
340 {
341         int sock;
342         uint32_t family_id;
343         resourced_ret_c ret;
344         pid_t pid;
345         sock = create_netlink(NETLINK_GENERIC, 0);
346
347         ret_value_msg_if(sock < 0, RESOURCED_ERROR_FAIL,
348                 "Failed to create netlink socket");
349         pid = getpid();
350         family_id = get_family_id(sock, pid, "NET_ACTIVITY");
351         if (!family_id) {
352                 _E("Invalid family id number");
353                 close(sock);
354                 return RESOURCED_ERROR_FAIL;
355         }
356         /* send without handling response */
357         ret = send_command(sock, pid, family_id, cmd);
358
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;
364         }
365
366         close(sock);
367
368         return ret;
369 }
370
371 resourced_ret_c start_net_activity(void)
372 {
373         return run_net_activity(NET_ACTIVITY_C_START);
374 }
375
376 resourced_ret_c stop_net_activity(void)
377 {
378         return run_net_activity(NET_ACTIVITY_C_STOP);
379 }
380
381
382 void send_start(int sock, const pid_t pid, const int family_id)
383 {
384         send_common_cmd(sock, pid, family_id, TRAF_STAT_C_START);
385 }
386
387 int send_command(int sock, const pid_t pid, const int family_id, __u8 cmd)
388 {
389         struct genl req;
390         struct nlattr *na;
391         struct sockaddr_nl nladdr;
392         const char *message = "INIT";
393         const int mlength = sizeof(message) + 1;
394
395         ret_value_msg_if(sock < 0, RESOURCED_ERROR_NONE,
396                 "Please provide valid socket!");
397
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;
404         req.g.cmd = cmd;
405
406         /* compose message */
407         na = (struct nlattr *)GENLMSG_DATA(&req);
408         na->nla_type = 1;
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);
412
413         /* send message */
414         memset(&nladdr, 0, sizeof(nladdr));
415         nladdr.nl_family = AF_NETLINK;
416
417         return sendto(sock, (char *)&req, req.n.nlmsg_len, 0,
418                       (struct sockaddr *)&nladdr, sizeof(nladdr));
419 }
420
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)
426 {
427         struct genl req;
428         struct traffic_restriction rst = {
429                 .sk_classid = classid,
430                 .type = restriction_type,
431                 .ifindex = ifindex,
432                 .send_limit = send_limit,
433                 .rcv_limit = rcv_limit,
434                 .snd_warning_threshold = snd_warning_threshold,
435                 .rcv_warning_threshold = rcv_warning_threshold,
436         };
437
438         struct nlattr *na;
439         struct sockaddr_nl nladdr;
440         int mlength = 0, r = 0;
441
442         if (sock < 0) {
443                 _D("Can't use socket\n");
444                 return -1;
445         }
446
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;
454
455         /*compose message */
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;
460
461         memcpy(NLA_DATA(na), &rst, sizeof(struct traffic_restriction));
462         req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
463
464         /*send message */
465
466         memset(&nladdr, 0, sizeof(nladdr));
467         nladdr.nl_family = AF_NETLINK;
468
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);
473         return r;
474 }
475
476 static void _process_answer(struct netlink_serialization_params *params)
477 {
478         struct genl *nl_ans = params->ans;
479         traffic_stat_tree *stats = params->stat_tree;
480         ssize_t remains;
481         char *buffer;
482         struct nlattr *first_na, *second_na;
483         int first_len;
484         int count = 0;
485
486         remains = GENLMSG_PAYLOAD(&nl_ans->n);
487         if (remains <= 0)
488                 return;
489
490         /* parse reply message */
491         first_na = (struct nlattr *)GENLMSG_DATA(nl_ans);
492
493         /* inline nla_next() */
494         first_len = NLA_ALIGN(first_na->nla_len);
495
496         second_na = (struct nlattr *) ((char *) first_na + first_len);
497         remains -= first_len;
498
499         /* but we need data_attr->nla_len */
500         buffer = (char *) malloc((size_t)remains);
501         if (buffer == NULL)
502                 return;
503
504         if (first_na->nla_type == TRAF_STAT_COUNT) {
505                 count = *(__u16 *) NLA_DATA(first_na);
506                 memcpy(buffer, (char *) NLA_DATA(second_na),
507                        second_na->nla_len);
508         } else {
509                 _D("Expected attribute %d got %d", TRAF_STAT_COUNT, first_na->nla_type);
510         }
511
512         if (count > 0)
513                 fill_traf_stat_list(buffer, count, stats);
514         free(buffer);
515
516 }
517
518 netlink_serialization_command *netlink_create_command(
519         struct netlink_serialization_params *params)
520 {
521         static netlink_serialization_command command = {0,};
522         const int netlink_command = netlink_get_command(params->ans);
523
524         command.params = *params;
525
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;
532         } else {
533                 _E("Unknown command!");
534                 return NULL;
535         }
536
537         return &command;
538 }
539
540 resourced_ret_c process_netlink_restriction_msg(const struct genl *ans,
541         struct traffic_restriction *restriction, uint8_t *command)
542 {
543         struct rtattr *na;
544         struct rtattr *attr_list[__RESTRICTION_NOTI_A_MAX] = {0};
545
546         int len = GENLMSG_PAYLOAD(&ans->n);
547
548         if (!restriction || !command)
549                 return RESOURCED_ERROR_INVALID_PARAMETER;
550
551         if (len <= 0)
552                 return RESOURCED_ERROR_INVALID_PARAMETER;
553
554         *command = ans->g.cmd;
555
556         /* parse reply message */
557         na = (struct rtattr *)GENLMSG_DATA(ans);
558
559         fill_attribute_list(attr_list, __RESTRICTION_NOTI_A_MAX - 1,
560                 na, len);
561
562         ret_value_msg_if(!attr_list[RESTRICTION_A_CLASSID], RESOURCED_ERROR_FAIL,
563                 "Restriction netlink message doesn't contain mandatory classid.");
564
565         restriction->sk_classid = *(uint32_t *)RTA_DATA(
566                         attr_list[RESTRICTION_A_CLASSID]);
567
568         if (attr_list[RESTRICTION_A_IFINDEX])
569                 restriction->ifindex = *(int *)RTA_DATA(
570                         attr_list[RESTRICTION_A_IFINDEX]);
571
572         return RESOURCED_ERROR_NONE;
573 }
574
575 enum net_activity_recv recv_net_activity(int sock, struct net_activity_info
576         *activity_info, const uint32_t net_activity_family_id)
577 {
578         int ans_len, traffic_type;
579         struct traffic_event *event;
580         struct nlattr *na = 0;
581         struct genl ans;
582         uint32_t family_id;
583
584         ans_len = recv(sock, &ans, sizeof(ans),
585                         MSG_DONTWAIT);
586
587         if (ans_len <= 0 || !NLMSG_OK((&ans.n), ans_len)) {
588                 ETRACE_ERRNO_MSG("Failed to read netlink socket %d",
589                         ans_len);
590                 return RESOURCED_NET_ACTIVITY_STOP;
591         }
592
593         _D("Reading multicast netlink message len %d", ans_len);
594
595         family_id = netlink_get_family(&ans);
596
597         if (family_id != net_activity_family_id) {
598                 _D("Received family_id %d", family_id);
599                 return RESOURCED_NET_ACTIVITY_CONTINUE;
600         }
601
602         na = (struct nlattr *)GENLMSG_DATA(&ans);
603
604         traffic_type = na->nla_type;
605
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);
611
612         return RESOURCED_NET_ACTIVITY_OK;
613 }