chiark / gitweb /
networkd: introduce gretap
[elogind.git] / src / libsystemd / 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 <stddef.h>
23 #include <stdint.h>
24 #include <sys/socket.h>
25 #include <linux/netlink.h>
26 #include <linux/rtnetlink.h>
27 #include <linux/in6.h>
28 #include <linux/veth.h>
29 #include <linux/if_bridge.h>
30 #include <linux/if_addr.h>
31 #include <linux/if.h>
32
33 #include <linux/ip.h>
34 #include <linux/if_link.h>
35 #include <linux/if_tunnel.h>
36
37 #include "macro.h"
38 #include "util.h"
39
40 #include "rtnl-types.h"
41 #include "missing.h"
42
43 static const NLTypeSystem rtnl_link_type_system;
44
45 static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
46         [VETH_INFO_PEER]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
47 };
48
49 static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
50         [IFLA_IPVLAN_MODE]  = { .type = NLA_U16 },
51 };
52
53 static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
54         [IFLA_MACVLAN_MODE]  = { .type = NLA_U32 },
55         [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
56 };
57
58 static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
59         [IFLA_BRIDGE_FLAGS]     = { .type = NLA_U16 },
60         [IFLA_BRIDGE_MODE]      = { .type = NLA_U16 },
61 /*
62         [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
63                                     .len = sizeof(struct bridge_vlan_info), },
64 */
65 };
66
67 static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
68         [IFLA_VLAN_ID]          = { .type = NLA_U16 },
69 /*
70         [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
71         [IFLA_VLAN_EGRESS_QOS]  = { .type = NLA_NESTED },
72         [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
73 */
74         [IFLA_VLAN_PROTOCOL]    = { .type = NLA_U16 },
75 };
76
77 static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
78         [IFLA_VXLAN_ID] = { .type = NLA_U32 },
79         [IFLA_VXLAN_GROUP] = {.type = NLA_IN_ADDR },
80         [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
81         [IFLA_VXLAN_LOCAL] = { .type = NLA_U32},
82         [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
83         [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
84         [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
85         [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
86         [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
87         [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_U32},
88         [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
89         [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
90         [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
91         [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
92 };
93
94 static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
95         [IFLA_BOND_MODE]                = { .type = NLA_U8 },
96         [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NLA_U32 },
97         [IFLA_BOND_MIIMON]              = { .type = NLA_U32 },
98         [IFLA_BOND_UPDELAY]             = { .type = NLA_U32 },
99         [IFLA_BOND_DOWNDELAY]           = { .type = NLA_U32 },
100         [IFLA_BOND_USE_CARRIER]         = { .type = NLA_U8 },
101         [IFLA_BOND_ARP_INTERVAL]        = { .type = NLA_U32 },
102         [IFLA_BOND_ARP_IP_TARGET]       = { .type = NLA_NESTED },
103         [IFLA_BOND_ARP_VALIDATE]        = { .type = NLA_U32 },
104         [IFLA_BOND_ARP_ALL_TARGETS]     = { .type = NLA_U32 },
105         [IFLA_BOND_PRIMARY]             = { .type = NLA_U32 },
106         [IFLA_BOND_PRIMARY_RESELECT]    = { .type = NLA_U8 },
107         [IFLA_BOND_FAIL_OVER_MAC]       = { .type = NLA_U8 },
108         [IFLA_BOND_XMIT_HASH_POLICY]    = { .type = NLA_U8 },
109         [IFLA_BOND_RESEND_IGMP]         = { .type = NLA_U32 },
110         [IFLA_BOND_NUM_PEER_NOTIF]      = { .type = NLA_U8 },
111         [IFLA_BOND_ALL_SLAVES_ACTIVE]   = { .type = NLA_U8 },
112         [IFLA_BOND_MIN_LINKS]           = { .type = NLA_U32 },
113         [IFLA_BOND_LP_INTERVAL]         = { .type = NLA_U32 },
114         [IFLA_BOND_PACKETS_PER_SLAVE]   = { .type = NLA_U32 },
115         [IFLA_BOND_AD_LACP_RATE]        = { .type = NLA_U8 },
116         [IFLA_BOND_AD_SELECT]           = { .type = NLA_U8 },
117         [IFLA_BOND_AD_INFO]             = { .type = NLA_NESTED },
118 };
119
120 static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
121         [IFLA_IPTUN_LINK]                = { .type = NLA_U32 },
122         [IFLA_IPTUN_LOCAL]               = { .type = NLA_IN_ADDR },
123         [IFLA_IPTUN_REMOTE]              = { .type = NLA_IN_ADDR },
124         [IFLA_IPTUN_TTL]                 = { .type = NLA_U8 },
125         [IFLA_IPTUN_TOS]                 = { .type = NLA_U8 },
126         [IFLA_IPTUN_PMTUDISC]            = { .type = NLA_U8 },
127         [IFLA_IPTUN_FLAGS]               = { .type = NLA_U16 },
128         [IFLA_IPTUN_PROTO]               = { .type = NLA_U8 },
129         [IFLA_IPTUN_6RD_PREFIX]          = { .type = NLA_IN_ADDR },
130         [IFLA_IPTUN_6RD_RELAY_PREFIX]    = { .type = NLA_U32 },
131         [IFLA_IPTUN_6RD_PREFIXLEN]       = { .type = NLA_U16 },
132         [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
133 };
134
135 static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
136         [IFLA_GRE_LINK]     = { .type = NLA_U32 },
137         [IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
138         [IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
139         [IFLA_GRE_IKEY]     = { .type = NLA_U32 },
140         [IFLA_GRE_OKEY]     = { .type = NLA_U32 },
141         [IFLA_GRE_LOCAL]    = { .type = NLA_IN_ADDR },
142         [IFLA_GRE_REMOTE]   = { .type = NLA_IN_ADDR },
143         [IFLA_GRE_TTL]      = { .type = NLA_U8 },
144         [IFLA_GRE_TOS]      = { .type = NLA_U8 },
145         [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
146 };
147
148 static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
149         [IFLA_VTI_LINK]         = { .type = NLA_U32 },
150         [IFLA_VTI_IKEY]         = { .type = NLA_U32 },
151         [IFLA_VTI_OKEY]         = { .type = NLA_U32 },
152         [IFLA_VTI_LOCAL]        = { .type = NLA_IN_ADDR  },
153         [IFLA_VTI_REMOTE]       = { .type = NLA_IN_ADDR  },
154 };
155
156 /* these strings must match the .kind entries in the kernel */
157 static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
158         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
159         [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
160         [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
161         [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
162         [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
163         [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
164         [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
165         [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
166         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
167         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
168         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
169         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
170         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
171 };
172
173 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
174
175 static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
176         [NL_UNION_LINK_INFO_DATA_BOND] =        { .max = ELEMENTSOF(rtnl_link_info_data_bond_types) - 1,
177                                                   .types = rtnl_link_info_data_bond_types },
178         [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .max = ELEMENTSOF(rtnl_link_info_data_bridge_types) - 1,
179                                                   .types = rtnl_link_info_data_bridge_types },
180         [NL_UNION_LINK_INFO_DATA_VLAN] =        { .max = ELEMENTSOF(rtnl_link_info_data_vlan_types) - 1,
181                                                   .types = rtnl_link_info_data_vlan_types },
182         [NL_UNION_LINK_INFO_DATA_VETH] =        { .max = ELEMENTSOF(rtnl_link_info_data_veth_types) - 1,
183                                                   .types = rtnl_link_info_data_veth_types },
184         [NL_UNION_LINK_INFO_DATA_MACVLAN] =     { .max = ELEMENTSOF(rtnl_link_info_data_macvlan_types) - 1,
185                                                   .types = rtnl_link_info_data_macvlan_types },
186         [NL_UNION_LINK_INFO_DATA_IPVLAN] =      { .max = ELEMENTSOF(rtnl_link_info_data_ipvlan_types) - 1,
187                                                   .types = rtnl_link_info_data_ipvlan_types },
188         [NL_UNION_LINK_INFO_DATA_VXLAN] =       { .max = ELEMENTSOF(rtnl_link_info_data_vxlan_types) - 1,
189                                                   .types = rtnl_link_info_data_vxlan_types },
190         [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
191                                                   .types = rtnl_link_info_data_iptun_types },
192         [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
193                                                     .types = rtnl_link_info_data_ipgre_types },
194         [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipgre_types) - 1,
195                                                     .types = rtnl_link_info_data_ipgre_types },
196         [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_iptun_types) - 1,
197                                                   .types = rtnl_link_info_data_iptun_types },
198         [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] =  { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
199                                                   .types = rtnl_link_info_data_ipvti_types },
200 };
201
202 static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
203         .num = _NL_UNION_LINK_INFO_DATA_MAX,
204         .lookup = nl_union_link_info_data_from_string,
205         .type_systems = rtnl_link_info_data_type_systems,
206         .match = IFLA_INFO_KIND,
207 };
208
209 static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
210         [IFLA_INFO_KIND]        = { .type = NLA_STRING },
211         [IFLA_INFO_DATA]        = { .type = NLA_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
212 /*
213         [IFLA_INFO_XSTATS],
214         [IFLA_INFO_SLAVE_KIND]  = { .type = NLA_STRING },
215         [IFLA_INFO_SLAVE_DATA]  = { .type = NLA_NESTED },
216 */
217 };
218
219 static const NLTypeSystem rtnl_link_info_type_system = {
220         .max = ELEMENTSOF(rtnl_link_info_types) - 1,
221         .types = rtnl_link_info_types,
222 };
223
224 static const struct NLType rtnl_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
225         [IFLA_BRPORT_STATE]     = { .type = NLA_U8 },
226         [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
227         [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
228         [IFLA_BRPORT_MODE]      = { .type = NLA_U8 },
229         [IFLA_BRPORT_GUARD]     = { .type = NLA_U8 },
230         [IFLA_BRPORT_PROTECT]   = { .type = NLA_U8 },
231         [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
232         [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
233 };
234
235 static const NLTypeSystem rtnl_bridge_port_type_system = {
236         .max = ELEMENTSOF(rtnl_bridge_port_types) - 1,
237         .types = rtnl_bridge_port_types,
238 };
239
240 static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
241         [IFLA_ADDRESS]          = { .type = NLA_ETHER_ADDR, },
242         [IFLA_BROADCAST]        = { .type = NLA_ETHER_ADDR, },
243         [IFLA_IFNAME]           = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
244         [IFLA_MTU]              = { .type = NLA_U32 },
245         [IFLA_LINK]             = { .type = NLA_U32 },
246 /*
247         [IFLA_QDISC],
248         [IFLA_STATS],
249         [IFLA_COST],
250         [IFLA_PRIORITY],
251 */
252         [IFLA_MASTER]           = { .type = NLA_U32 },
253 /*
254         [IFLA_WIRELESS],
255         [IFLA_PROTINFO],
256 */
257         [IFLA_PROTINFO]         = { .type = NLA_NESTED, .type_system = &rtnl_bridge_port_type_system },
258         [IFLA_TXQLEN]           = { .type = NLA_U32 },
259 /*
260         [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
261 */
262         [IFLA_WEIGHT]           = { .type = NLA_U32 },
263         [IFLA_OPERSTATE]        = { .type = NLA_U8 },
264         [IFLA_LINKMODE]         = { .type = NLA_U8 },
265         [IFLA_LINKINFO]         = { .type = NLA_NESTED, .type_system = &rtnl_link_info_type_system },
266         [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
267         [IFLA_IFALIAS]          = { .type = NLA_STRING, .size = IFALIASZ - 1 },
268 /*
269         [IFLA_NUM_VF],
270         [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED, },
271         [IFLA_STATS64],
272         [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
273         [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
274         [IFLA_AF_SPEC]          = { .type = NLA_NESTED },
275         [IFLA_VF_PORTS],
276         [IFLA_PORT_SELF],
277         [IFLA_AF_SPEC],
278 */
279         [IFLA_GROUP]            = { .type = NLA_U32 },
280         [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
281         [IFLA_EXT_MASK]         = { .type = NLA_U32 },
282         [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
283         [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
284         [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
285         [IFLA_CARRIER]          = { .type = NLA_U8 },
286 /*
287         [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
288 */
289 };
290
291 static const NLTypeSystem rtnl_link_type_system = {
292         .max = ELEMENTSOF(rtnl_link_types) - 1,
293         .types = rtnl_link_types,
294 };
295
296 static const NLType rtnl_address_types[IFA_MAX + 1] = {
297         [IFA_ADDRESS]           = { .type = NLA_IN_ADDR },
298         [IFA_LOCAL]             = { .type = NLA_IN_ADDR },
299         [IFA_LABEL]             = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
300         [IFA_BROADCAST]         = { .type = NLA_IN_ADDR }, /* 6? */
301         [IFA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
302 /*
303         [IFA_ANYCAST],
304         [IFA_MULTICAST],
305 */
306 #ifdef IFA_FLAGS
307         [IFA_FLAGS]             = { .type = NLA_U32 },
308 #endif
309 };
310
311 static const NLTypeSystem rtnl_address_type_system = {
312         .max = ELEMENTSOF(rtnl_address_types) - 1,
313         .types = rtnl_address_types,
314 };
315
316 static const NLType rtnl_route_types[RTA_MAX + 1] = {
317         [RTA_DST]               = { .type = NLA_IN_ADDR }, /* 6? */
318         [RTA_SRC]               = { .type = NLA_IN_ADDR }, /* 6? */
319         [RTA_IIF]               = { .type = NLA_U32 },
320         [RTA_OIF]               = { .type = NLA_U32 },
321         [RTA_GATEWAY]           = { .type = NLA_IN_ADDR },
322         [RTA_PRIORITY]          = { .type = NLA_U32 },
323         [RTA_PREFSRC]           = { .type = NLA_IN_ADDR }, /* 6? */
324 /*
325         [RTA_METRICS]           = { .type = NLA_NESTED },
326         [RTA_MULTIPATH]         = { .len = sizeof(struct rtnexthop) },
327 */
328         [RTA_FLOW]              = { .type = NLA_U32 }, /* 6? */
329 /*
330         RTA_CACHEINFO,
331         RTA_TABLE,
332         RTA_MARK,
333         RTA_MFC_STATS,
334 */
335 };
336
337 static const NLTypeSystem rtnl_route_type_system = {
338         .max = ELEMENTSOF(rtnl_route_types) - 1,
339         .types = rtnl_route_types,
340 };
341
342 static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
343         [NDA_DST]               = { .type = NLA_IN_ADDR },
344         [NDA_LLADDR]            = { .type = NLA_ETHER_ADDR },
345         [NDA_CACHEINFO]         = { .type = NLA_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
346         [NDA_PROBES]            = { .type = NLA_U32 },
347         [NDA_VLAN]              = { .type = NLA_U16 },
348         [NDA_PORT]              = { .type = NLA_U16 },
349         [NDA_VNI]               = { .type = NLA_U32 },
350         [NDA_IFINDEX]           = { .type = NLA_U32 },
351 };
352
353 static const NLTypeSystem rtnl_neigh_type_system = {
354         .max = ELEMENTSOF(rtnl_neigh_types) - 1,
355         .types = rtnl_neigh_types,
356 };
357
358 static const NLType rtnl_types[RTM_MAX + 1] = {
359         [NLMSG_ERROR]  = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
360         [RTM_NEWLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
361         [RTM_DELLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
362         [RTM_GETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
363         [RTM_SETLINK]  = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
364         [RTM_NEWADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
365         [RTM_DELADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
366         [RTM_GETADDR]  = { .type = NLA_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
367         [RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
368         [RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
369         [RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
370         [RTM_NEWNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
371         [RTM_DELNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
372         [RTM_GETNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
373 };
374
375 const NLTypeSystem rtnl_type_system = {
376         .max = ELEMENTSOF(rtnl_types) - 1,
377         .types = rtnl_types,
378 };
379
380 int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
381         const NLType *nl_type;
382
383         assert(ret);
384
385         if (!type_system)
386                 type_system = &rtnl_type_system;
387
388         assert(type_system->types);
389
390         if (type > type_system->max)
391                 return -ENOTSUP;
392
393         nl_type = &type_system->types[type];
394
395         if (nl_type->type == NLA_UNSPEC)
396                 return -ENOTSUP;
397
398         *ret = nl_type;
399
400         return 0;
401 }
402
403 int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
404         const NLType *nl_type;
405         int r;
406
407         assert(ret);
408
409         r = type_system_get_type(type_system, &nl_type, type);
410         if (r < 0)
411                 return r;
412
413         assert_return(nl_type->type == NLA_NESTED, -EINVAL);
414
415         assert(nl_type->type_system);
416
417         *ret = nl_type->type_system;
418
419         return 0;
420 }
421
422 int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
423         const NLType *nl_type;
424         int r;
425
426         assert(ret);
427
428         r = type_system_get_type(type_system, &nl_type, type);
429         if (r < 0)
430                 return r;
431
432         assert_return(nl_type->type == NLA_UNION, -EINVAL);
433
434         assert(nl_type->type_system_union);
435
436         *ret = nl_type->type_system_union;
437
438         return 0;
439 }
440
441 int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
442         int type;
443
444         assert(type_system_union);
445         assert(type_system_union->lookup);
446         assert(type_system_union->type_systems);
447         assert(ret);
448         assert(key);
449
450         type = type_system_union->lookup(key);
451         if (type < 0)
452                 return -ENOTSUP;
453
454         assert(type < type_system_union->num);
455
456         *ret = &type_system_union->type_systems[type];
457
458         return 0;
459 }