Verify that netlink messages are coming from kernel.
[v86d.git] / v86.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <time.h>
7 #include <fcntl.h>
8
9 #include <sys/socket.h>
10 #include <sys/poll.h>
11
12 #include <linux/netlink.h>
13 #include <linux/rtnetlink.h>
14
15 #include <arpa/inet.h>
16
17 #include "v86.h"
18
19 static int need_exit;
20 static __u32 seq;
21
22 static int netlink_send(int s, struct cn_msg *msg)
23 {
24         struct nlmsghdr *nlh;
25         unsigned int size;
26         int err;
27         char buf[CONNECTOR_MAX_MSG_SIZE];
28         struct cn_msg *m;
29
30         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
31
32         nlh = (struct nlmsghdr *)buf;
33         nlh->nlmsg_seq = seq++;
34         nlh->nlmsg_pid = getpid();
35         nlh->nlmsg_type = NLMSG_DONE;
36         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
37         nlh->nlmsg_flags = 0;
38
39         m = NLMSG_DATA(nlh);
40         memcpy(m, msg, sizeof(*m) + msg->len);
41
42         err = send(s, nlh, size, 0);
43         if (err == -1)
44                 ulog(LOG_ERR, "Failed to send: %s [%d].\n", strerror(errno), errno);
45
46         return err;
47 }
48
49 int req_exec(int s, struct cn_msg *msg)
50 {
51         struct uvesafb_task *tsk = (struct uvesafb_task*)(msg + 1);
52         u8 *buf = (u8*)tsk + sizeof(struct uvesafb_task);
53
54         if (tsk->flags & TF_EXIT)
55                 return 1;
56
57         if (v86_task(tsk, buf))
58                 return 2;
59
60         netlink_send(s, msg);
61
62         return 0;
63 }
64
65
66 int main(int argc, char *argv[])
67 {
68         char buf[CONNECTOR_MAX_MSG_SIZE];
69         int len, i, err = 0, s;
70         struct nlmsghdr *reply;
71         struct sockaddr_nl l_local;
72         struct cn_msg *data;
73         struct pollfd pfd;
74
75         s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
76         if (s == -1) {
77                 perror("socket");
78                 return -1;
79         }
80
81         l_local.nl_family = AF_NETLINK;
82         l_local.nl_groups = 1 << (CN_IDX_V86D-1); /* bitmask of requested groups */
83         l_local.nl_pid = 0;
84
85         if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) {
86                 perror("bind");
87                 close(s);
88                 return -1;
89         }
90
91         i = fork();
92         if (i) {
93                 exit(0);
94         }
95
96         setsid();
97         chdir("/");
98
99         openlog("v86d", 0, LOG_KERN);
100
101         if (v86_init())
102                 return -1;
103
104         memset(buf, 0, sizeof(buf));
105         pfd.fd = s;
106
107         while (!need_exit) {
108                 pfd.events = POLLIN;
109                 pfd.revents = 0;
110                 switch (poll(&pfd, 1, -1)) {
111                         case 0:
112                                 need_exit = 1;
113                                 continue;
114                         case -1:
115                                 if (errno != EINTR) {
116                                         need_exit = 1;
117                                         break;
118                                 }
119                                 continue;
120                 }
121
122                 memset(buf, 0, sizeof(buf));
123                 len = recv(s, buf, sizeof(buf), 0);
124                 if (len == -1) {
125                         perror("recv buf");
126                         err = -1;
127                         goto out;
128                 }
129
130                 reply = (struct nlmsghdr *)buf;
131
132                 /* Ignore requests coming from outside the kernel. */
133                 if (reply->nlmsg_pid != 0) {
134                         continue;
135                 }
136
137                 switch (reply->nlmsg_type) {
138                 case NLMSG_ERROR:
139                         ulog(LOG_ERR, "Error message received.\n");
140                         break;
141
142                 case NLMSG_DONE:
143                         data = (struct cn_msg *)NLMSG_DATA(reply);
144                         if (req_exec(s, data))
145                                 goto out;
146                         break;
147                 default:
148                         break;
149                 }
150         }
151
152 out:
153         v86_cleanup();
154
155         closelog();
156         close(s);
157         return err;
158 }