]>
Commit | Line | Data |
---|---|---|
2fb975da TT |
1 | /* NHRP netlink/GRE tunnel configuration code |
2 | * Copyright (c) 2014-2016 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 | ||
836c52da | 10 | #include <sys/socket.h> |
2fb975da TT |
11 | #include <linux/netlink.h> |
12 | #include <linux/rtnetlink.h> | |
836c52da | 13 | #include <linux/in.h> |
2fb975da TT |
14 | #include <linux/if.h> |
15 | #include <linux/ip.h> | |
16 | #include <linux/ipv6.h> | |
17 | #include <linux/if_tunnel.h> | |
18 | ||
19 | #include "debug.h" | |
20 | #include "netlink.h" | |
21 | #include "znl.h" | |
22 | ||
996c9314 LB |
23 | static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, |
24 | int ifindex) | |
2fb975da TT |
25 | { |
26 | struct nlmsghdr *n; | |
27 | struct ifinfomsg *ifi; | |
28 | struct zbuf payload, rtapayload; | |
29 | struct rtattr *rta; | |
30 | ||
31 | debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex); | |
32 | ||
33 | n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST); | |
34 | ifi = znl_push(zb, sizeof(*ifi)); | |
996c9314 | 35 | *ifi = (struct ifinfomsg){ |
2fb975da TT |
36 | .ifi_index = ifindex, |
37 | }; | |
38 | znl_nlmsg_complete(zb, n); | |
39 | ||
996c9314 LB |
40 | if (zbuf_send(zb, netlink_req_fd) < 0 |
41 | || zbuf_recv(zb, netlink_req_fd) < 0) | |
2fb975da TT |
42 | return -1; |
43 | ||
44 | n = znl_nlmsg_pull(zb, &payload); | |
996c9314 LB |
45 | if (!n) |
46 | return -1; | |
2fb975da TT |
47 | |
48 | if (n->nlmsg_type != RTM_NEWLINK) | |
49 | return -1; | |
50 | ||
51 | ifi = znl_pull(&payload, sizeof(struct ifinfomsg)); | |
52 | if (!ifi) | |
53 | return -1; | |
54 | ||
996c9314 LB |
55 | debugf(NHRP_DEBUG_KERNEL, |
56 | "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u", | |
57 | ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags); | |
2fb975da TT |
58 | |
59 | if (ifi->ifi_index != ifindex) | |
60 | return -1; | |
61 | ||
62 | while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) | |
63 | if (rta->rta_type == IFLA_LINKINFO) | |
64 | break; | |
996c9314 LB |
65 | if (!rta) |
66 | return -1; | |
2fb975da TT |
67 | |
68 | payload = rtapayload; | |
69 | while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) | |
70 | if (rta->rta_type == IFLA_INFO_DATA) | |
71 | break; | |
996c9314 LB |
72 | if (!rta) |
73 | return -1; | |
2fb975da TT |
74 | |
75 | *data = rtapayload; | |
76 | return 0; | |
77 | } | |
78 | ||
996c9314 LB |
79 | void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, |
80 | unsigned int *link_index, struct in_addr *saddr) | |
2fb975da TT |
81 | { |
82 | struct zbuf *zb = zbuf_alloc(8192), data, rtapl; | |
83 | struct rtattr *rta; | |
84 | ||
85 | *link_index = 0; | |
86 | *gre_key = 0; | |
87 | saddr->s_addr = 0; | |
88 | ||
89 | if (__netlink_gre_get_data(zb, &data, ifindex) < 0) | |
90 | goto err; | |
91 | ||
92 | while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { | |
93 | switch (rta->rta_type) { | |
94 | case IFLA_GRE_LINK: | |
95 | *link_index = zbuf_get32(&rtapl); | |
96 | break; | |
97 | case IFLA_GRE_IKEY: | |
98 | case IFLA_GRE_OKEY: | |
99 | *gre_key = zbuf_get32(&rtapl); | |
100 | break; | |
101 | case IFLA_GRE_LOCAL: | |
102 | saddr->s_addr = zbuf_get32(&rtapl); | |
103 | break; | |
104 | } | |
105 | } | |
106 | err: | |
107 | zbuf_free(zb); | |
108 | } | |
109 | ||
110 | void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index) | |
111 | { | |
112 | struct nlmsghdr *n; | |
113 | struct ifinfomsg *ifi; | |
114 | struct rtattr *rta_info, *rta_data, *rta; | |
115 | struct zbuf *zr = zbuf_alloc(8192), data, rtapl; | |
116 | struct zbuf *zb = zbuf_alloc(8192); | |
117 | size_t len; | |
118 | ||
119 | if (__netlink_gre_get_data(zr, &data, ifindex) < 0) | |
120 | goto err; | |
121 | ||
122 | n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST); | |
123 | ifi = znl_push(zb, sizeof(*ifi)); | |
996c9314 | 124 | *ifi = (struct ifinfomsg){ |
2fb975da TT |
125 | .ifi_index = ifindex, |
126 | }; | |
127 | rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO); | |
128 | znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3); | |
129 | rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA); | |
130 | ||
131 | znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index); | |
132 | while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { | |
133 | if (rta->rta_type == IFLA_GRE_LINK) | |
134 | continue; | |
135 | len = zbuf_used(&rtapl); | |
136 | znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len); | |
137 | } | |
138 | ||
139 | znl_rta_nested_complete(zb, rta_data); | |
140 | znl_rta_nested_complete(zb, rta_info); | |
141 | ||
142 | znl_nlmsg_complete(zb, n); | |
143 | zbuf_send(zb, netlink_req_fd); | |
144 | zbuf_recv(zb, netlink_req_fd); | |
145 | err: | |
146 | zbuf_free(zb); | |
147 | zbuf_free(zr); | |
148 | } |