* Receive a message from the kernel on the netlink socket, following an * tap_nl_send(). * * @param[in] nlsk_fd * The netlink socket file descriptor used for communication. * @param[in] cb * The callback function to call for each netlink message received. * @param[in, out] arg * Custom arguments for the callback. * * @return * 0 on success, -1 otherwise with errno set. */
| 234 | * 0 on success, -1 otherwise with errno set. |
| 235 | */ |
| 236 | int |
| 237 | tap_nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg) |
| 238 | { |
| 239 | char buf[BUF_SIZE]; |
| 240 | int multipart = 0; |
| 241 | int ret = 0; |
| 242 | |
| 243 | do { |
| 244 | struct nlmsghdr *nh; |
| 245 | int recv_bytes; |
| 246 | |
| 247 | retry: |
| 248 | recv_bytes = recv(nlsk_fd, buf, sizeof(buf), 0); |
| 249 | if (recv_bytes < 0) { |
| 250 | if (errno == EINTR) |
| 251 | goto retry; |
| 252 | return -1; |
| 253 | } |
| 254 | |
| 255 | for (nh = (struct nlmsghdr *)buf; |
| 256 | NLMSG_OK(nh, (unsigned int)recv_bytes); |
| 257 | nh = NLMSG_NEXT(nh, recv_bytes)) { |
| 258 | if (nh->nlmsg_type == NLMSG_ERROR) { |
| 259 | struct nlmsgerr *err_data = NLMSG_DATA(nh); |
| 260 | |
| 261 | tap_nl_dump_ext_ack(nh, err_data); |
| 262 | if (err_data->error < 0) { |
| 263 | errno = -err_data->error; |
| 264 | return -1; |
| 265 | } |
| 266 | /* Ack message. */ |
| 267 | return 0; |
| 268 | } |
| 269 | /* Multi-part msgs and their trailing DONE message. */ |
| 270 | if (nh->nlmsg_flags & NLM_F_MULTI) { |
| 271 | if (nh->nlmsg_type == NLMSG_DONE) |
| 272 | return 0; |
| 273 | multipart = 1; |
| 274 | } |
| 275 | if (cb) |
| 276 | ret = cb(nh, arg); |
| 277 | } |
| 278 | } while (multipart); |
| 279 | return ret; |
| 280 | } |
| 281 | |
| 282 | /** |
| 283 | * Append a netlink attribute to a message. |
no test coverage detected