net/mlx5: change non failing function return values
[dpdk.git] / drivers / net / mlx5 / mlx5_socket.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016 6WIND S.A.
3  */
4
5 #define _GNU_SOURCE
6
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <sys/stat.h>
14
15 #include "mlx5.h"
16 #include "mlx5_utils.h"
17
18 /**
19  * Initialise the socket to communicate with the secondary process
20  *
21  * @param[in] dev
22  *   Pointer to Ethernet device.
23  *
24  * @return
25  *   0 on success, errno value on failure.
26  */
27 int
28 mlx5_socket_init(struct rte_eth_dev *dev)
29 {
30         struct priv *priv = dev->data->dev_private;
31         struct sockaddr_un sun = {
32                 .sun_family = AF_UNIX,
33         };
34         int ret;
35         int flags;
36         struct stat file_stat;
37
38         /*
39          * Initialise the socket to communicate with the secondary
40          * process.
41          */
42         ret = socket(AF_UNIX, SOCK_STREAM, 0);
43         if (ret < 0) {
44                 WARN("secondary process not supported: %s", strerror(errno));
45                 return ret;
46         }
47         priv->primary_socket = ret;
48         flags = fcntl(priv->primary_socket, F_GETFL, 0);
49         if (flags == -1)
50                 goto out;
51         ret = fcntl(priv->primary_socket, F_SETFL, flags | O_NONBLOCK);
52         if (ret < 0)
53                 goto out;
54         snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
55                  MLX5_DRIVER_NAME, priv->primary_socket);
56         ret = stat(sun.sun_path, &file_stat);
57         if (!ret)
58                 claim_zero(remove(sun.sun_path));
59         ret = bind(priv->primary_socket, (const struct sockaddr *)&sun,
60                    sizeof(sun));
61         if (ret < 0) {
62                 WARN("cannot bind socket, secondary process not supported: %s",
63                      strerror(errno));
64                 goto close;
65         }
66         ret = listen(priv->primary_socket, 0);
67         if (ret < 0) {
68                 WARN("Secondary process not supported: %s", strerror(errno));
69                 goto close;
70         }
71         return ret;
72 close:
73         remove(sun.sun_path);
74 out:
75         claim_zero(close(priv->primary_socket));
76         priv->primary_socket = 0;
77         return -(ret);
78 }
79
80 /**
81  * Un-Initialise the socket to communicate with the secondary process
82  *
83  * @param[in] dev
84  *   Pointer to Ethernet device.
85  */
86 void
87 mlx5_socket_uninit(struct rte_eth_dev *dev)
88 {
89         struct priv *priv = dev->data->dev_private;
90
91         MKSTR(path, "/var/tmp/%s_%d", MLX5_DRIVER_NAME, priv->primary_socket);
92         claim_zero(close(priv->primary_socket));
93         priv->primary_socket = 0;
94         claim_zero(remove(path));
95 }
96
97 /**
98  * Handle socket interrupts.
99  *
100  * @param dev
101  *   Pointer to Ethernet device.
102  */
103 void
104 mlx5_socket_handle(struct rte_eth_dev *dev)
105 {
106         struct priv *priv = dev->data->dev_private;
107         int conn_sock;
108         int ret = 0;
109         struct cmsghdr *cmsg = NULL;
110         struct ucred *cred = NULL;
111         char buf[CMSG_SPACE(sizeof(struct ucred))] = { 0 };
112         char vbuf[1024] = { 0 };
113         struct iovec io = {
114                 .iov_base = vbuf,
115                 .iov_len = sizeof(*vbuf),
116         };
117         struct msghdr msg = {
118                 .msg_iov = &io,
119                 .msg_iovlen = 1,
120                 .msg_control = buf,
121                 .msg_controllen = sizeof(buf),
122         };
123         int *fd;
124
125         /* Accept the connection from the client. */
126         conn_sock = accept(priv->primary_socket, NULL, NULL);
127         if (conn_sock < 0) {
128                 WARN("connection failed: %s", strerror(errno));
129                 return;
130         }
131         ret = setsockopt(conn_sock, SOL_SOCKET, SO_PASSCRED, &(int){1},
132                                          sizeof(int));
133         if (ret < 0) {
134                 WARN("cannot change socket options");
135                 goto out;
136         }
137         ret = recvmsg(conn_sock, &msg, MSG_WAITALL);
138         if (ret < 0) {
139                 WARN("received an empty message: %s", strerror(errno));
140                 goto out;
141         }
142         /* Expect to receive credentials only. */
143         cmsg = CMSG_FIRSTHDR(&msg);
144         if (cmsg == NULL) {
145                 WARN("no message");
146                 goto out;
147         }
148         if ((cmsg->cmsg_type == SCM_CREDENTIALS) &&
149                 (cmsg->cmsg_len >= sizeof(*cred))) {
150                 cred = (struct ucred *)CMSG_DATA(cmsg);
151                 assert(cred != NULL);
152         }
153         cmsg = CMSG_NXTHDR(&msg, cmsg);
154         if (cmsg != NULL) {
155                 WARN("Message wrongly formatted");
156                 goto out;
157         }
158         /* Make sure all the ancillary data was received and valid. */
159         if ((cred == NULL) || (cred->uid != getuid()) ||
160             (cred->gid != getgid())) {
161                 WARN("wrong credentials");
162                 goto out;
163         }
164         /* Set-up the ancillary data. */
165         cmsg = CMSG_FIRSTHDR(&msg);
166         assert(cmsg != NULL);
167         cmsg->cmsg_level = SOL_SOCKET;
168         cmsg->cmsg_type = SCM_RIGHTS;
169         cmsg->cmsg_len = CMSG_LEN(sizeof(priv->ctx->cmd_fd));
170         fd = (int *)CMSG_DATA(cmsg);
171         *fd = priv->ctx->cmd_fd;
172         ret = sendmsg(conn_sock, &msg, 0);
173         if (ret < 0)
174                 WARN("cannot send response");
175 out:
176         close(conn_sock);
177 }
178
179 /**
180  * Connect to the primary process.
181  *
182  * @param[in] dev
183  *   Pointer to Ethernet structure.
184  *
185  * @return
186  *   fd on success, negative errno value on failure.
187  */
188 int
189 mlx5_socket_connect(struct rte_eth_dev *dev)
190 {
191         struct priv *priv = dev->data->dev_private;
192         struct sockaddr_un sun = {
193                 .sun_family = AF_UNIX,
194         };
195         int socket_fd;
196         int *fd = NULL;
197         int ret;
198         struct ucred *cred;
199         char buf[CMSG_SPACE(sizeof(*cred))] = { 0 };
200         char vbuf[1024] = { 0 };
201         struct iovec io = {
202                 .iov_base = vbuf,
203                 .iov_len = sizeof(*vbuf),
204         };
205         struct msghdr msg = {
206                 .msg_control = buf,
207                 .msg_controllen = sizeof(buf),
208                 .msg_iov = &io,
209                 .msg_iovlen = 1,
210         };
211         struct cmsghdr *cmsg;
212
213         ret = socket(AF_UNIX, SOCK_STREAM, 0);
214         if (ret < 0) {
215                 WARN("cannot connect to primary");
216                 return ret;
217         }
218         socket_fd = ret;
219         snprintf(sun.sun_path, sizeof(sun.sun_path), "/var/tmp/%s_%d",
220                  MLX5_DRIVER_NAME, priv->primary_socket);
221         ret = connect(socket_fd, (const struct sockaddr *)&sun, sizeof(sun));
222         if (ret < 0) {
223                 WARN("cannot connect to primary");
224                 goto out;
225         }
226         cmsg = CMSG_FIRSTHDR(&msg);
227         if (cmsg == NULL) {
228                 DEBUG("cannot get first message");
229                 goto out;
230         }
231         cmsg->cmsg_level = SOL_SOCKET;
232         cmsg->cmsg_type = SCM_CREDENTIALS;
233         cmsg->cmsg_len = CMSG_LEN(sizeof(*cred));
234         cred = (struct ucred *)CMSG_DATA(cmsg);
235         if (cred == NULL) {
236                 DEBUG("no credentials received");
237                 goto out;
238         }
239         cred->pid = getpid();
240         cred->uid = getuid();
241         cred->gid = getgid();
242         ret = sendmsg(socket_fd, &msg, MSG_DONTWAIT);
243         if (ret < 0) {
244                 WARN("cannot send credentials to primary: %s",
245                      strerror(errno));
246                 goto out;
247         }
248         ret = recvmsg(socket_fd, &msg, MSG_WAITALL);
249         if (ret <= 0) {
250                 WARN("no message from primary: %s", strerror(errno));
251                 goto out;
252         }
253         cmsg = CMSG_FIRSTHDR(&msg);
254         if (cmsg == NULL) {
255                 WARN("No file descriptor received");
256                 goto out;
257         }
258         fd = (int *)CMSG_DATA(cmsg);
259         if (*fd <= 0) {
260                 WARN("no file descriptor received: %s", strerror(errno));
261                 ret = *fd;
262                 goto out;
263         }
264         ret = *fd;
265 out:
266         close(socket_fd);
267         return ret;
268 }