~ubuntu-branches/ubuntu/oneiric/network-manager/oneiric

« back to all changes in this revision

Viewing changes to .pc/libnl3-cache-args.patch/src/nm-netlink-utils.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2011-09-28 11:59:27 UTC
  • Revision ID: package-import@ubuntu.com-20110928115927-yjmzefutrycez8eu
Tags: 0.9.1.90-0ubuntu2
* debian/patches/libnl3-cache-args.patch: unbreak setting route priorities,
  which will also unbreak cases where connections fails when  wired and wifi
  are connected to the same network. (LP: #856333)
* debian/patches/dhcpv6-duid-support.patch: support handling DUIDs for DHCPv6
  requests, as defined by RFC 3315, section 9. (LP: #849994)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 
2
/* NetworkManager -- Network link manager
 
3
 *
 
4
 * This program is free software; you can redistribute it 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
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License along
 
15
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
17
 *
 
18
 * Copyright (C) 2011 Red Hat, Inc.
 
19
 */
 
20
 
 
21
#include "logging/nm-logging.h"
 
22
#include "nm-netlink-utils.h"
 
23
#include "nm-netlink-monitor.h"
 
24
#include "nm-netlink-compat.h"
 
25
 
 
26
#include <arpa/inet.h>
 
27
#include <netinet/in.h>
 
28
#include <netlink/netlink.h>
 
29
#include <netlink/addr.h>
 
30
#include <netlink/route/addr.h>
 
31
 
 
32
#include <errno.h>
 
33
 
 
34
typedef struct {
 
35
        int ifindex;
 
36
        int family;
 
37
        void *addr;
 
38
        int addrlen;
 
39
        int prefix;
 
40
        gboolean found;
 
41
} FindAddrInfo;
 
42
 
 
43
static void
 
44
find_one_address (struct nl_object *object, void *user_data)
 
45
{
 
46
        FindAddrInfo *info = user_data;
 
47
        struct rtnl_addr *addr = (struct rtnl_addr *) object;
 
48
        struct nl_addr *local;
 
49
        void *binaddr;
 
50
 
 
51
        if (info->found)
 
52
                return;
 
53
 
 
54
        if (rtnl_addr_get_ifindex (addr) != info->ifindex)
 
55
                return;
 
56
        if (rtnl_addr_get_family (addr) != info->family)
 
57
                return;
 
58
 
 
59
        if (rtnl_addr_get_prefixlen (addr) != info->prefix)
 
60
                return;
 
61
 
 
62
        local = rtnl_addr_get_local (addr);
 
63
        if (nl_addr_get_family (local) != info->family)
 
64
                return;
 
65
        if (nl_addr_get_len (local) != info->addrlen)
 
66
                return;
 
67
        binaddr = nl_addr_get_binary_addr (local);
 
68
        if (binaddr) {
 
69
                if (memcmp (binaddr, info->addr, info->addrlen) == 0)
 
70
                        info->found = TRUE; /* Yay, found it */
 
71
        }
 
72
}
 
73
 
 
74
/**
 
75
 * nm_netlink_find_address:
 
76
 * @ifindex: interface index
 
77
 * @family: address family, either AF_INET or AF_INET6
 
78
 * @addr: binary address, either struct in_addr* or struct in6_addr*
 
79
 * @prefix: prefix length
 
80
 *
 
81
 * Searches for a matching address on the given interface.
 
82
 *
 
83
 * Returns: %TRUE if the given address was found on the interface, %FALSE if it
 
84
 * was not found or an error occurred.
 
85
 **/
 
86
gboolean
 
87
nm_netlink_find_address (int ifindex,
 
88
                         int family,
 
89
                         void *addr,  /* struct in_addr or struct in6_addr */
 
90
                         int prefix)
 
91
{
 
92
        struct nl_sock *nlh = NULL;
 
93
        struct nl_cache *cache = NULL;
 
94
        FindAddrInfo info;
 
95
 
 
96
        g_return_val_if_fail (ifindex > 0, FALSE);
 
97
        g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
 
98
        g_return_val_if_fail (addr != NULL, FALSE);
 
99
        g_return_val_if_fail (prefix >= 0, FALSE);
 
100
 
 
101
        memset (&info, 0, sizeof (info));
 
102
        info.ifindex = ifindex;
 
103
        info.family = family;
 
104
        info.prefix = prefix;
 
105
        info.addr = addr;
 
106
        if (family == AF_INET)
 
107
                info.addrlen = sizeof (struct in_addr);
 
108
        else if (family == AF_INET6)
 
109
                info.addrlen = sizeof (struct in6_addr);
 
110
        else
 
111
                g_assert_not_reached ();
 
112
 
 
113
        nlh = nm_netlink_get_default_handle ();
 
114
        if (nlh) {
 
115
                rtnl_addr_alloc_cache(nlh, &cache);
 
116
                if (cache) {
 
117
                        nl_cache_mngt_provide (cache);
 
118
                        nl_cache_foreach (cache, find_one_address, &info);
 
119
                        nl_cache_free (cache);
 
120
                }
 
121
        }
 
122
        return info.found;
 
123
}
 
124
 
 
125
struct rtnl_route *
 
126
nm_netlink_route_new (int ifindex,
 
127
                      int family,
 
128
                      int mss,
 
129
                      ...)
 
130
{
 
131
        va_list var_args;
 
132
        struct rtnl_route *route;
 
133
        NmNlProp prop = NMNL_PROP_INVALID;
 
134
        int value;
 
135
 
 
136
        route = rtnl_route_alloc ();
 
137
        g_return_val_if_fail (route != NULL, NULL);
 
138
 
 
139
        if (ifindex >= 0)
 
140
                rtnl_route_set_oif (route, ifindex);
 
141
        if (family != AF_UNSPEC)
 
142
                rtnl_route_set_family (route, family);
 
143
        if (mss > 0)
 
144
                rtnl_route_set_metric (route, RTAX_ADVMSS, mss);
 
145
 
 
146
        va_start (var_args, mss);
 
147
        prop = va_arg (var_args, NmNlProp);
 
148
        while (prop != NMNL_PROP_INVALID) {
 
149
                value = va_arg (var_args, int);
 
150
 
 
151
                if (prop == NMNL_PROP_PROT && value != RTPROT_UNSPEC)
 
152
                        rtnl_route_set_protocol (route, value);
 
153
                else if (prop == NMNL_PROP_TABLE && value != RT_TABLE_UNSPEC)
 
154
                        rtnl_route_set_table (route, value);
 
155
                else if (prop == NMNL_PROP_SCOPE && value != RT_SCOPE_NOWHERE)
 
156
                        rtnl_route_set_scope (route, value);
 
157
                else if (prop == NMNL_PROP_PRIO && value > 0)
 
158
                        rtnl_route_set_priority (route, value);
 
159
 
 
160
                prop = va_arg (var_args, NmNlProp);
 
161
        }
 
162
        va_end (var_args);
 
163
 
 
164
        return route;
 
165
}
 
166
 
 
167
/**
 
168
 * nm_netlink_route_add:
 
169
 * @route: the route to add
 
170
 *
 
171
 * Returns: zero if succeeded or the netlink error otherwise.
 
172
 **/
 
173
int nm_netlink_route_add(struct rtnl_route * route,
 
174
                         int family,
 
175
                         const void * dest, /* in_addr or in6_addr */
 
176
                         int dest_prefix,
 
177
                         const void * gateway, /* in_addr or in6_addr */
 
178
                         int flags)
 
179
{
 
180
        struct nl_sock * sk;
 
181
        struct nl_addr * dest_addr, * gw_addr;
 
182
        void * tmp_addr;
 
183
        int addrlen, err, log;
 
184
 
 
185
        if(family == AF_INET) {
 
186
                addrlen = sizeof(struct in_addr);
 
187
                log = LOGD_IP4;
 
188
        }
 
189
        else if (family == AF_INET6) {
 
190
                addrlen = sizeof(struct in6_addr);
 
191
                log = LOGD_IP6;
 
192
        } else {
 
193
                g_assert_not_reached ();
 
194
        }
 
195
 
 
196
 
 
197
        sk = nm_netlink_get_default_handle();
 
198
 
 
199
        /* Build up the destination address */
 
200
        if (dest) {
 
201
                /* Copy to preserve const */
 
202
                tmp_addr = g_malloc0(addrlen);
 
203
                memcpy(tmp_addr, dest, addrlen);
 
204
 
 
205
                dest_addr = nl_addr_build (family, tmp_addr, addrlen);
 
206
                g_free(tmp_addr);
 
207
 
 
208
                g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL);
 
209
                nl_addr_set_prefixlen (dest_addr, dest_prefix);
 
210
 
 
211
                rtnl_route_set_dst (route, dest_addr);
 
212
                nl_addr_put (dest_addr);
 
213
        }
 
214
 
 
215
        /* Build up the gateway address */
 
216
        if (gateway) {
 
217
                tmp_addr = g_malloc0(addrlen);
 
218
                memcpy(tmp_addr, gateway, addrlen);
 
219
 
 
220
                gw_addr = nl_addr_build (family, tmp_addr, addrlen);
 
221
                g_free(tmp_addr);
 
222
 
 
223
                if (gw_addr) {
 
224
                        nl_addr_set_prefixlen (gw_addr, 0);
 
225
                        rtnl_route_set_gateway (route, gw_addr);
 
226
                        rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
 
227
                        nl_addr_put(gw_addr);
 
228
                } else {
 
229
                        nm_log_err (LOGD_DEVICE | log, "Invalid gateway");
 
230
                }
 
231
        }
 
232
 
 
233
        err = rtnl_route_add (sk, route, flags);
 
234
 
 
235
        /* LIBNL Bug: Aliased ESRCH */
 
236
        if (err == -NLE_FAILURE)
 
237
                err = -NLE_OBJ_NOTFOUND;
 
238
 
 
239
        if (err)
 
240
                nm_log_warn (LOGD_DEVICE | log,
 
241
                             "Failed to add route %s",
 
242
                             nl_geterror(err));
 
243
 
 
244
        return err;
 
245
}
 
246
 
 
247
/**
 
248
 * nm_netlink_route_delete:
 
249
 * @route: the route to delete
 
250
 *
 
251
 * Returns: %TRUE if the request was successful, %FALSE if it failed
 
252
 **/
 
253
gboolean
 
254
nm_netlink_route_delete (struct rtnl_route *route)
 
255
{
 
256
        struct nl_sock *nlh;
 
257
        int err = 0;
 
258
 
 
259
        g_return_val_if_fail (route != NULL, FALSE);
 
260
 
 
261
        nlh = nm_netlink_get_default_handle ();
 
262
        err = rtnl_route_delete (nlh, route, 0);
 
263
 
 
264
        if (err)
 
265
                nm_log_dbg (LOGD_IP4 | LOGD_IP6, "%s (%d)", nl_geterror(err), err);
 
266
 
 
267
        /* Workaround libnl BUG: ESRCH is aliased to generic NLE_FAILURE
 
268
         * See: http://git.kernel.org/?p=libs/netlink/libnl.git;a=commit;h=7e9d5f */
 
269
        if (err == -NLE_FAILURE)
 
270
                err = -NLE_OBJ_NOTFOUND;
 
271
 
 
272
        return (err && (err != -NLE_OBJ_NOTFOUND) && (err != -NLE_RANGE) ) ? FALSE : TRUE;
 
273
}
 
274
 
 
275
 
 
276
static void
 
277
dump_route (struct rtnl_route *route)
 
278
{
 
279
        char buf6[INET6_ADDRSTRLEN];
 
280
        char buf4[INET_ADDRSTRLEN];
 
281
        struct nl_addr *nl;
 
282
        struct in6_addr *addr6 = NULL;
 
283
        struct in_addr *addr4 = NULL;
 
284
        int prefixlen = 0;
 
285
        const char *sf = "UNSPEC";
 
286
        int family = rtnl_route_get_family (route);
 
287
        guint32 log_level = LOGD_IP4 | LOGD_IP6;
 
288
 
 
289
        memset (buf6, 0, sizeof (buf6));
 
290
        memset (buf4, 0, sizeof (buf4));
 
291
        nl = rtnl_route_get_dst (route);
 
292
        if (nl) {
 
293
                if (nl_addr_get_family (nl) == AF_INET) {
 
294
                        addr4 = nl_addr_get_binary_addr (nl);
 
295
                        if (addr4)
 
296
                                inet_ntop (AF_INET, addr4, &buf4[0], sizeof (buf4));
 
297
                } else if (nl_addr_get_family (nl) == AF_INET6) {
 
298
                        addr6 = nl_addr_get_binary_addr (nl);
 
299
                        if (addr6)
 
300
                                inet_ntop (AF_INET6, addr6, &buf6[0], sizeof (buf6));
 
301
                }
 
302
                prefixlen = nl_addr_get_prefixlen (nl);
 
303
        }
 
304
 
 
305
        if (family == AF_INET) {
 
306
                sf = "INET";
 
307
                log_level = LOGD_IP4;
 
308
        } else if (family == AF_INET6) {
 
309
                sf = "INET6";
 
310
                log_level = LOGD_IP6;
 
311
        }
 
312
 
 
313
        nm_log_dbg (log_level, "  route idx %d family %s (%d) addr %s/%d",
 
314
                    rtnl_route_get_oif (route),
 
315
                    sf, family,
 
316
                    strlen (buf4) ? buf4 : (strlen (buf6) ? buf6 : "<unknown>"),
 
317
                    prefixlen);
 
318
}
 
319
 
 
320
 
 
321
typedef struct {
 
322
        int ifindex;
 
323
        int family;
 
324
        int scope;
 
325
        gboolean ignore_inet6_ll_mc;
 
326
        const char *iface;
 
327
        NlRouteForeachFunc callback;
 
328
        gpointer user_data;
 
329
        struct rtnl_route *out_route;
 
330
} ForeachRouteInfo;
 
331
 
 
332
static void
 
333
foreach_route_cb (struct nl_object *object, void *user_data)
 
334
{
 
335
        ForeachRouteInfo *info = user_data;
 
336
        struct rtnl_route *route = (struct rtnl_route *) object;
 
337
        struct nl_addr *dst;
 
338
 
 
339
        if (info->out_route)
 
340
                return;
 
341
 
 
342
        if (nm_logging_level_enabled (LOGL_DEBUG))
 
343
                dump_route (route);
 
344
 
 
345
        if (   info->ifindex >= 0
 
346
            && rtnl_route_get_oif (route) != info->ifindex)
 
347
                return;
 
348
 
 
349
        if (   info->scope != RT_SCOPE_UNIVERSE
 
350
            && rtnl_route_get_scope (route) != info->scope)
 
351
                return;
 
352
 
 
353
        if (   info->family != AF_UNSPEC
 
354
            && rtnl_route_get_family (route) != info->family)
 
355
                return;
 
356
 
 
357
        dst = rtnl_route_get_dst (route);
 
358
 
 
359
        /* Check for IPv6 LL and MC routes that might need to be ignored */
 
360
        if (   (info->family == AF_INET6 || info->family == AF_UNSPEC)
 
361
            && (rtnl_route_get_family (route) == AF_INET6)) {
 
362
                struct in6_addr *addr = NULL;
 
363
 
 
364
                if (dst)
 
365
                        addr = nl_addr_get_binary_addr (dst);
 
366
                if (addr) {
 
367
                        if (   IN6_IS_ADDR_LINKLOCAL (addr)
 
368
                            || IN6_IS_ADDR_MC_LINKLOCAL (addr)
 
369
                            || (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (dst) == 8)))
 
370
                                return;
 
371
                }
 
372
        }
 
373
 
 
374
        info->out_route = info->callback (route, dst, info->iface, info->user_data);
 
375
        if (info->out_route) {
 
376
                /* Ref the route so it sticks around after the cache is cleared */
 
377
                rtnl_route_get (info->out_route);
 
378
        }
 
379
}
 
