diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/udp_media.c | 112 |
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 | */ |
267 | static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub, | 266 | |
268 | struct udp_media_addr *local, | 267 | static 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 { | ||
286 | err: | ||
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 | ||