e3169126793f43be3d840874ffb3935a51097001Patrik Flykt/***
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt This file is part of systemd.
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt Copyright (C) 2014 Intel Corporation. All rights reserved.
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt systemd is free software; you can redistribute it and/or modify it
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt under the terms of the GNU Lesser General Public License as published by
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt the Free Software Foundation; either version 2.1 of the License, or
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt (at your option) any later version.
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt systemd is distributed in the hope that it will be useful, but
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt Lesser General Public License for more details.
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt You should have received a copy of the GNU Lesser General Public License
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt***/
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt#include <errno.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <netinet/in.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <netinet/ip6.h>
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt#include <stdio.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <string.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <sys/socket.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <sys/types.h>
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt#include <unistd.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <linux/if_packet.h>
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt#include "dhcp6-internal.h"
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt#include "dhcp6-protocol.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "socket-util.h"
e3169126793f43be3d840874ffb3935a51097001Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flyktint dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt union sockaddr_union src = {
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt .in6.sin6_family = AF_INET6,
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen .in6.sin6_scope_id = index,
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt };
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt _cleanup_close_ int s = -1;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt int r, off = 0, on = 1;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen assert(index > 0);
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen assert(local_address);
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen
c601ebf79f0c54be14d3c16f0f484c0335cdeec4Tom Gundersen src.in6.sin6_addr = *local_address;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
6506063f8f68f589040cfcc138d3f61269fb2a63Tom Gundersen s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP);
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt if (s < 0)
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return -errno;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt if (r < 0)
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return -errno;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt if (r < 0)
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return -errno;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
6506063f8f68f589040cfcc138d3f61269fb2a63Tom Gundersen r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
6506063f8f68f589040cfcc138d3f61269fb2a63Tom Gundersen if (r < 0)
6506063f8f68f589040cfcc138d3f61269fb2a63Tom Gundersen return -errno;
6506063f8f68f589040cfcc138d3f61269fb2a63Tom Gundersen
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt r = bind(s, &src.sa, sizeof(src.in6));
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt if (r < 0)
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return -errno;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt r = s;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt s = -1;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return r;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt}
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flyktint dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt const void *packet, size_t len) {
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt union sockaddr_union dest = {
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt .in6.sin6_family = AF_INET6,
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt .in6.sin6_port = htobe16(DHCP6_PORT_SERVER),
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt };
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt int r;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt assert(server_address);
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr));
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6));
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt if (r < 0)
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return -errno;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt return 0;
34e8c5a23cd1c53ef3c1169388dabe1f6dfd7319Patrik Flykt}