LCOV - code coverage report
Current view: top level - network - networkd-dhcp6.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 178 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright (C) 2014 Intel Corporation. All rights reserved.
       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 <netinet/ether.h>
      23             : #include <linux/if.h>
      24             : 
      25             : #include "networkd-link.h"
      26             : #include "network-internal.h"
      27             : 
      28             : #include "sd-icmp6-nd.h"
      29             : #include "sd-dhcp6-client.h"
      30             : 
      31             : static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
      32             : 
      33           0 : static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
      34             :                                         Link *link) {
      35           0 :         return 0;
      36             : }
      37             : 
      38           0 : static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
      39             :                                  void *userdata) {
      40           0 :         _cleanup_link_unref_ Link *link = userdata;
      41             :         int r;
      42             : 
      43           0 :         assert(link);
      44             : 
      45           0 :         r = sd_netlink_message_get_errno(m);
      46           0 :         if (r < 0 && r != -EEXIST) {
      47           0 :                 if (link->rtnl_extended_attrs) {
      48           0 :                         log_link_warning(link, "Could not set extended netlink attributes, reverting to fallback mechanism");
      49             : 
      50           0 :                         link->rtnl_extended_attrs = false;
      51           0 :                         dhcp6_lease_address_acquired(link->dhcp6_client, link);
      52             : 
      53           0 :                         return 1;
      54             :                 }
      55             : 
      56           0 :                 log_link_error(link, "Could not set DHCPv6 address: %s",
      57             :                                strerror(-r));
      58             : 
      59           0 :                 link_enter_failed(link);
      60             : 
      61           0 :         } else if (r >= 0)
      62           0 :                 link_rtnl_process_address(rtnl, m, link->manager);
      63             : 
      64           0 :         return 1;
      65             : }
      66             : 
      67           0 : static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
      68             :                                 uint8_t prefixlen, uint32_t lifetime_preferred,
      69             :                                 uint32_t lifetime_valid) {
      70             :         int r;
      71           0 :         _cleanup_address_free_ Address *addr = NULL;
      72             : 
      73           0 :         r = address_new_dynamic(&addr);
      74           0 :         if (r < 0)
      75           0 :                 return r;
      76             : 
      77           0 :         addr->family = AF_INET6;
      78           0 :         memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
      79             : 
      80           0 :         addr->flags = IFA_F_NOPREFIXROUTE;
      81           0 :         addr->prefixlen = prefixlen;
      82             : 
      83           0 :         addr->cinfo.ifa_prefered = lifetime_preferred;
      84           0 :         addr->cinfo.ifa_valid = lifetime_valid;
      85             : 
      86           0 :         log_link_info(link,
      87             :                       "DHCPv6 address "SD_ICMP6_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
      88             :                       SD_ICMP6_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
      89             :                       addr->prefixlen, lifetime_preferred, lifetime_valid);
      90             : 
      91           0 :         r = address_update(addr, link, dhcp6_address_handler);
      92           0 :         if (r < 0)
      93           0 :                 log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
      94             : 
      95           0 :         return r;
      96             : }
      97             : 
      98           0 : static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
      99             :         int r;
     100             :         sd_dhcp6_lease *lease;
     101             :         struct in6_addr ip6_addr;
     102             :         uint32_t lifetime_preferred, lifetime_valid;
     103             :         uint8_t prefixlen;
     104             : 
     105           0 :         r = sd_dhcp6_client_get_lease(client, &lease);
     106           0 :         if (r < 0)
     107           0 :                 return r;
     108             : 
     109           0 :         sd_dhcp6_lease_reset_address_iter(lease);
     110             : 
     111           0 :         while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
     112             :                                                 &lifetime_preferred,
     113             :                                                 &lifetime_valid) >= 0) {
     114             : 
     115           0 :                 r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
     116             :                                         &ip6_addr, &prefixlen);
     117           0 :                 if (r < 0 && r != -EADDRNOTAVAIL) {
     118           0 :                         log_link_warning(link, "Could not get prefix information: %s",
     119             :                                         strerror(-r));
     120           0 :                         return r;
     121             :                 }
     122             : 
     123           0 :                 if (r == -EADDRNOTAVAIL)
     124           0 :                         prefixlen = 128;
     125             : 
     126           0 :                 r = dhcp6_address_update(link, &ip6_addr, prefixlen,
     127             :                                         lifetime_preferred, lifetime_valid);
     128           0 :                 if (r < 0)
     129           0 :                         return r;
     130             :         }
     131             : 
     132           0 :         return 0;
     133             : }
     134             : 
     135           0 : static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
     136             :         int r;
     137           0 :         Link *link = userdata;
     138             : 
     139           0 :         assert(link);
     140           0 :         assert(link->network);
     141           0 :         assert(link->manager);
     142             : 
     143           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     144           0 :                 return;
     145             : 
     146           0 :         switch(event) {
     147             :         case DHCP6_EVENT_STOP:
     148             :         case DHCP6_EVENT_RESEND_EXPIRE:
     149             :         case DHCP6_EVENT_RETRANS_MAX:
     150           0 :                 log_link_debug(link, "DHCPv6 event %d", event);
     151           0 :                 break;
     152             : 
     153             :         case DHCP6_EVENT_IP_ACQUIRE:
     154           0 :                 r = dhcp6_lease_address_acquired(client, link);
     155           0 :                 if (r < 0) {
     156           0 :                         link_enter_failed(link);
     157           0 :                         return;
     158             :                 }
     159             : 
     160             :                 /* fall through */
     161             :         case DHCP6_EVENT_INFORMATION_REQUEST:
     162           0 :                 r = dhcp6_lease_information_acquired(client, link);
     163           0 :                 if (r < 0) {
     164           0 :                         link_enter_failed(link);
     165           0 :                         return;
     166             :                 }
     167             : 
     168           0 :                 break;
     169             : 
     170             :         default:
     171           0 :                 if (event < 0)
     172           0 :                         log_link_warning(link, "DHCPv6 error: %s",
     173             :                                          strerror(-event));
     174             :                 else
     175           0 :                         log_link_warning(link, "DHCPv6 unknown event: %d",
     176             :                                          event);
     177           0 :                 return;
     178             :         }
     179             : }
     180             : 
     181           0 : static int dhcp6_configure(Link *link, int event) {
     182             :         int r;
     183             :         bool information_request;
     184             : 
     185           0 :         assert_return(link, -EINVAL);
     186             : 
     187           0 :         if (link->dhcp6_client) {
     188           0 :                 if (event != ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED)
     189           0 :                         return 0;
     190             : 
     191           0 :                 r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
     192             :                                                         &information_request);
     193           0 :                 if (r < 0) {
     194           0 :                         log_link_warning(link, "Could not get DHCPv6 Information request setting: %s",
     195             :                                         strerror(-r));
     196           0 :                         link->dhcp6_client =
     197           0 :                                 sd_dhcp6_client_unref(link->dhcp6_client);
     198           0 :                         return r;
     199             :                 }
     200             : 
     201           0 :                 if (!information_request)
     202           0 :                         return r;
     203             : 
     204           0 :                 r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
     205             :                                                         false);
     206           0 :                 if (r < 0) {
     207           0 :                         log_link_warning(link, "Could not unset DHCPv6 Information request: %s",
     208             :                                         strerror(-r));
     209           0 :                         link->dhcp6_client =
     210           0 :                                 sd_dhcp6_client_unref(link->dhcp6_client);
     211           0 :                         return r;
     212             :                 }
     213             : 
     214           0 :                 r = sd_dhcp6_client_start(link->dhcp6_client);
     215           0 :                 if (r < 0) {
     216           0 :                         log_link_warning(link, "Could not restart DHCPv6 after enabling Information request: %s",
     217             :                                         strerror(-r));
     218           0 :                         link->dhcp6_client =
     219           0 :                                 sd_dhcp6_client_unref(link->dhcp6_client);
     220           0 :                         return r;
     221             :                 }
     222             : 
     223           0 :                 return r;
     224             :         }
     225             : 
     226           0 :         r = sd_dhcp6_client_new(&link->dhcp6_client);
     227           0 :         if (r < 0)
     228           0 :                 return r;
     229             : 
     230           0 :         r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
     231           0 :         if (r < 0) {
     232           0 :                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
     233           0 :                 return r;
     234             :         }
     235             : 
     236           0 :         r = sd_dhcp6_client_set_mac(link->dhcp6_client,
     237           0 :                                     (const uint8_t *) &link->mac,
     238             :                                     sizeof (link->mac), ARPHRD_ETHER);
     239           0 :         if (r < 0) {
     240           0 :                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
     241           0 :                 return r;
     242             :         }
     243             : 
     244           0 :         r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
     245           0 :         if (r < 0) {
     246           0 :                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
     247           0 :                 return r;
     248             :         }
     249             : 
     250           0 :         r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
     251             :                                          link);
     252           0 :         if (r < 0) {
     253           0 :                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
     254           0 :                 return r;
     255             :         }
     256             : 
     257           0 :         if (event == ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER) {
     258           0 :                 r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
     259             :                                                         true);
     260           0 :                 if (r < 0) {
     261           0 :                         link->dhcp6_client =
     262           0 :                                 sd_dhcp6_client_unref(link->dhcp6_client);
     263           0 :                         return r;
     264             :                 }
     265             :         }
     266             : 
     267           0 :         r = sd_dhcp6_client_start(link->dhcp6_client);
     268           0 :         if (r < 0)
     269           0 :                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
     270             : 
     271           0 :         return r;
     272             : }
     273             : 
     274           0 : static int dhcp6_prefix_expired(Link *link) {
     275             :         int r;
     276             :         sd_dhcp6_lease *lease;
     277             :         struct in6_addr *expired_prefix, ip6_addr;
     278             :         uint8_t expired_prefixlen;
     279             :         uint32_t lifetime_preferred, lifetime_valid;
     280             : 
     281           0 :         r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
     282             :                                         &expired_prefix, &expired_prefixlen);
     283           0 :         if (r < 0)
     284           0 :                 return r;
     285             : 
     286           0 :         r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
     287           0 :         if (r < 0)
     288           0 :                 return r;
     289             : 
     290           0 :         log_link_info(link, "IPv6 prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d expired",
     291             :                       SD_ICMP6_ADDRESS_FORMAT_VAL(*expired_prefix),
     292             :                       expired_prefixlen);
     293             : 
     294           0 :         sd_dhcp6_lease_reset_address_iter(lease);
     295             : 
     296           0 :         while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
     297             :                                                 &lifetime_preferred,
     298             :                                                 &lifetime_valid) >= 0) {
     299             : 
     300           0 :                 r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
     301             :                                         &ip6_addr);
     302           0 :                 if (r < 0)
     303           0 :                         continue;
     304             : 
     305           0 :                 log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ADDRESS_FORMAT_VAL(ip6_addr), 128);
     306             : 
     307           0 :                 dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
     308             :         }
     309             : 
     310           0 :         return 0;
     311             : }
     312             : 
     313           0 : static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
     314           0 :         Link *link = userdata;
     315             : 
     316           0 :         assert(link);
     317           0 :         assert(link->network);
     318           0 :         assert(link->manager);
     319             : 
     320           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     321           0 :                 return;
     322             : 
     323           0 :         switch(event) {
     324             :         case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
     325           0 :                 return;
     326             : 
     327             :         case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
     328             :         case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
     329             :         case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
     330           0 :                 dhcp6_configure(link, event);
     331             : 
     332           0 :                 break;
     333             : 
     334             :         case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
     335           0 :                 if (!link->rtnl_extended_attrs)
     336           0 :                         dhcp6_prefix_expired(link);
     337             : 
     338           0 :                 break;
     339             : 
     340             :         default:
     341           0 :                 if (event < 0)
     342           0 :                         log_link_warning(link, "ICMPv6 error: %s",
     343             :                                          strerror(-event));
     344             :                 else
     345           0 :                         log_link_warning(link, "ICMPv6 unknown event: %d",
     346             :                                          event);
     347             : 
     348           0 :                 break;
     349             :         }
     350             : 
     351             : }
     352             : 
     353           0 : int icmp6_configure(Link *link) {
     354             :         int r;
     355             : 
     356           0 :         assert_return(link, -EINVAL);
     357             : 
     358           0 :         r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
     359           0 :         if (r < 0)
     360           0 :                 return r;
     361             : 
     362           0 :         r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0);
     363           0 :         if (r < 0)
     364           0 :                 return r;
     365             : 
     366           0 :         r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac);
     367           0 :         if (r < 0)
     368           0 :                 return r;
     369             : 
     370           0 :         r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex);
     371           0 :         if (r < 0)
     372           0 :                 return r;
     373             : 
     374           0 :         r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
     375             :                                 icmp6_router_handler, link);
     376             : 
     377           0 :         return r;
     378             : }

Generated by: LCOV version 1.11