]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/znl.c
zebra: Allow ns delete to happen after under/over flow checks
[mirror_frr.git] / nhrpd / znl.c
CommitLineData
2fb975da
TT
1/* Netlink helpers for zbuf
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
b45ac5f5
DL
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
2fb975da
TT
14#include <fcntl.h>
15#include <errno.h>
16#include <string.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <linux/netlink.h>
21#include <linux/rtnetlink.h>
22
23#include "znl.h"
24
25#define ZNL_ALIGN(len) (((len)+3) & ~3)
26
27void *znl_push(struct zbuf *zb, size_t n)
28{
29 return zbuf_pushn(zb, ZNL_ALIGN(n));
30}
31
32void *znl_pull(struct zbuf *zb, size_t n)
33{
34 return zbuf_pulln(zb, ZNL_ALIGN(n));
35}
36
37struct nlmsghdr *znl_nlmsg_push(struct zbuf *zb, uint16_t type, uint16_t flags)
38{
39 struct nlmsghdr *n;
40
41 n = znl_push(zb, sizeof(*n));
996c9314
LB
42 if (!n)
43 return NULL;
2fb975da 44
996c9314
LB
45 *n = (struct nlmsghdr){
46 .nlmsg_type = type, .nlmsg_flags = flags,
2fb975da
TT
47 };
48 return n;
49}
50
51void znl_nlmsg_complete(struct zbuf *zb, struct nlmsghdr *n)
52{
996c9314 53 n->nlmsg_len = zb->tail - (uint8_t *)n;
2fb975da
TT
54}
55
56struct nlmsghdr *znl_nlmsg_pull(struct zbuf *zb, struct zbuf *payload)
57{
58 struct nlmsghdr *n;
59 size_t plen;
60
61 n = znl_pull(zb, sizeof(*n));
996c9314
LB
62 if (!n)
63 return NULL;
2fb975da
TT
64
65 plen = n->nlmsg_len - sizeof(*n);
66 zbuf_init(payload, znl_pull(zb, plen), plen, plen);
67 zbuf_may_pulln(zb, ZNL_ALIGN(plen) - plen);
68
69 return n;
70}
71
996c9314
LB
72struct rtattr *znl_rta_push(struct zbuf *zb, uint16_t type, const void *val,
73 size_t len)
2fb975da
TT
74{
75 struct rtattr *rta;
76 uint8_t *dst;
77
78 rta = znl_push(zb, ZNL_ALIGN(sizeof(*rta)) + ZNL_ALIGN(len));
996c9314
LB
79 if (!rta)
80 return NULL;
2fb975da 81
996c9314
LB
82 *rta = (struct rtattr){
83 .rta_type = type, .rta_len = ZNL_ALIGN(sizeof(*rta)) + len,
2fb975da
TT
84 };
85
996c9314 86 dst = (uint8_t *)(rta + 1);
2fb975da 87 memcpy(dst, val, len);
996c9314 88 memset(dst + len, 0, ZNL_ALIGN(len) - len);
2fb975da
TT
89
90 return rta;
91}
92
93struct rtattr *znl_rta_push_u32(struct zbuf *zb, uint16_t type, uint32_t val)
94{
95 return znl_rta_push(zb, type, &val, sizeof(val));
96}
97
98struct rtattr *znl_rta_nested_push(struct zbuf *zb, uint16_t type)
99{
100 struct rtattr *rta;
101
102 rta = znl_push(zb, sizeof(*rta));
996c9314
LB
103 if (!rta)
104 return NULL;
2fb975da 105
996c9314 106 *rta = (struct rtattr){
2fb975da
TT
107 .rta_type = type,
108 };
109 return rta;
110}
111
112void znl_rta_nested_complete(struct zbuf *zb, struct rtattr *rta)
113{
996c9314 114 size_t len = zb->tail - (uint8_t *)rta;
2fb975da
TT
115 size_t align = ZNL_ALIGN(len) - len;
116
117 if (align) {
118 void *dst = zbuf_pushn(zb, align);
996c9314
LB
119 if (dst)
120 memset(dst, 0, align);
2fb975da
TT
121 }
122 rta->rta_len = len;
123}
124
125struct rtattr *znl_rta_pull(struct zbuf *zb, struct zbuf *payload)
126{
127 struct rtattr *rta;
128 size_t plen;
129
130 rta = znl_pull(zb, sizeof(*rta));
996c9314
LB
131 if (!rta)
132 return NULL;
2fb975da
TT
133
134 if (rta->rta_len > sizeof(*rta)) {
135 plen = rta->rta_len - sizeof(*rta);
136 zbuf_init(payload, znl_pull(zb, plen), plen, plen);
137 } else {
138 zbuf_init(payload, NULL, 0, 0);
139 }
140
141 return rta;
142}
143
144int znl_open(int protocol, int groups)
145{
146 struct sockaddr_nl addr;
147 int fd, buf = 128 * 1024;
148
149 fd = socket(AF_NETLINK, SOCK_RAW, protocol);
150 if (fd < 0)
151 return -1;
152
6c8ca260
JB
153 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0)
154 goto error;
155 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
156 goto error;
2fb975da
TT
157 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0)
158 goto error;
159
160 memset(&addr, 0, sizeof(addr));
161 addr.nl_family = AF_NETLINK;
162 addr.nl_groups = groups;
996c9314 163 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
2fb975da
TT
164 goto error;
165
166 return fd;
167error:
168 close(fd);
169 return -1;
170}