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