| File: | .build-ci/../discoverd/src/netif.c |
| Warning: | line 42, column 2 Use of memory after it is released |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||||
| 2 | /* | ||||
| 3 | * This file is part of nvme-cli. | ||||
| 4 | * Copyright (c) 2026 Dell Technologies Inc. or its subsidiaries. | ||||
| 5 | * | ||||
| 6 | * Authors: Martin Belanger <martin.belanger@dell.com> | ||||
| 7 | */ | ||||
| 8 | |||||
| 9 | #include <errno(*__errno_location ()).h> | ||||
| 10 | #include <net/if.h> | ||||
| 11 | #include <stdlib.h> | ||||
| 12 | #include <systemd/sd-device.h> | ||||
| 13 | |||||
| 14 | #include <ccan/list/list.h> | ||||
| 15 | |||||
| 16 | #include <daemon-util/log.h> | ||||
| 17 | |||||
| 18 | #include "netif.h" | ||||
| 19 | |||||
| 20 | struct tracked_iface { | ||||
| 21 | struct list_node entry; | ||||
| 22 | int ifindex; | ||||
| 23 | }; | ||||
| 24 | |||||
| 25 | struct netif_ctx { | ||||
| 26 | struct netif_callbacks callbacks; | ||||
| 27 | void *user_data; | ||||
| 28 | sd_device_monitor *monitor; | ||||
| 29 | struct list_head tracked; // candidates reported with iface_add | ||||
| 30 | }; | ||||
| 31 | |||||
| 32 | bool_Bool netif_is_candidate(unsigned int flags) | ||||
| 33 | { | ||||
| 34 | return (flags & IFF_UPIFF_UP) && (flags & IFF_MULTICASTIFF_MULTICAST) && | ||||
| 35 | !(flags & IFF_LOOPBACKIFF_LOOPBACK); | ||||
| 36 | } | ||||
| 37 | |||||
| 38 | static struct tracked_iface *tracked_find(struct netif_ctx *nctx, int ifindex) | ||||
| 39 | { | ||||
| 40 | struct tracked_iface *e; | ||||
| 41 | |||||
| 42 | list_for_each(&nctx->tracked, e, entry)for ((e) = list_node_to_off_(((void)"../discoverd/src/netif.c" ":" "42", (&nctx->tracked))->n.next, (((__builtin_offsetof (typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0))))); list_node_from_off_((void *)(e), (((__builtin_offsetof (typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0))))) != &((&nctx->tracked))->n; (e) = list_node_to_off_ (list_node_from_off_((void *)(e), (((__builtin_offsetof(typeof (*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0)))))->next, (((__builtin_offsetof(typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0)))))) { | ||||
| |||||
| 43 | if (e->ifindex == ifindex) | ||||
| 44 | return e; | ||||
| 45 | } | ||||
| 46 | |||||
| 47 | return NULL((void*)0); | ||||
| 48 | } | ||||
| 49 | |||||
| 50 | static unsigned int device_flags(sd_device *dev) | ||||
| 51 | { | ||||
| 52 | const char *val = NULL((void*)0); | ||||
| 53 | |||||
| 54 | sd_device_get_sysattr_value(dev, "flags", &val); | ||||
| 55 | |||||
| 56 | return val ? (unsigned int)strtoul(val, NULL((void*)0), 0) : 0; | ||||
| 57 | } | ||||
| 58 | |||||
| 59 | /* | ||||
| 60 | * Bring the tracked state of one interface in line with @candidate. This | ||||
| 61 | * is the only place that calls iface_add and iface_remove. | ||||
| 62 | */ | ||||
| 63 | static void reconcile(struct netif_ctx *nctx, int ifindex, const char *ifname, | ||||
| 64 | bool_Bool candidate) | ||||
| 65 | { | ||||
| 66 | struct tracked_iface *e = tracked_find(nctx, ifindex); | ||||
| 67 | |||||
| 68 | if (candidate
| ||||
| 69 | e = calloc(1, sizeof(*e)); | ||||
| 70 | if (!e) { | ||||
| 71 | log_err("%s: out of memory", ifname)dmn_log_msg(DMN_LOG_ERR, "%s: out of memory", ifname); | ||||
| 72 | return; | ||||
| 73 | } | ||||
| 74 | e->ifindex = ifindex; | ||||
| 75 | list_add(&nctx->tracked, &e->entry)list_add_(&nctx->tracked, &e->entry, "../discoverd/src/netif.c" ":" "75"); | ||||
| 76 | if (nctx->callbacks.iface_add) | ||||
| 77 | nctx->callbacks.iface_add(ifindex, ifname, | ||||
| 78 | nctx->user_data); | ||||
| 79 | } else if (!candidate
| ||||
| 80 | list_del(&e->entry)list_del_(&e->entry, "../discoverd/src/netif.c" ":" "80" ); | ||||
| 81 | free(e); | ||||
| 82 | if (nctx->callbacks.iface_remove) | ||||
| 83 | nctx->callbacks.iface_remove(ifindex, ifname, | ||||
| 84 | nctx->user_data); | ||||
| 85 | } | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | static void reconcile_device(struct netif_ctx *nctx, sd_device *dev, | ||||
| 89 | bool_Bool removed) | ||||
| 90 | { | ||||
| 91 | const char *ifname = NULL((void*)0); | ||||
| 92 | int ifindex; | ||||
| 93 | |||||
| 94 | if (sd_device_get_sysname(dev, &ifname) < 0) | ||||
| 95 | return; | ||||
| 96 | if (sd_device_get_ifindex(dev, &ifindex) < 0) | ||||
| 97 | return; | ||||
| 98 | |||||
| 99 | reconcile(nctx, ifindex, ifname, | ||||
| 100 | !removed
| ||||
| 101 | } | ||||
| 102 | |||||
| 103 | static int net_monitor_handler( | ||||
| 104 | sd_device_monitor *monitor __attribute__((unused)), | ||||
| 105 | sd_device *dev, void *user_data) | ||||
| 106 | { | ||||
| 107 | sd_device_action_t action; | ||||
| 108 | |||||
| 109 | if (sd_device_get_action(dev, &action) < 0) | ||||
| 110 | return 0; | ||||
| 111 | |||||
| 112 | reconcile_device(user_data, dev, action == SD_DEVICE_REMOVE); | ||||
| 113 | |||||
| 114 | return 0; | ||||
| 115 | } | ||||
| 116 | |||||
| 117 | static int enumerate_existing(struct netif_ctx *nctx) | ||||
| 118 | { | ||||
| 119 | sd_device_enumerator *en = NULL((void*)0); | ||||
| 120 | sd_device *dev; | ||||
| 121 | int r; | ||||
| 122 | |||||
| 123 | r = sd_device_enumerator_new(&en); | ||||
| 124 | if (r < 0) | ||||
| 125 | return r; | ||||
| 126 | r = sd_device_enumerator_add_match_subsystem(en, "net", true1); | ||||
| 127 | if (r < 0) | ||||
| 128 | goto out; | ||||
| 129 | |||||
| 130 | for (dev = sd_device_enumerator_get_device_first(en); dev; | ||||
| 131 | dev = sd_device_enumerator_get_device_next(en)) | ||||
| 132 | reconcile_device(nctx, dev, false0); | ||||
| 133 | out: | ||||
| 134 | sd_device_enumerator_unref(en); | ||||
| 135 | |||||
| 136 | return r; | ||||
| 137 | } | ||||
| 138 | |||||
| 139 | int netif_start(sd_event *event, const struct netif_callbacks *callbacks, | ||||
| 140 | void *user_data, struct netif_ctx **nctxp) | ||||
| 141 | { | ||||
| 142 | struct netif_ctx *nctx; | ||||
| 143 | int r; | ||||
| 144 | |||||
| 145 | nctx = calloc(1, sizeof(*nctx)); | ||||
| 146 | if (!nctx) | ||||
| |||||
| 147 | return -ENOMEM12; | ||||
| 148 | |||||
| 149 | nctx->callbacks = *callbacks; | ||||
| 150 | nctx->user_data = user_data; | ||||
| 151 | list_head_init(&nctx->tracked); | ||||
| 152 | |||||
| 153 | r = sd_device_monitor_new(&nctx->monitor); | ||||
| 154 | if (r < 0) | ||||
| 155 | goto err; | ||||
| 156 | r = sd_device_monitor_filter_add_match_subsystem_devtype( | ||||
| 157 | nctx->monitor, "net", NULL((void*)0)); | ||||
| 158 | if (r < 0) | ||||
| 159 | goto err; | ||||
| 160 | r = sd_device_monitor_attach_event(nctx->monitor, event); | ||||
| 161 | if (r < 0) | ||||
| 162 | goto err; | ||||
| 163 | r = sd_device_monitor_start(nctx->monitor, net_monitor_handler, nctx); | ||||
| 164 | if (r < 0) | ||||
| 165 | goto err; | ||||
| 166 | |||||
| 167 | r = enumerate_existing(nctx); | ||||
| 168 | if (r < 0) | ||||
| 169 | goto err; | ||||
| 170 | |||||
| 171 | *nctxp = nctx; | ||||
| 172 | |||||
| 173 | return 0; | ||||
| 174 | err: | ||||
| 175 | netif_stop(nctx); | ||||
| 176 | |||||
| 177 | return r; | ||||
| 178 | } | ||||
| 179 | |||||
| 180 | void netif_stop(struct netif_ctx *nctx) | ||||
| 181 | { | ||||
| 182 | struct tracked_iface *e, *next; | ||||
| 183 | |||||
| 184 | if (!nctx) | ||||
| 185 | return; | ||||
| 186 | |||||
| 187 | list_for_each_safe(&nctx->tracked, e, next, entry)for ((e) = list_node_to_off_(((void)"../discoverd/src/netif.c" ":" "187", (&nctx->tracked))->n.next, (((__builtin_offsetof (typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0))))), (next) = list_node_to_off_(list_node_from_off_((e) , (((__builtin_offsetof(typeof(*e), entry) + ((typeof(e->entry ) *)0 != (struct list_node *)0)))))->next, (((__builtin_offsetof (typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0))))); list_node_from_off_((e), (((__builtin_offsetof(typeof (*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0))))) != &((&nctx->tracked))->n; (e) = (next ), (next) = list_node_to_off_(list_node_from_off_((e), (((__builtin_offsetof (typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0)))))->next, (((__builtin_offsetof(typeof(*e), entry) + ((typeof(e->entry) *)0 != (struct list_node *)0)))))) | ||||
| 188 | free(e); | ||||
| 189 | |||||
| 190 | sd_device_monitor_unref(nctx->monitor); | ||||
| 191 | free(nctx); | ||||
| 192 | } |