aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/udp_media.c112
1 files changed, 55 insertions, 57 deletions
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 33bdf5449a5e..adb3c2117a1c 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -258,68 +258,47 @@ static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
258} 258}
259 259
260/** 260/**
261 * parse_options - build local/remote addresses from configuration 261 * tipc_parse_udp_addr - build udp media address from netlink data
262 * @attrs: netlink config data 262 * @nlattr: netlink attribute containing sockaddr storage aligned address
263 * @ub: UDP bearer instance 263 * @addr: tipc media address to fill with address, port and protocol type
264 * @local: local bearer IP address/port 264 * @scope_id: IPv6 scope id pointer, not NULL indicates it's required
265 * @remote: peer or multicast IP/port
266 */ 265 */
267static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub, 266
268 struct udp_media_addr *local, 267static int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr,
269 struct udp_media_addr *remote) 268 u32 *scope_id)
270{ 269{
271 struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; 270 struct sockaddr_storage sa;
272 struct sockaddr_storage sa_local, sa_remote;
273 271
274 if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) 272 nla_memcpy(&sa, nla, sizeof(sa));
275 goto err; 273 if (sa.ss_family == AF_INET) {
276 if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX, 274 struct sockaddr_in *ip4 = (struct sockaddr_in *)&sa;
277 attrs[TIPC_NLA_BEARER_UDP_OPTS], 275
278 tipc_nl_udp_policy)) 276 addr->proto = htons(ETH_P_IP);
279 goto err; 277 addr->port = ip4->sin_port;
280 if (opts[TIPC_NLA_UDP_LOCAL] && opts[TIPC_NLA_UDP_REMOTE]) { 278 addr->ipv4.s_addr = ip4->sin_addr.s_addr;
281 nla_memcpy(&sa_local, opts[TIPC_NLA_UDP_LOCAL],
282 sizeof(sa_local));
283 nla_memcpy(&sa_remote, opts[TIPC_NLA_UDP_REMOTE],
284 sizeof(sa_remote));
285 } else {
286err:
287 pr_err("Invalid UDP bearer configuration");
288 return -EINVAL;
289 }
290 if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET) {
291 struct sockaddr_in *ip4;
292
293 ip4 = (struct sockaddr_in *)&sa_local;
294 local->proto = htons(ETH_P_IP);
295 local->port = ip4->sin_port;
296 local->ipv4.s_addr = ip4->sin_addr.s_addr;
297
298 ip4 = (struct sockaddr_in *)&sa_remote;
299 remote->proto = htons(ETH_P_IP);
300 remote->port = ip4->sin_port;
301 remote->ipv4.s_addr = ip4->sin_addr.s_addr;
302 return 0; 279 return 0;
303 280
304#if IS_ENABLED(CONFIG_IPV6) 281#if IS_ENABLED(CONFIG_IPV6)
305 } else if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET6) { 282 } else if (sa.ss_family == AF_INET6) {
306 int atype; 283 struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)&sa;
307 struct sockaddr_in6 *ip6; 284
308 285 addr->proto = htons(ETH_P_IPV6);
309 ip6 = (struct sockaddr_in6 *)&sa_local; 286 addr->port = ip6->sin6_port;
310 atype = ipv6_addr_type(&ip6->sin6_addr); 287 memcpy(&addr->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
311 if (__ipv6_addr_needs_scope_id(atype) && !ip6->sin6_scope_id) 288
312 return -EINVAL; 289 /* Scope ID is only interesting for local addresses */
313 290 if (scope_id) {
314 local->proto = htons(ETH_P_IPV6); 291 int atype;
315 local->port = ip6->sin6_port; 292
316 memcpy(&local->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); 293 atype = ipv6_addr_type(&ip6->sin6_addr);
317 ub->ifindex = ip6->sin6_scope_id; 294 if (__ipv6_addr_needs_scope_id(atype) &&
318 295 !ip6->sin6_scope_id) {
319 ip6 = (struct sockaddr_in6 *)&sa_remote; 296 return -EINVAL;
320 remote->proto = htons(ETH_P_IPV6); 297 }
321 remote->port = ip6->sin6_port; 298
322 memcpy(&remote->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); 299 *scope_id = ip6->sin6_scope_id ? : 0;
300 }
301
323 return 0; 302 return 0;
324#endif 303#endif
325 } 304 }
@@ -344,14 +323,33 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
344 struct udp_media_addr local = {0}; 323 struct udp_media_addr local = {0};
345 struct udp_port_cfg udp_conf = {0}; 324 struct udp_port_cfg udp_conf = {0};
346 struct udp_tunnel_sock_cfg tuncfg = {NULL}; 325 struct udp_tunnel_sock_cfg tuncfg = {NULL};
326 struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
347 327
348 ub = kzalloc(sizeof(*ub), GFP_ATOMIC); 328 ub = kzalloc(sizeof(*ub), GFP_ATOMIC);
349 if (!ub) 329 if (!ub)
350 return -ENOMEM; 330 return -ENOMEM;
351 331
332 if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
333 goto err;
334
335 if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX,
336 attrs[TIPC_NLA_BEARER_UDP_OPTS],
337 tipc_nl_udp_policy))
338 goto err;
339
340 if (!opts[TIPC_NLA_UDP_LOCAL] || !opts[TIPC_NLA_UDP_REMOTE]) {
341 pr_err("Invalid UDP bearer configuration");
342 return -EINVAL;
343 }
344
345 err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_LOCAL], &local,
346 &ub->ifindex);
347 if (err)
348 goto err;
349
352 remote = (struct udp_media_addr *)&b->bcast_addr.value; 350 remote = (struct udp_media_addr *)&b->bcast_addr.value;
353 memset(remote, 0, sizeof(struct udp_media_addr)); 351 memset(remote, 0, sizeof(struct udp_media_addr));
354 err = parse_options(attrs, ub, &local, remote); 352 err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], remote, NULL);
355 if (err) 353 if (err)
356 goto err; 354 goto err;
357 355