chiark / gitweb /
7715ff8a444982198c847c1d46446843d5402881
[elogind.git] / src / libsystemd / sd-netlink / netlink-types.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdint.h>
23 #include <sys/socket.h>
24 #include <linux/netlink.h>
25 #include <linux/rtnetlink.h>
26 #include <linux/in6.h>
27 #include <linux/veth.h>
28 #include <linux/if_bridge.h>
29 #include <linux/if_addr.h>
30 #include <linux/if.h>
31
32 #include <linux/ip.h>
33 #include <linux/if_link.h>
34 #include <linux/if_tunnel.h>
35
36 #include "macro.h"
37 #include "util.h"
38
39 #include "netlink-types.h"
40 #include "missing.h"
41
42 struct NLType {
43         uint16_t type;
44         size_t size;
45         const NLTypeSystem *type_system;
46         const NLTypeSystemUnion *type_system_union;
47 };
48
49 static const NLTypeSystem rtnl_link_type_system;
50
51 static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
52         [VETH_INFO_PEER]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
53 };
54
55 static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
56         [IFLA_IPVLAN_MODE]  = { .type = NETLINK_TYPE_U16 },
57 };
58
59 static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
60         [IFLA_MACVLAN_MODE]  = { .type = NETLINK_TYPE_U32 },
61         [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
62 };
63
64 static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
65         [IFLA_BRIDGE_FLAGS]     = { .type = NETLINK_TYPE_U16 },
66         [IFLA_BRIDGE_MODE]      = { .type = NETLINK_TYPE_U16 },
67 /*
68         [IFLA_BRIDGE_VLAN_INFO] = { .type = NETLINK_TYPE_BINARY,
69                                     .len = sizeof(struct bridge_vlan_info), },
70 */
71 };
72
73 static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
74         [IFLA_VLAN_ID]          = { .type = NETLINK_TYPE_U16 },
75 /*
76         [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
77         [IFLA_VLAN_EGRESS_QOS]  = { .type = NETLINK_TYPE_NESTED },
78         [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
79 */
80         [IFLA_VLAN_PROTOCOL]    = { .type = NETLINK_TYPE_U16 },
81 };
82
83 static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
84         [IFLA_VXLAN_ID]         = { .type = NETLINK_TYPE_U32 },
85         [IFLA_VXLAN_GROUP]      = { .type = NETLINK_TYPE_IN_ADDR },
86         [IFLA_VXLAN_LINK]       = { .type = NETLINK_TYPE_U32 },
87         [IFLA_VXLAN_LOCAL]      = { .type = NETLINK_TYPE_U32},
88         [IFLA_VXLAN_TTL]        = { .type = NETLINK_TYPE_U8 },
89         [IFLA_VXLAN_TOS]        = { .type = NETLINK_TYPE_U8 },
90         [IFLA_VXLAN_LEARNING]   = { .type = NETLINK_TYPE_U8 },
91         [IFLA_VXLAN_AGEING]     = { .type = NETLINK_TYPE_U32 },
92         [IFLA_VXLAN_LIMIT]      = { .type = NETLINK_TYPE_U32 },
93         [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
94         [IFLA_VXLAN_PROXY]      = { .type = NETLINK_TYPE_U8 },
95         [IFLA_VXLAN_RSC]        = { .type = NETLINK_TYPE_U8 },
96         [IFLA_VXLAN_L2MISS]     = { .type = NETLINK_TYPE_U8 },
97         [IFLA_VXLAN_L3MISS]     = { .type = NETLINK_TYPE_U8 },
98 };
99
100 static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
101         [BOND_ARP_TARGETS_0]        = { .type = NETLINK_TYPE_U32 },
102         [BOND_ARP_TARGETS_1]        = { .type = NETLINK_TYPE_U32 },
103         [BOND_ARP_TARGETS_2]        = { .type = NETLINK_TYPE_U32 },
104         [BOND_ARP_TARGETS_3]        = { .type = NETLINK_TYPE_U32 },
105         [BOND_ARP_TARGETS_4]        = { .type = NETLINK_TYPE_U32 },
106         [BOND_ARP_TARGETS_5]        = { .type = NETLINK_TYPE_U32 },
107         [BOND_ARP_TARGETS_6]        = { .type = NETLINK_TYPE_U32 },
108         [BOND_ARP_TARGETS_7]        = { .type = NETLINK_TYPE_U32 },
109         [BOND_ARP_TARGETS_8]        = { .type = NETLINK_TYPE_U32 },
110         [BOND_ARP_TARGETS_9]        = { .type = NETLINK_TYPE_U32 },
111         [BOND_ARP_TARGETS_10]       = { .type = NETLINK_TYPE_U32 },
112         [BOND_ARP_TARGETS_11]       = { .type = NETLINK_TYPE_U32 },
113         [BOND_ARP_TARGETS_12]       = { .type = NETLINK_TYPE_U32 },
114         [BOND_ARP_TARGETS_13]       = { .type = NETLINK_TYPE_U32 },
115         [BOND_ARP_TARGETS_14]       = { .type = NETLINK_TYPE_U32 },
116         [BOND_ARP_TARGETS_MAX]      = { .type = NETLINK_TYPE_U32 },
117 };
118
119 static const NLTypeSystem rtnl_bond_arp_type_system = {
120         .max = ELEMENTSOF(rtnl_bond_arp_target_types) - 1,
121         .types = rtnl_bond_arp_target_types,
122 };
123
124 static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
125         [IFLA_BOND_MODE]                = { .type = NETLINK_TYPE_U8 },
126         [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NETLINK_TYPE_U32 },
127         [IFLA_BOND_MIIMON]              = { .type = NETLINK_TYPE_U32 },
128         [IFLA_BOND_UPDELAY]             = { .type = NETLINK_TYPE_U32 },
129         [IFLA_BOND_DOWNDELAY]           = { .type = NETLINK_TYPE_U32 },
130         [IFLA_BOND_USE_CARRIER]         = { .type = NETLINK_TYPE_U8 },
131         [IFLA_BOND_ARP_INTERVAL]        = { .type = NETLINK_TYPE_U32 },
132         [IFLA_BOND_ARP_IP_TARGET]       = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_type_system },
133         [IFLA_BOND_ARP_VALIDATE]        = { .type = NETLINK_TYPE_U32 },
134         [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NETLINK_TYPE_U32 },
135         [IFLA_BOND_PRIMARY]             = { .type = NETLINK_TYPE_U32 },
136         [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NETLINK_TYPE_U8 },
137         [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NETLINK_TYPE_U8 },
138         [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NETLINK_TYPE_U8 },
139         [IFLA_BOND_RESEND_IGMP]         = { .type = NETLINK_TYPE_U32 },
140         [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NETLINK_TYPE_U8 },
141         [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NETLINK_TYPE_U8 },
142         [IFLA_BOND_MIN_LINKS]           = { .type = NETLINK_TYPE_U32 },
143         [IFLA_BOND_LP_INTERVAL]         = { .type = NETLINK_TYPE_U32 },
144         [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NETLINK_TYPE_U32 },
145         [IFLA_BOND_AD_LACP_RATE]        = { .type = NETLINK_TYPE_U8 },
146         [IFLA_BOND_AD_SELECT]           = { .type = NETLINK_TYPE_U8 },
147         [IFLA_BOND_AD_INFO]             = { .type = NETLINK_TYPE_NESTED },
148 };
149
150 static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
151         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
152         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
153         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
154         [IFLA_IPTUN_TTL]                 = { .type = NETLINK_TYPE_U8 },
155         [IFLA_IPTUN_TOS]                 = { .type = NETLINK_TYPE_U8 },
156         [IFLA_IPTUN_PMTUDISC]            = { .type = NETLINK_TYPE_U8 },
157         [IFLA_IPTUN_FLAGS]               = { .type = NETLINK_TYPE_U16 },
158         [IFLA_IPTUN_PROTO]               = { .type = NETLINK_TYPE_U8 },
159         [IFLA_IPTUN_6RD_PREFIX]          = { .type = NETLINK_TYPE_IN_ADDR },
160         [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NETLINK_TYPE_U32 },
161         [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NETLINK_TYPE_U16 },
162         [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
163 };
164
165 static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
166         [IFLA_GRE_LINK]     = { .type = NETLINK_TYPE_U32 },
167         [IFLA_GRE_IFLAGS]   = { .type = NETLINK_TYPE_U16 },
168         [IFLA_GRE_OFLAGS]   = { .type = NETLINK_TYPE_U16 },
169         [IFLA_GRE_IKEY]     = { .type = NETLINK_TYPE_U32 },
170         [IFLA_GRE_OKEY]     = { .type = NETLINK_TYPE_U32 },
171         [IFLA_GRE_LOCAL]    = { .type = NETLINK_TYPE_IN_ADDR },
172         [IFLA_GRE_REMOTE]   = { .type = NETLINK_TYPE_IN_ADDR },
173         [IFLA_GRE_TTL]      = { .type = NETLINK_TYPE_U8 },
174         [IFLA_GRE_TOS]      = { .type = NETLINK_TYPE_U8 },
175         [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
176 };
177
178 static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
179         [IFLA_VTI_LINK]         = { .type = NETLINK_TYPE_U32 },
180         [IFLA_VTI_IKEY]         = { .type = NETLINK_TYPE_U32 },
181         [IFLA_VTI_OKEY]         = { .type = NETLINK_TYPE_U32 },
182         [IFLA_VTI_LOCAL]        = { .type = NETLINK_TYPE_IN_ADDR  },
183         [IFLA_VTI_REMOTE]       = { .type = NETLINK_TYPE_IN_ADDR  },
184 };
185
186 static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
187         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
188         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
189         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
190         [IFLA_IPTUN_TTL]                 = { .type = NETLINK_TYPE_U8 },
191         [IFLA_IPTUN_FLAGS]               = { .type = NETLINK_TYPE_U32 },
192         [IFLA_IPTUN_PROTO]               = { .type = NETLINK_TYPE_U8 },
193         [IFLA_IPTUN_ENCAP_LIMIT]         = { .type = NETLINK_TYPE_U8 },
194         [IFLA_IPTUN_FLOWINFO]            = { .type = NETLINK_TYPE_U32},
195 };
196
197 /* these strings must match the .kind entries in the kernel */
198 static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
199         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
200         [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
201         [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
202         [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
203         [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
204         [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
205         [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
206         [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
207         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
208         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
209         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
210         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre",
211         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
212         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
213         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
214         [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
215         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
216 };
217
218 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
219
220 static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
221         [NL_UNION_LINK_INFO_DATA_BOND] =        { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
222                                                   .types = rtnl_link_info_data_bond_types },
223         [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
224                                                   .types = rtnl_link_info_data_bridge_types },
225         [NL_UNION_LINK_INFO_DATA_VLAN] =        { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
226                                                   .types = rtnl_link_info_data_vlan_types },
227         [NL_UNION_LINK_INFO_DATA_VETH] =        { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
228                                                   .types = rtnl_link_info_data_veth_types },
229         [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
230                                                   .types = rtnl_link_info_data_macvlan_types },
231         [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .max = ELEMENTSOF(rtnl_link_info_data_ipvlan_types) - 1,
232                                                   .types = rtnl_link_info_data_ipvlan_types },
233         [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .max = ELEMENTSOF(rtnl_link_info_data_vxlan_types) - 1,
234                                                   .types = rtnl_link_info_data_vxlan_types },
235         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
236                                                   .types = rtnl_link_info_data_iptun_types },
237         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
238                                                     .types = rtnl_link_info_data_ipgre_types },
239         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
240                                                     .types = rtnl_link_info_data_ipgre_types },
241         [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
242                                                     .types = rtnl_link_info_data_ipgre_types },
243         [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
244                                                     .types = rtnl_link_info_data_ipgre_types },
245         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
246                                                   .types = rtnl_link_info_data_iptun_types },
247         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
248                                                   .types = rtnl_link_info_data_ipvti_types },
249         [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
250                                                   .types = rtnl_link_info_data_ipvti_types },
251         [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
252                                                      .types = rtnl_link_info_data_ip6tnl_types },
253
254 };
255
256 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
257         .num = _NL_UNION_LINK_INFO_DATA_MAX,
258         .lookup = nl_union_link_info_data_from_string,
259         .type_systems = rtnl_link_info_data_type_systems,
260         .match_type = NL_MATCH_SIBLING,
261         .match = IFLA_INFO_KIND,
262 };
263
264 static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
265         [IFLA_INFO_KIND]        = { .type = NETLINK_TYPE_STRING },
266         [IFLA_INFO_DATA]        = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
267 /*
268         [IFLA_INFO_XSTATS],
269         [IFLA_INFO_SLAVE_KIND]  = { .type = NETLINK_TYPE_STRING },
270         [IFLA_INFO_SLAVE_DATA]  = { .type = NETLINK_TYPE_NESTED },
271 */
272 };
273
274 static const NLTypeSystem rtnl_link_info_type_system = {
275         .max = ELEMENTSOF(rtnl_link_info_types) - 1,
276         .types = rtnl_link_info_types,
277 };
278
279 static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
280         [IFLA_BRPORT_STATE]             = { .type = NETLINK_TYPE_U8 },
281         [IFLA_BRPORT_COST]              = { .type = NETLINK_TYPE_U32 },
282         [IFLA_BRPORT_PRIORITY]          = { .type = NETLINK_TYPE_U16 },
283         [IFLA_BRPORT_MODE]              = { .type = NETLINK_TYPE_U8 },
284         [IFLA_BRPORT_GUARD]             = { .type = NETLINK_TYPE_U8 },
285         [IFLA_BRPORT_PROTECT]           = { .type = NETLINK_TYPE_U8 },
286         [IFLA_BRPORT_LEARNING]          = { .type = NETLINK_TYPE_U8 },
287         [IFLA_BRPORT_UNICAST_FLOOD]     = { .type = NETLINK_TYPE_U8 },
288 };
289
290 static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
291         [AF_BRIDGE] =   { .max = ELEMENTSOF(rtnl_prot_info_bridge_port_types) - 1,
292                           .types = rtnl_prot_info_bridge_port_types },
293 };
294
295 static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
296         .num = AF_MAX,
297         .type_systems = rtnl_prot_info_type_systems,
298         .match_type = NL_MATCH_PROTOCOL,
299 };
300
301 static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
302         [IFLA_INET6_FLAGS]              = { .type = NETLINK_TYPE_U32 },
303 /*
304         IFLA_INET6_CONF,
305         IFLA_INET6_STATS,
306         IFLA_INET6_MCAST,
307         IFLA_INET6_CACHEINFO,
308         IFLA_INET6_ICMP6STATS,
309 */
310         [IFLA_INET6_TOKEN]              = { .type = NETLINK_TYPE_IN_ADDR },
311         [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NETLINK_TYPE_U8 },
312 };
313
314 static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
315         .max = ELEMENTSOF(rtnl_af_spec_inet6_types) - 1,
316         .types = rtnl_af_spec_inet6_types,
317 };
318
319 static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
320         [AF_INET6] =    { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
321 };
322
323 static const NLTypeSystem rtnl_af_spec_type_system = {
324         .max = ELEMENTSOF(rtnl_af_spec_types) - 1,
325         .types = rtnl_af_spec_types,
326 };
327
328 static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
329         [IFLA_ADDRESS]          = { .type = NETLINK_TYPE_ETHER_ADDR, },
330         [IFLA_BROADCAST]        = { .type = NETLINK_TYPE_ETHER_ADDR, },
331         [IFLA_IFNAME]           = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1, },
332         [IFLA_MTU]              = { .type = NETLINK_TYPE_U32 },
333         [IFLA_LINK]             = { .type = NETLINK_TYPE_U32 },
334 /*
335         [IFLA_QDISC],
336         [IFLA_STATS],
337         [IFLA_COST],
338         [IFLA_PRIORITY],
339 */
340         [IFLA_MASTER]           = { .type = NETLINK_TYPE_U32 },
341 /*
342         [IFLA_WIRELESS],
343 */
344         [IFLA_PROTINFO]         = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
345         [IFLA_TXQLEN]           = { .type = NETLINK_TYPE_U32 },
346 /*
347         [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
348 */
349         [IFLA_WEIGHT]           = { .type = NETLINK_TYPE_U32 },
350         [IFLA_OPERSTATE]        = { .type = NETLINK_TYPE_U8 },
351         [IFLA_LINKMODE]         = { .type = NETLINK_TYPE_U8 },
352         [IFLA_LINKINFO]         = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system },
353         [IFLA_NET_NS_PID]       = { .type = NETLINK_TYPE_U32 },
354         [IFLA_IFALIAS]          = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 },
355 /*
356         [IFLA_NUM_VF],
357         [IFLA_VFINFO_LIST]      = {. type = NETLINK_TYPE_NESTED, },
358         [IFLA_STATS64],
359         [IFLA_VF_PORTS]         = { .type = NETLINK_TYPE_NESTED },
360         [IFLA_PORT_SELF]        = { .type = NETLINK_TYPE_NESTED },
361 */
362         [IFLA_AF_SPEC]          = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_type_system },
363 /*
364         [IFLA_VF_PORTS],
365         [IFLA_PORT_SELF],
366         [IFLA_AF_SPEC],
367 */
368         [IFLA_GROUP]            = { .type = NETLINK_TYPE_U32 },
369         [IFLA_NET_NS_FD]        = { .type = NETLINK_TYPE_U32 },
370         [IFLA_EXT_MASK]         = { .type = NETLINK_TYPE_U32 },
371         [IFLA_PROMISCUITY]      = { .type = NETLINK_TYPE_U32 },
372         [IFLA_NUM_TX_QUEUES]    = { .type = NETLINK_TYPE_U32 },
373         [IFLA_NUM_RX_QUEUES]    = { .type = NETLINK_TYPE_U32 },
374         [IFLA_CARRIER]          = { .type = NETLINK_TYPE_U8 },
375 /*
376         [IFLA_PHYS_PORT_ID]     = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
377 */
378 };
379
380 static const NLTypeSystem rtnl_link_type_system = {
381         .max = ELEMENTSOF(rtnl_link_types) - 1,
382         .types = rtnl_link_types,
383 };
384
385 /* IFA_FLAGS was defined in kernel 3.14, but we still support older
386  * kernels where IFA_MAX is lower. */
387 static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
388         [IFA_ADDRESS]           = { .type = NETLINK_TYPE_IN_ADDR },
389         [IFA_LOCAL]             = { .type = NETLINK_TYPE_IN_ADDR },
390         [IFA_LABEL]             = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
391         [IFA_BROADCAST]         = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
392         [IFA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
393 /*
394         [IFA_ANYCAST],
395         [IFA_MULTICAST],
396 */
397         [IFA_FLAGS]             = { .type = NETLINK_TYPE_U32 },
398 };
399
400 static const NLTypeSystem rtnl_address_type_system = {
401         .max = ELEMENTSOF(rtnl_address_types) - 1,
402         .types = rtnl_address_types,
403 };
404
405 static const NLType rtnl_route_types[RTA_MAX + 1] = {
406         [RTA_DST]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
407         [RTA_SRC]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
408         [RTA_IIF]               = { .type = NETLINK_TYPE_U32 },
409         [RTA_OIF]               = { .type = NETLINK_TYPE_U32 },
410         [RTA_GATEWAY]           = { .type = NETLINK_TYPE_IN_ADDR },
411         [RTA_PRIORITY]          = { .type = NETLINK_TYPE_U32 },
412         [RTA_PREFSRC]           = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
413 /*
414         [RTA_METRICS]           = { .type = NETLINK_TYPE_NESTED },
415         [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
416 */
417         [RTA_FLOW]              = { .type = NETLINK_TYPE_U32 }, /* 6? */
418 /*
419         RTA_CACHEINFO,
420         RTA_TABLE,
421         RTA_MARK,
422         RTA_MFC_STATS,
423 */
424 };
425
426 static const NLTypeSystem rtnl_route_type_system = {
427         .max = ELEMENTSOF(rtnl_route_types) - 1,
428         .types = rtnl_route_types,
429 };
430
431 static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
432         [NDA_DST]               = { .type = NETLINK_TYPE_IN_ADDR },
433         [NDA_LLADDR]            = { .type = NETLINK_TYPE_ETHER_ADDR },
434         [NDA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
435         [NDA_PROBES]            = { .type = NETLINK_TYPE_U32 },
436         [NDA_VLAN]              = { .type = NETLINK_TYPE_U16 },
437         [NDA_PORT]              = { .type = NETLINK_TYPE_U16 },
438         [NDA_VNI]               = { .type = NETLINK_TYPE_U32 },
439         [NDA_IFINDEX]           = { .type = NETLINK_TYPE_U32 },
440 };
441
442 static const NLTypeSystem rtnl_neigh_type_system = {
443         .max = ELEMENTSOF(rtnl_neigh_types) - 1,
444         .types = rtnl_neigh_types,
445 };
446
447 static const NLType rtnl_types[RTM_MAX + 1] = {
448         [NLMSG_DONE]   = { .type = NETLINK_TYPE_META, .size = 0 },
449         [NLMSG_ERROR]  = { .type = NETLINK_TYPE_META, .size = sizeof(struct nlmsgerr) },
450         [RTM_NEWLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
451         [RTM_DELLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
452         [RTM_GETLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
453         [RTM_SETLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
454         [RTM_NEWADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
455         [RTM_DELADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
456         [RTM_GETADDR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
457         [RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
458         [RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
459         [RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
460         [RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
461         [RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
462         [RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
463 };
464
465 const NLTypeSystem rtnl_type_system = {
466         .max = ELEMENTSOF(rtnl_types) - 1,
467         .types = rtnl_types,
468 };
469
470 uint16_t type_get_type(const NLType *type) {
471         assert(type);
472         return type->type;
473 }
474
475 size_t type_get_size(const NLType *type) {
476         assert(type);
477         return type->size;
478 }
479
480 void type_get_type_system(const NLType *nl_type, const NLTypeSystem **ret) {
481         assert(nl_type);
482         assert(ret);
483         assert(nl_type->type == NETLINK_TYPE_NESTED);
484         assert(nl_type->type_system);
485
486         *ret = nl_type->type_system;
487 }
488
489 void type_get_type_system_union(const NLType *nl_type, const NLTypeSystemUnion **ret) {
490         assert(nl_type);
491         assert(ret);
492         assert(nl_type->type == NETLINK_TYPE_UNION);
493         assert(nl_type->type_system_union);
494
495         *ret = nl_type->type_system_union;
496 }
497
498 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
499         const NLType *nl_type;
500
501         assert(ret);
502
503         if (!type_system)
504                 type_system = &rtnl_type_system;
505
506         assert(type_system->types);
507
508         if (type > type_system->max)
509                 return -EOPNOTSUPP;
510
511         nl_type = &type_system->types[type];
512
513         if (nl_type->type == NETLINK_TYPE_UNSPEC)
514                 return -EOPNOTSUPP;
515
516         *ret = nl_type;
517
518         return 0;
519 }
520
521 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
522         const NLType *nl_type;
523         int r;
524
525         assert(ret);
526
527         r = type_system_get_type(type_system, &nl_type, type);
528         if (r < 0)
529                 return r;
530
531         type_get_type_system(nl_type, ret);
532         return 0;
533 }
534
535 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
536         const NLType *nl_type;
537         int r;
538
539         assert(ret);
540
541         r = type_system_get_type(type_system, &nl_type, type);
542         if (r < 0)
543                 return r;
544
545         type_get_type_system_union(nl_type, ret);
546         return 0;
547 }
548
549 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
550         int type;
551
552         assert(type_system_union);
553         assert(type_system_union->match_type == NL_MATCH_SIBLING);
554         assert(type_system_union->lookup);
555         assert(type_system_union->type_systems);
556         assert(ret);
557         assert(key);
558
559         type = type_system_union->lookup(key);
560         if (type < 0)
561                 return -EOPNOTSUPP;
562
563         assert(type < type_system_union->num);
564
565         *ret = &type_system_union->type_systems[type];
566
567         return 0;
568 }
569
570 int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
571         const NLTypeSystem *type_system;
572
573         assert(type_system_union);
574         assert(type_system_union->type_systems);
575         assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
576         assert(ret);
577
578         if (protocol >= type_system_union->num)
579                 return -EOPNOTSUPP;
580
581         type_system = &type_system_union->type_systems[protocol];
582         if (type_system->max == 0)
583                 return -EOPNOTSUPP;
584
585         *ret = type_system;
586
587         return 0;
588 }