tizen 2.3 release
[framework/system/deviced.git] / src / logd / src / shared / netlink.c
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6
7 #include "core/log.h"
8 #include "netlink.h"
9
10 int create_netlink_socket(int protocol, int groups, int pid)
11 {
12         int sock;
13         int flags;
14         struct sockaddr_nl local;
15         int buf_size = 1024*1024;
16
17         sock = socket(AF_NETLINK, SOCK_RAW, protocol);
18         if (sock < 0) {
19                 int ret = -errno;
20                 _E("socket failed: %s", strerror(errno));
21                 return ret;
22         }
23         if ((flags = fcntl(sock, F_GETFL, 0)) < 0) {
24                 int ret = -errno;
25                 _E("fcntl failed");
26                 close(sock);
27                 return ret;
28         }
29
30         if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) != 0) {
31                 int ret = -errno;
32                 _E("fcntl failed: %s", strerror(errno));
33                 close(sock);
34                 return ret;
35         }
36         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&buf_size, sizeof(buf_size)) < 0)
37                 return -1;
38
39         if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&buf_size, sizeof(buf_size)) < 0)
40                 return -1;
41
42         bzero(&local, sizeof(struct sockaddr_nl));
43         local.nl_family = AF_NETLINK;
44         local.nl_groups = groups;
45         local.nl_pid = pid;
46
47         if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0) {
48                 int ret = -errno;
49                 _E("bind failed: %s", strerror(errno));
50                 close(sock);
51                 return ret;
52         }
53
54         return sock;
55 }
56
57 int send_cmd(int sock, unsigned short family_id, pid_t pid, __u8 cmd,
58          unsigned short nl_type, void *nl_data, int nl_len)
59 {
60         struct nlattr *attr;
61         struct sockaddr_nl addr;
62         int ret = 0;
63         int len;
64         char *buffer;
65
66         struct msgtemplate message;
67
68         message.g.cmd = cmd;
69         message.g.version = 1;
70         message.n.nlmsg_flags = NLM_F_REQUEST;
71         message.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
72         message.n.nlmsg_pid = pid;
73         message.n.nlmsg_seq = 0;
74         message.n.nlmsg_type = family_id;
75
76         attr = (struct nlattr *) GENLMSG_DATA(&message);
77         attr->nla_type = nl_type;
78         attr->nla_len = nl_len + 1 + NLA_HDRLEN;
79
80         memcpy(NLA_DATA(attr), nl_data, nl_len);
81         message.n.nlmsg_len += NLMSG_ALIGN(attr->nla_len);
82
83         buffer = (char *) &message;
84         len = message.n.nlmsg_len;
85         memset(&addr, 0, sizeof(addr));
86         addr.nl_family = AF_NETLINK;
87
88         for (; ret < len; buffer += ret, len -= ret) {
89                 ret = sendto(sock, buffer, len, 0, (struct sockaddr *) &addr,
90                         sizeof(addr));
91                 if (ret < 0 && errno != EAGAIN)
92                         return -errno;
93         }
94
95         return 0;
96 }
97
98 int get_family_id(int sock, const char *name)
99 {
100         struct {
101                 struct nlmsghdr n;
102                 struct genlmsghdr g;
103                 char buf[256];
104         } ans;
105
106         struct nlattr *na;
107         int id = 0, rc;
108         int rep_len;
109
110         rc = send_cmd(sock, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
111                         CTRL_ATTR_FAMILY_NAME, (void *)name, strlen(name) + 1);
112         if (rc < 0) {
113                 _E("send_cmd error");
114                 return rc;
115         }
116
117         rep_len = recv(sock, &ans, sizeof(ans), 0);
118         if (rep_len < 0 || ans.n.nlmsg_type == NLMSG_ERROR ||
119             !NLMSG_OK((&ans.n), (unsigned int)rep_len)) {
120                 _E("recv error");
121                 return -errno;
122         }
123
124         na = (struct nlattr *) GENLMSG_DATA(&ans);
125         na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
126
127         if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
128                 id = *(__u16 *) NLA_DATA(na);
129         }
130
131         return id;
132 }