chiark / gitweb /
networkctl: avoid leak if a field was specified twice
[elogind.git] / src / network / networkctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
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 <stdbool.h>
23 #include <getopt.h>
24 #include <net/if.h>
25
26 #include "sd-network.h"
27 #include "sd-rtnl.h"
28 #include "sd-hwdb.h"
29 #include "libudev.h"
30
31 #include "strv.h"
32 #include "build.h"
33 #include "util.h"
34 #include "pager.h"
35 #include "lldp.h"
36 #include "rtnl-util.h"
37 #include "udev-util.h"
38 #include "hwdb-util.h"
39 #include "arphrd-list.h"
40 #include "local-addresses.h"
41 #include "socket-util.h"
42 #include "ether-addr-util.h"
43 #include "verbs.h"
44
45 static bool arg_no_pager = false;
46 static bool arg_legend = true;
47 static bool arg_all = false;
48
49 static void pager_open_if_enabled(void) {
50
51         if (arg_no_pager)
52                 return;
53
54         pager_open(false);
55 }
56
57 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
58         const char *t;
59         char *p;
60
61         if (iftype == ARPHRD_ETHER && d) {
62                 const char *devtype, *id = NULL;
63                 /* WLANs have iftype ARPHRD_ETHER, but we want
64                  * to show a more useful type string for
65                  * them */
66
67                 devtype = udev_device_get_devtype(d);
68                 if (streq_ptr(devtype, "wlan"))
69                         id = "wlan";
70                 else if (streq_ptr(devtype, "wwan"))
71                         id = "wwan";
72
73                 if (id) {
74                         p = strdup(id);
75                         if (!p)
76                                 return -ENOMEM;
77
78                         *ret = p;
79                         return 1;
80                 }
81         }
82
83         t = arphrd_to_name(iftype);
84         if (!t) {
85                 *ret = NULL;
86                 return 0;
87         }
88
89         p = strdup(t);
90         if (!p)
91                 return -ENOMEM;
92
93         ascii_strlower(p);
94         *ret = p;
95
96         return 0;
97 }
98
99 typedef struct LinkInfo {
100         const char *name;
101         int ifindex;
102         unsigned iftype;
103 } LinkInfo;
104
105 static int link_info_compare(const void *a, const void *b) {
106         const LinkInfo *x = a, *y = b;
107
108         return x->ifindex - y->ifindex;
109 }
110
111 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
112         _cleanup_free_ LinkInfo *links = NULL;
113         size_t size = 0, c = 0;
114         sd_rtnl_message *i;
115         int r;
116
117         for (i = m; i; i = sd_rtnl_message_next(i)) {
118                 const char *name;
119                 unsigned iftype;
120                 uint16_t type;
121                 int ifindex;
122
123                 r = sd_rtnl_message_get_type(i, &type);
124                 if (r < 0)
125                         return r;
126
127                 if (type != RTM_NEWLINK)
128                         continue;
129
130                 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
131                 if (r < 0)
132                         return r;
133
134                 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
135                 if (r < 0)
136                         return r;
137
138                 r = sd_rtnl_message_link_get_type(i, &iftype);
139                 if (r < 0)
140                         return r;
141
142                 if (!GREEDY_REALLOC(links, size, c+1))
143                         return -ENOMEM;
144
145                 links[c].name = name;
146                 links[c].ifindex = ifindex;
147                 links[c].iftype = iftype;
148                 c++;
149         }
150
151         qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
152
153         *ret = links;
154         links = NULL;
155
156         return (int) c;
157 }
158
159 static void operational_state_to_color(const char *state, const char **on, const char **off) {
160         assert(on);
161         assert(off);
162
163         if (streq_ptr(state, "routable")) {
164                 *on = ansi_highlight_green();
165                 *off = ansi_highlight_off();
166         } else if (streq_ptr(state, "degraded")) {
167                 *on = ansi_highlight_yellow();
168                 *off = ansi_highlight_off();
169         } else
170                 *on = *off = "";
171 }
172
173 static void setup_state_to_color(const char *state, const char **on, const char **off) {
174         assert(on);
175         assert(off);
176
177         if (streq_ptr(state, "configured")) {
178                 *on = ansi_highlight_green();
179                 *off = ansi_highlight_off();
180         } else if (streq_ptr(state, "configuring")) {
181                 *on = ansi_highlight_yellow();
182                 *off = ansi_highlight_off();
183         } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
184                 *on = ansi_highlight_red();
185                 *off = ansi_highlight_off();
186         } else
187                 *on = *off = "";
188 }
189
190 static int list_links(int argc, char *argv[], void *userdata) {
191         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
192         _cleanup_udev_unref_ struct udev *udev = NULL;
193         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
194         _cleanup_free_ LinkInfo *links = NULL;
195         int r, c, i;
196
197         pager_open_if_enabled();
198
199         r = sd_rtnl_open(&rtnl, 0);
200         if (r < 0)
201                 return log_error_errno(r, "Failed to connect to netlink: %m");
202
203         udev = udev_new();
204         if (!udev)
205                 return log_error_errno(errno, "Failed to connect to udev: %m");
206
207         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
208         if (r < 0)
209                 return rtnl_log_create_error(r);
210
211         r = sd_rtnl_message_request_dump(req, true);
212         if (r < 0)
213                 return rtnl_log_create_error(r);
214
215         r = sd_rtnl_call(rtnl, req, 0, &reply);
216         if (r < 0)
217                 return log_error_errno(r, "Failed to enumerate links: %m");
218
219         if (arg_legend)
220                 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
221
222         c = decode_and_sort_links(reply, &links);
223         if (c < 0)
224                 return rtnl_log_parse_error(c);
225
226         for (i = 0; i < c; i++) {
227                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
228                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
229                 const char *on_color_operational, *off_color_operational,
230                            *on_color_setup, *off_color_setup;
231                  char devid[2 + DECIMAL_STR_MAX(int)];
232                 _cleanup_free_ char *t = NULL;
233
234                 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
235                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
236
237                 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
238                 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
239
240                 sprintf(devid, "n%i", links[i].ifindex);
241                 d = udev_device_new_from_device_id(udev, devid);
242
243                 link_get_type_string(links[i].iftype, d, &t);
244
245                 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
246                        links[i].ifindex, links[i].name, strna(t),
247                        on_color_operational, strna(operational_state), off_color_operational,
248                        on_color_setup, strna(setup_state), off_color_setup);
249         }
250
251         if (arg_legend)
252                 printf("\n%i links listed.\n", c);
253
254         return 0;
255 }
256
257 /* IEEE Organizationally Unique Identifier vendor string */
258 static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
259         const char *description;
260         char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
261         int r;
262
263         assert(ret);
264
265         if (!hwdb)
266                 return -EINVAL;
267
268         if (!mac)
269                 return -EINVAL;
270
271         /* skip commonly misused 00:00:00 (Xerox) prefix */
272         if (memcmp(mac, "\0\0\0", 3) == 0)
273                 return -EINVAL;
274
275         snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
276
277         r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
278         if (r < 0)
279                 return r;
280
281         desc = strdup(description);
282         if (!desc)
283                 return -ENOMEM;
284
285         *ret = desc;
286
287         return 0;
288 }
289
290 static int get_gateway_description(
291                 sd_rtnl *rtnl,
292                 sd_hwdb *hwdb,
293                 int ifindex,
294                 int family,
295                 union in_addr_union *gateway,
296                 char **gateway_description) {
297         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
298         sd_rtnl_message *m;
299         int r;
300
301         assert(rtnl);
302         assert(ifindex >= 0);
303         assert(family == AF_INET || family == AF_INET6);
304         assert(gateway);
305         assert(gateway_description);
306
307         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
308         if (r < 0)
309                 return r;
310
311         r = sd_rtnl_message_request_dump(req, true);
312         if (r < 0)
313                 return r;
314
315         r = sd_rtnl_call(rtnl, req, 0, &reply);
316         if (r < 0)
317                 return r;
318
319         for (m = reply; m; m = sd_rtnl_message_next(m)) {
320                 union in_addr_union gw = {};
321                 struct ether_addr mac = {};
322                 uint16_t type;
323                 int ifi, fam;
324
325                 r = sd_rtnl_message_get_errno(m);
326                 if (r < 0) {
327                         log_error_errno(r, "got error: %m");
328                         continue;
329                 }
330
331                 r = sd_rtnl_message_get_type(m, &type);
332                 if (r < 0) {
333                         log_error_errno(r, "could not get type: %m");
334                         continue;
335                 }
336
337                 if (type != RTM_NEWNEIGH) {
338                         log_error("type is not RTM_NEWNEIGH");
339                         continue;
340                 }
341
342                 r = sd_rtnl_message_neigh_get_family(m, &fam);
343                 if (r < 0) {
344                         log_error_errno(r, "could not get family: %m");
345                         continue;
346                 }
347
348                 if (fam != family) {
349                         log_error("family is not correct");
350                         continue;
351                 }
352
353                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
354                 if (r < 0) {
355                         log_error_errno(r, "could not get ifindex: %m");
356                         continue;
357                 }
358
359                 if (ifindex > 0 && ifi != ifindex)
360                         continue;
361
362                 switch (fam) {
363                 case AF_INET:
364                         r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
365                         if (r < 0)
366                                 continue;
367
368                         break;
369                 case AF_INET6:
370                         r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
371                         if (r < 0)
372                                 continue;
373
374                         break;
375                 default:
376                         continue;
377                 }
378
379                 if (!in_addr_equal(fam, &gw, gateway))
380                         continue;
381
382                 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
383                 if (r < 0)
384                         continue;
385
386                 r = ieee_oui(hwdb, &mac, gateway_description);
387                 if (r < 0)
388                         continue;
389
390                 return 0;
391         }
392
393         return -ENODATA;
394 }
395
396 static int dump_gateways(
397                 sd_rtnl *rtnl,
398                 sd_hwdb *hwdb,
399                 const char *prefix,
400                 int ifindex) {
401         _cleanup_free_ struct local_address *local = NULL;
402         int r, n, i;
403
404         n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
405         if (n < 0)
406                 return n;
407
408         for (i = 0; i < n; i++) {
409                 _cleanup_free_ char *gateway = NULL, *description = NULL;
410
411                 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
412                 if (r < 0)
413                         return r;
414
415                 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
416                 if (r < 0)
417                         log_debug_errno(r, "Could not get description of gateway: %m");
418
419                 printf("%*s%s",
420                        (int) strlen(prefix),
421                        i == 0 ? prefix : "",
422                        gateway);
423
424                 if (description)
425                         printf(" (%s)", description);
426
427                 /* Show interface name for the entry if we show
428                  * entries for all interfaces */
429                 if (ifindex <= 0) {
430                         char name[IF_NAMESIZE+1];
431
432                         if (if_indextoname(local[i].ifindex, name)) {
433                                 fputs(" on ", stdout);
434                                 fputs(name, stdout);
435                         } else
436                                 printf(" on %%%i", local[i].ifindex);
437                 }
438
439                 fputc('\n', stdout);
440         }
441
442         return 0;
443 }
444
445 static int dump_addresses(
446                 sd_rtnl *rtnl,
447                 const char *prefix,
448                 int ifindex) {
449
450         _cleanup_free_ struct local_address *local = NULL;
451         int r, n, i;
452
453         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
454         if (n < 0)
455                 return n;
456
457         for (i = 0; i < n; i++) {
458                 _cleanup_free_ char *pretty = NULL;
459
460                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
461                 if (r < 0)
462                         return r;
463
464                 printf("%*s%s",
465                        (int) strlen(prefix),
466                        i == 0 ? prefix : "",
467                        pretty);
468
469                 if (ifindex <= 0) {
470                         char name[IF_NAMESIZE+1];
471
472                         if (if_indextoname(local[i].ifindex, name)) {
473                                 fputs(" on ", stdout);
474                                 fputs(name, stdout);
475                         } else
476                                 printf(" on %%%i", local[i].ifindex);
477                 }
478
479                 fputc('\n', stdout);
480         }
481
482         return 0;
483 }
484
485 static void dump_list(const char *prefix, char **l) {
486         char **i;
487
488         STRV_FOREACH(i, l) {
489                 printf("%*s%s\n",
490                        (int) strlen(prefix),
491                        i == l ? prefix : "",
492                        *i);
493         }
494 }
495
496 static int link_status_one(
497                 sd_rtnl *rtnl,
498                 struct udev *udev,
499                 sd_hwdb *hwdb,
500                 const char *name) {
501
502         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
503         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
504         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
505         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
506         char devid[2 + DECIMAL_STR_MAX(int)];
507         _cleanup_free_ char *t = NULL, *network = NULL;
508         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
509         const char *on_color_operational, *off_color_operational,
510                    *on_color_setup, *off_color_setup;
511         _cleanup_strv_free_ char **carrier_bound_to = NULL;
512         _cleanup_strv_free_ char **carrier_bound_by = NULL;
513         struct ether_addr e;
514         unsigned iftype;
515         int r, ifindex;
516         bool have_mac;
517         uint32_t mtu;
518
519         assert(rtnl);
520         assert(udev);
521         assert(name);
522
523         if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
524                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
525         else {
526                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
527                 if (r < 0)
528                         return rtnl_log_create_error(r);
529
530                 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
531         }
532
533         if (r < 0)
534                 return rtnl_log_create_error(r);
535
536         r = sd_rtnl_call(rtnl, req, 0, &reply);
537         if (r < 0)
538                 return log_error_errno(r, "Failed to query link: %m");
539
540         r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
541         if (r < 0)
542                 return rtnl_log_parse_error(r);
543
544         r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
545         if (r < 0)
546                 return rtnl_log_parse_error(r);
547
548         r = sd_rtnl_message_link_get_type(reply, &iftype);
549         if (r < 0)
550                 return rtnl_log_parse_error(r);
551
552         have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
553
554         if (have_mac) {
555                 const uint8_t *p;
556                 bool all_zeroes = true;
557
558                 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
559                         if (*p != 0) {
560                                 all_zeroes = false;
561                                 break;
562                         }
563
564                 if (all_zeroes)
565                         have_mac = false;
566         }
567
568         sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
569
570         sd_network_link_get_operational_state(ifindex, &operational_state);
571         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
572
573         sd_network_link_get_setup_state(ifindex, &setup_state);
574         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
575
576         sd_network_link_get_dns(ifindex, &dns);
577         sd_network_link_get_ntp(ifindex, &ntp);
578         sd_network_link_get_domains(ifindex, &domains);
579         r = sd_network_link_get_wildcard_domain(ifindex);
580         if (r > 0) {
581                 char *wildcard;
582
583                 wildcard = strdup("*");
584                 if (!wildcard)
585                         return log_oom();
586
587                 if (strv_consume(&domains, wildcard) < 0)
588                         return log_oom();
589         }
590
591         sprintf(devid, "n%i", ifindex);
592         d = udev_device_new_from_device_id(udev, devid);
593         if (d) {
594                 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
595                 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
596                 path = udev_device_get_property_value(d, "ID_PATH");
597
598                 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
599                 if (!vendor)
600                         vendor = udev_device_get_property_value(d, "ID_VENDOR");
601
602                 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
603                 if (!model)
604                         model = udev_device_get_property_value(d, "ID_MODEL");
605         }
606
607         link_get_type_string(iftype, d, &t);
608
609         sd_network_link_get_network_file(ifindex, &network);
610
611         sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
612         sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
613
614         printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
615
616         printf("       Link File: %s\n"
617                "    Network File: %s\n"
618                "            Type: %s\n"
619                "           State: %s%s%s (%s%s%s)\n",
620                strna(link),
621                strna(network),
622                strna(t),
623                on_color_operational, strna(operational_state), off_color_operational,
624                on_color_setup, strna(setup_state), off_color_setup);
625
626         if (path)
627                 printf("            Path: %s\n", path);
628         if (driver)
629                 printf("          Driver: %s\n", driver);
630         if (vendor)
631                 printf("          Vendor: %s\n", vendor);
632         if (model)
633                 printf("           Model: %s\n", model);
634
635         if (have_mac) {
636                 _cleanup_free_ char *description = NULL;
637                 char ea[ETHER_ADDR_TO_STRING_MAX];
638
639                 ieee_oui(hwdb, &e, &description);
640
641                 if (description)
642                         printf("      HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
643                 else
644                         printf("      HW Address: %s\n", ether_addr_to_string(&e, ea));
645         }
646
647         if (mtu > 0)
648                 printf("             MTU: %u\n", mtu);
649
650         dump_addresses(rtnl, "         Address: ", ifindex);
651         dump_gateways(rtnl, hwdb, "         Gateway: ", ifindex);
652
653         if (!strv_isempty(dns))
654                 dump_list("             DNS: ", dns);
655         if (!strv_isempty(domains))
656                 dump_list("          Domain: ", domains);
657         if (!strv_isempty(ntp))
658                 dump_list("             NTP: ", ntp);
659
660         if (!strv_isempty(carrier_bound_to))
661                 dump_list("Carrier Bound To: ", carrier_bound_to);
662
663         if (!strv_isempty(carrier_bound_by))
664                 dump_list("Carrier Bound By: ", carrier_bound_by);
665
666         return 0;
667 }
668
669 static int link_status(int argc, char *argv[], void *userdata) {
670         _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
671         _cleanup_udev_unref_ struct udev *udev = NULL;
672         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
673         char **name;
674         int r;
675
676         r = sd_rtnl_open(&rtnl, 0);
677         if (r < 0)
678                 return log_error_errno(r, "Failed to connect to netlink: %m");
679
680         udev = udev_new();
681         if (!udev)
682                 return log_error_errno(errno, "Failed to connect to udev: %m");
683
684         r = sd_hwdb_new(&hwdb);
685         if (r < 0)
686                 log_debug_errno(r, "Failed to open hardware database: %m");
687
688         if (argc <= 1 && !arg_all) {
689                 _cleanup_free_ char *operational_state = NULL;
690                 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
691                 const char *on_color_operational, *off_color_operational;
692
693                 sd_network_get_operational_state(&operational_state);
694                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
695
696                 printf("%s%s%s      State: %s%s%s\n",
697                        on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
698                        on_color_operational, strna(operational_state), off_color_operational);
699
700                 dump_addresses(rtnl, "     Address: ", 0);
701                 dump_gateways(rtnl, hwdb, "     Gateway: ", 0);
702
703                 sd_network_get_dns(&dns);
704                 if (!strv_isempty(dns))
705                         dump_list("         DNS: ", dns);
706
707                 sd_network_get_domains(&domains);
708                 if (!strv_isempty(domains))
709                         dump_list("      Domain: ", domains);
710
711                 sd_network_get_ntp(&ntp);
712                 if (!strv_isempty(ntp))
713                         dump_list("         NTP: ", ntp);
714
715                 return 0;
716         }
717
718         pager_open_if_enabled();
719
720         if (arg_all) {
721                 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
722                 _cleanup_free_ LinkInfo *links = NULL;
723                 int c, i;
724
725                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
726                 if (r < 0)
727                         return rtnl_log_create_error(r);
728
729                 r = sd_rtnl_message_request_dump(req, true);
730                 if (r < 0)
731                         return rtnl_log_create_error(r);
732
733                 r = sd_rtnl_call(rtnl, req, 0, &reply);
734                 if (r < 0)
735                         return log_error_errno(r, "Failed to enumerate links: %m");
736
737                 c = decode_and_sort_links(reply, &links);
738                 if (c < 0)
739                         return rtnl_log_parse_error(c);
740
741                 for (i = 0; i < c; i++) {
742                         if (i > 0)
743                                 fputc('\n', stdout);
744
745                         link_status_one(rtnl, udev, hwdb, links[i].name);
746                 }
747         } else {
748                 STRV_FOREACH(name, argv + 1) {
749                         if (name != argv + 1)
750                                 fputc('\n', stdout);
751
752                         link_status_one(rtnl, udev, hwdb, *name);
753                 }
754         }
755
756         return 0;
757 }
758
759 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
760 LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
761
762 static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
763         [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
764         [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
765         [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
766         [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
767         [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
768         [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
769         [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
770         [LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
771         [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
772         [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
773         [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
774         [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
775 };
776
777 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
778
779 static char *lldp_system_caps(uint16_t cap) {
780         _cleanup_free_ char *s = NULL, *t = NULL;
781         char *capability;
782
783         t = strdup("[ ");
784         if (!t)
785                 return NULL;
786
787         if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
788                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
789                 if (!s)
790                         return NULL;
791
792                 free(t);
793                 t = s;
794         }
795
796         if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
797                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
798                 if (!s)
799                         return NULL;
800
801                 free(t);
802                 t = s;
803         }
804
805         if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
806                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
807                 if (!s)
808                         return NULL;
809
810                 free(t);
811                 t = s;
812         }
813
814         if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
815                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
816                 if (!s)
817                         return NULL;
818
819                 free(t);
820                 t = s;
821         }
822
823         if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
824                 s =  strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
825                 if (!s)
826                         return NULL;
827
828                 free(t);
829                 t = s;
830         }
831
832         if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
833                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
834                 if (!s)
835                         return NULL;
836
837                 free(t);
838                 t = s;
839         }
840
841         if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
842                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
843                 if (!s)
844                         return NULL;
845
846                 free(t);
847                 t = s;
848         }
849
850         if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
851                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
852                 if (!s)
853                         return NULL;
854
855                 free(t);
856                 t = s;
857         }
858
859         if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
860                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
861                 if (!s)
862                         return NULL;
863
864                 free(t);
865                 t = s;
866         }
867
868         if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
869                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
870                 if (!s)
871                         return NULL;
872
873                 free(t);
874                 t = s;
875         }
876
877         if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
878                 s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
879                 if (!s)
880                         return NULL;
881
882                 free(t);
883         }
884
885         if (!s) {
886                 s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
887                 if (!s)
888                         return NULL;
889
890                 free(t);
891         }
892
893         t = strappend(s, "]");
894         if (!t)
895                 return NULL;
896
897         free(s);
898         capability = t;
899
900         s = NULL;
901         t = NULL;
902
903         return capability;
904 }
905
906 static int link_lldp_status(int argc, char *argv[], void *userdata) {
907         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
908         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
909         _cleanup_free_ LinkInfo *links = NULL;
910         const char *state, *word;
911
912         double ttl = -1;
913         uint32_t capability;
914         int i, r, c, j;
915         size_t ll;
916         char **s;
917
918         pager_open_if_enabled();
919
920         r = sd_rtnl_open(&rtnl, 0);
921         if (r < 0)
922                 return log_error_errno(r, "Failed to connect to netlink: %m");
923
924         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
925         if (r < 0)
926                 return rtnl_log_create_error(r);
927
928         r = sd_rtnl_message_request_dump(req, true);
929         if (r < 0)
930                 return rtnl_log_create_error(r);
931
932         r = sd_rtnl_call(rtnl, req, 0, &reply);
933         if (r < 0)
934                 return log_error_errno(r, "Failed to enumerate links: %m");
935
936         c = decode_and_sort_links(reply, &links);
937         if (c < 0)
938                 return rtnl_log_parse_error(c);
939
940         if (arg_legend)
941                 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
942
943         for (i = j = 0; i < c; i++) {
944                 _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
945                 _cleanup_strv_free_ char **l = NULL;
946
947                 r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
948                 if (r < 0)
949                         continue;
950
951                 l = strv_split_newlines(lldp);
952                 if (!l)
953                         return -ENOMEM;
954
955                 STRV_FOREACH(s, l) {
956                         FOREACH_WORD_QUOTED(word, ll, *s, state) {
957                                 _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
958
959                                 t = strndup(word, ll);
960                                 if (!t)
961                                         return -ENOMEM;
962
963                                 r = split_pair(t, "=", &a, &b);
964                                 if (r < 0)
965                                         continue;
966
967                                 if (streq(a, "_Chassis")) {
968                                         r = free_and_strdup(&chassis, b);
969                                         if (r < 0)
970                                                 return r;
971
972                                 } else if (streq(a, "_Port")) {
973                                         r = free_and_strdup(&port, b);
974                                         if (r < 0)
975                                                 return r;
976
977                                 } else if (streq(a, "_TTL")) {
978                                         long long unsigned x;
979                                         usec_t time;
980
981                                         r = safe_atollu(b, &x);
982                                         if (r < 0 || (usec_t) x != x)
983                                                 return log_warning_errno(r < 0 ? r : ERANGE,
984                                                                          "Failed to parse TTL \"%s\": %m", b);
985
986                                         time = now(CLOCK_BOOTTIME);
987                                         if (x < time)
988                                                 continue;
989
990                                         ttl = (double) (x - time) / USEC_PER_SEC;
991
992                                 } else if (streq(a, "_CAP")) {
993                                         sscanf(b, "%x", &capability);
994
995                                         cap = lldp_system_caps(capability);
996                                 }
997
998                         }
999
1000                         if (ttl >= 0) {
1001                                 printf("%10s %24s %16s %16f %16s\n",
1002                                        links[i].name,
1003                                        strna(chassis), strna(port),
1004                                        ttl, cap);
1005                                 j++;
1006                         }
1007                 }
1008         }
1009
1010         if (arg_legend) {
1011                 printf("\nCapability Codes:\n"
1012                        "(O) - Other, (P) - Repeater,  (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1013                        "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1014                        "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1015
1016                 printf("Total entries displayed: %d\n", j);
1017         }
1018
1019         return 0;
1020 }
1021
1022 static void help(void) {
1023         printf("%s [OPTIONS...]\n\n"
1024                "Query and control the networking subsystem.\n\n"
1025                "  -h --help             Show this help\n"
1026                "     --version          Show package version\n"
1027                "     --no-pager         Do not pipe output into a pager\n"
1028                "     --no-legend        Do not show the headers and footers\n"
1029                "  -a --all              Show status for all links\n\n"
1030                "Commands:\n"
1031                "  list                  List links\n"
1032                "  status [LINK...]      Show link status\n"
1033                "  lldp                  Show lldp information\n"
1034                , program_invocation_short_name);
1035 }
1036
1037 static int parse_argv(int argc, char *argv[]) {
1038
1039         enum {
1040                 ARG_VERSION = 0x100,
1041                 ARG_NO_PAGER,
1042                 ARG_NO_LEGEND,
1043         };
1044
1045         static const struct option options[] = {
1046                 { "help",      no_argument,       NULL, 'h'           },
1047                 { "version",   no_argument,       NULL, ARG_VERSION   },
1048                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
1049                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
1050                 { "all",       no_argument,       NULL, 'a'           },
1051                 {}
1052         };
1053
1054         int c;
1055
1056         assert(argc >= 0);
1057         assert(argv);
1058
1059         while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
1060
1061                 switch (c) {
1062
1063                 case 'h':
1064                         help();
1065                         return 0;
1066
1067                 case ARG_VERSION:
1068                         puts(PACKAGE_STRING);
1069                         puts(SYSTEMD_FEATURES);
1070                         return 0;
1071
1072                 case ARG_NO_PAGER:
1073                         arg_no_pager = true;
1074                         break;
1075
1076                 case ARG_NO_LEGEND:
1077                         arg_legend = false;
1078                         break;
1079
1080                 case 'a':
1081                         arg_all = true;
1082                         break;
1083
1084                 case '?':
1085                         return -EINVAL;
1086
1087                 default:
1088                         assert_not_reached("Unhandled option");
1089                 }
1090         }
1091
1092         return 1;
1093 }
1094
1095 static int networkctl_main(int argc, char *argv[]) {
1096         const Verb verbs[] = {
1097                 { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
1098                 { "status", 1, VERB_ANY, 0, link_status },
1099                 { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
1100                 {}
1101         };
1102
1103         return dispatch_verb(argc, argv, verbs, NULL);
1104 }
1105
1106 int main(int argc, char* argv[]) {
1107         int r;
1108
1109         log_parse_environment();
1110         log_open();
1111
1112         r = parse_argv(argc, argv);
1113         if (r <= 0)
1114                 goto finish;
1115
1116         r = networkctl_main(argc, argv);
1117
1118 finish:
1119         pager_close();
1120
1121         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1122 }