380
 
 
381
/**
 
382
 * nm_netlink_foreach_route:
 
383
 * @ifindex: the interface index to filter routes for
 
384
 * @family: the address family to filter routes for
 
385
 * @scope: route scope, eg RT_SCOPE_LINK
 
386
 * @ignore_inet6_ll_mc: if %TRUE ignore IPv6 link-local and multi-cast routes
 
387
 * @callback: function called when a route matches the filter
 
388
 * @user_data: data passed to @callback
 
389
 *
 
390
 * Filters each route in the routing table against the given @ifindex and
 
391
 * @family (if given) and calls @callback for each matching route.
 
392
 *
 
393
 * Returns: a route if @callback returned one; the caller must dispose of the
 
394
 * route using rtnl_route_put() when it is no longer required.
 
395
 **/
 
396
struct rtnl_route *
 
397
nm_netlink_foreach_route (int ifindex,
 
398
                          int family,
 
399
                          int scope,
 
400
                          gboolean ignore_inet6_ll_mc,
 
401
                          NlRouteForeachFunc callback,
 
402
                          gpointer user_data)
 
403
{
 
404
        struct nl_cache *cache;
 
405
        ForeachRouteInfo info;
 
406
 
 
407
        memset (&info, 0, sizeof (info));
 
408
        info.ifindex = ifindex;
 
409
        info.family = family;
 
410
        info.scope = scope;
 
411
        info.ignore_inet6_ll_mc = ignore_inet6_ll_mc;
 
412
        info.callback = callback;
 
413
        info.user_data = user_data;
 
414
        info.iface = nm_netlink_index_to_iface (ifindex);
 
415
 
 
416
        rtnl_route_alloc_cache (nm_netlink_get_default_handle (), family, NL_AUTO_PROVIDE, &cache);
 
417
        g_return_val_if_fail (cache != NULL, NULL);
 
418
        nl_cache_foreach (cache, foreach_route_cb, &info);
 
419
        nl_cache_free (cache);
 
420
        return info.out_route;
 
421
}
 
422
 
 
423