1 /* 2 * netifd - network interface daemon 3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 7 * as published by the Free Software Foundation 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 #include <string.h> 15 #include <stdlib.h> 16 #include <stdio.h> 17 18 #include "netifd.h" 19 #include "device.h" 20 #include "interface.h" 21 22 static struct avl_tree aliases; 23 24 struct alias_device { 25 struct avl_node avl; 26 struct device dev; 27 struct device_user dep; 28 struct device_user new_dep; 29 bool update; 30 char name[]; 31 }; 32 33 static void alias_set_device(struct alias_device *alias, struct device *dev) 34 { 35 if (dev == alias->dep.dev) { 36 if (alias->update) { 37 device_remove_user(&alias->new_dep); 38 alias->update = false; 39 if (dev) 40 device_set_present(&alias->dev, true); 41 } 42 return; 43 } 44 45 device_set_present(&alias->dev, false); 46 device_remove_user(&alias->new_dep); 47 if (alias->dev.active) { 48 if (dev) 49 device_add_user(&alias->new_dep, dev); 50 51 alias->update = true; 52 return; 53 } 54 55 alias->update = false; 56 device_remove_user(&alias->dep); 57 alias->dev.hidden = !dev; 58 if (dev) { 59 device_set_ifindex(&alias->dev, dev->ifindex); 60 device_set_ifname(&alias->dev, dev->ifname); 61 device_add_user(&alias->dep, dev); 62 } else { 63 device_set_ifname(&alias->dev, ""); 64 device_set_link(&alias->dev, false); 65 } 66 } 67 68 static int 69 alias_device_set_state(struct device *dev, bool state) 70 { 71 struct alias_device *alias; 72 73 alias = container_of(dev, struct alias_device, dev); 74 if (!alias->dep.dev) 75 return -1; 76 77 if (state) 78 return device_claim(&alias->dep); 79 80 device_release(&alias->dep); 81 if (alias->update) 82 alias_set_device(alias, alias->new_dep.dev); 83 84 return 0; 85 } 86 87 static void alias_device_cb(struct device_user *dep, enum device_event ev) 88 { 89 struct alias_device *alias; 90 91 alias = container_of(dep, struct alias_device, dep); 92 switch (ev) { 93 case DEV_EVENT_ADD: 94 device_set_present(&alias->dev, true); 95 break; 96 case DEV_EVENT_REMOVE: 97 device_set_present(&alias->dev, false); 98 break; 99 case DEV_EVENT_LINK_UP: 100 device_set_link(&alias->dev, true); 101 break; 102 case DEV_EVENT_LINK_DOWN: 103 device_set_link(&alias->dev, false); 104 break; 105 case DEV_EVENT_UPDATE_IFINDEX: 106 device_set_ifindex(&alias->dev, dep->dev->ifindex); 107 break; 108 default: 109 device_broadcast_event(&alias->dev, ev); 110 break; 111 } 112 } 113 114 static struct device * 115 alias_device_create(const char *name, struct device_type *devtype, 116 struct blob_attr *attr) 117 { 118 struct alias_device *alias; 119 120 alias = calloc(1, sizeof(*alias) + strlen(name) + 1); 121 if (!alias) 122 return NULL; 123 124 strcpy(alias->name, name); 125 alias->dev.set_state = alias_device_set_state; 126 alias->dev.hidden = true; 127 if (device_init_virtual(&alias->dev, devtype, NULL) < 0) { 128 free(alias); 129 return NULL; 130 } 131 132 alias->avl.key = alias->name; 133 avl_insert(&aliases, &alias->avl); 134 alias->dep.alias = true; 135 alias->dep.cb = alias_device_cb; 136 device_check_state(&alias->dev); 137 138 return &alias->dev; 139 } 140 141 static void alias_device_free(struct device *dev) 142 { 143 struct alias_device *alias; 144 145 alias = container_of(dev, struct alias_device, dev); 146 device_remove_user(&alias->new_dep); 147 device_remove_user(&alias->dep); 148 avl_delete(&aliases, &alias->avl); 149 free(alias); 150 } 151 152 static int alias_check_state(struct device *dev) 153 { 154 struct alias_device *alias; 155 struct interface *iface; 156 struct device *ndev = NULL; 157 158 alias = container_of(dev, struct alias_device, dev); 159 160 iface = vlist_find(&interfaces, alias->name, iface, node); 161 if (iface && iface->state == IFS_UP) 162 ndev = iface->l3_dev.dev; 163 164 alias_set_device(alias, ndev); 165 166 return 0; 167 } 168 169 static struct device_type alias_device_type = { 170 .name = "Network alias", 171 .create = alias_device_create, 172 .free = alias_device_free, 173 .check_state = alias_check_state, 174 }; 175 176 void 177 alias_notify_device(const char *name, struct device *dev) 178 { 179 struct alias_device *alias; 180 181 alias = avl_find_element(&aliases, name, alias, avl); 182 if (alias) 183 alias_set_device(alias, dev); 184 } 185 186 struct device * 187 device_alias_get(const char *name) 188 { 189 struct alias_device *alias; 190 191 alias = avl_find_element(&aliases, name, alias, avl); 192 if (alias) 193 return &alias->dev; 194 195 return alias_device_create(name, &alias_device_type, NULL); 196 } 197 198 static void __init alias_init(void) 199 { 200 avl_init(&aliases, avl_strcmp, false, NULL); 201 } 202
This page was automatically generated by LXR 0.3.1. • OpenWrt