예제 #1
0
파일: wireless.c 프로젝트: gsanso/wicked
/*
 * Callback from wpa_supplicant client whenever the association state changes
 * in a significant way.
 */
void
ni_wireless_association_changed(unsigned int ifindex, ni_wireless_assoc_state_t new_state)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev;
	ni_wireless_t *wlan;

	if (!(dev = ni_netdev_by_index(nc, ifindex)))
		return;

	if (!(wlan = dev->wireless))
		return;

	if (new_state == wlan->assoc.state)
		return;

	wlan->assoc.state = new_state;
	if (new_state == NI_WIRELESS_ESTABLISHED)
		__ni_netdev_event(nc, dev, NI_EVENT_LINK_ASSOCIATED);

	/* We keep track of when we were last changing to or
	 * from fully authenticated state.
	 * We use this to decide when to give up and announce
	 * that we've lost the network - see the timer handling
	 * code above.
	 */
	ni_wireless_update_association_timer(dev);
}
예제 #2
0
파일: wireless.c 프로젝트: gsanso/wicked
static void
__ni_wireless_association_timeout(void *ptr, const ni_timer_t *timer)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev = ptr;
	ni_wireless_t *wlan = dev->wireless;

	if (wlan->assoc.timer != timer)
		return;

	ni_debug_wireless("%s: association timed out", dev->name);
	wlan->assoc.timer = NULL;

	__ni_netdev_event(nc, dev, NI_EVENT_LINK_DOWN);
	__ni_netdev_event(nc, dev, NI_EVENT_LINK_ASSOCIATION_LOST);

	ni_wireless_disconnect(dev);
}
예제 #3
0
파일: ifevent.c 프로젝트: nirmoy/wicked
/*
 * Process NEWLINK event
 */
int
__ni_rtevent_newlink(ni_netconfig_t *nc, const struct sockaddr_nl *nladdr, struct nlmsghdr *h)
{
	char namebuf[IF_NAMESIZE+1] = {'\0'};
	ni_netdev_t *dev, *old;
	struct ifinfomsg *ifi;
	struct nlattr *nla;
	char *ifname = NULL;
	int old_flags = 0;

	if (!(ifi = ni_rtnl_ifinfomsg(h, RTM_NEWLINK)))
		return -1;

	if (ifi->ifi_family == AF_BRIDGE)
		return 0;

	old = ni_netdev_by_index(nc, ifi->ifi_index);
	ifname = if_indextoname(ifi->ifi_index, namebuf);
	if (!ifname) {
		/*
		 * device (index) does not exists any more;
		 * process deletion/cleanup of the device.
		 */
		if (old) {
			old_flags = old->link.ifflags;
			old->link.ifflags = 0;
			old->deleted = 1;

			__ni_netdev_process_events(nc, old, old_flags);
			ni_client_state_drop(old->link.ifindex);
			ni_netconfig_device_remove(nc, old);
		}
		return 0;
	}

	if (old) {
		if (!ni_string_eq(old->name, ifname)) {
			ni_debug_events("%s[%u]: device renamed to %s",
					old->name, old->link.ifindex, ifname);
			ni_string_dup(&old->name, ifname);
			__ni_netdev_event(nc, old, NI_EVENT_DEVICE_RENAME);
		}
		dev = old;
		old_flags = old->link.ifflags;
	} else {
		if (!(dev = ni_netdev_new(ifname, ifi->ifi_index))) {
			ni_warn("%s[%u]: unable to allocate memory for device",
					ifname, ifi->ifi_index);
			return -1;
		}
		dev->created = 1;
		ni_netconfig_device_append(nc, dev);
	}

	if (__ni_netdev_process_newlink(dev, h, ifi, nc) < 0) {
		ni_error("Problem parsing RTM_NEWLINK message for %s", ifname);
		return -1;
	}

	if ((ifname = dev->name)) {
		ni_netdev_t *conflict;

		conflict = ni_netdev_by_name(nc, ifname);
		if (conflict && conflict->link.ifindex != (unsigned int)ifi->ifi_index) {
			/*
			 * As the events often provide an already obsolete name [2 events,
			 * we process 1st with next in read buffer], we are reading the
			 * current dev->name in advance (above).
			 *
			 * On a rename like eth0->rename1->eth1, eth1->rename2->eth0, the
			 * current dev->name is already eth1 at processing time of eth0
			 * to rename1 event. This sometimes causes that we find eth1 in
			 * our device list [eth1 -> rename2 event in the read buffer].
			 *
			 * Just update the name of the conflicting device in advance too
			 * and when the interface does not exist any more, emit events.
			 */
			char *current = if_indextoname(conflict->link.ifindex, namebuf);
			if (current) {
				ni_string_dup(&conflict->name, current);
				__ni_netdev_event(nc, conflict, NI_EVENT_DEVICE_RENAME);
			} else {
				unsigned int ifflags = conflict->link.ifflags;
				conflict->link.ifflags = 0;
				conflict->deleted = 1;

				__ni_netdev_process_events(nc, conflict, ifflags);
				ni_client_state_drop(conflict->link.ifindex);
				ni_netconfig_device_remove(nc, conflict);
			}
		}
	}

	__ni_netdev_process_events(nc, dev, old_flags);

	if ((nla = nlmsg_find_attr(h, sizeof(*ifi), IFLA_WIRELESS)) != NULL)
		__ni_wireless_link_event(nc, dev, nla_data(nla), nla_len(nla));

	return 0;
}
예제 #4
0
파일: ifevent.c 프로젝트: nirmoy/wicked
/*
 * Process device state change events
 */
void
__ni_netdev_process_events(ni_netconfig_t *nc, ni_netdev_t *dev, unsigned int old_flags)
{
	static struct flag_transition {
		unsigned int	flag;
		unsigned int	event_up;
		unsigned int	event_down;
	} *edge, flag_transitions[] = {
		{ NI_IFF_DEVICE_READY,	NI_EVENT_DEVICE_READY,	0			},
		{ NI_IFF_DEVICE_UP,	NI_EVENT_DEVICE_UP,	NI_EVENT_DEVICE_DOWN	},
		{ NI_IFF_LINK_UP,	NI_EVENT_LINK_UP,	NI_EVENT_LINK_DOWN	},
		{ NI_IFF_NETWORK_UP,	NI_EVENT_NETWORK_UP,	NI_EVENT_NETWORK_DOWN	},
	};
	size_t flags = sizeof(flag_transitions)/sizeof(flag_transitions[0]);
	unsigned int i, new_flags, flags_changed;
	ni_uint_array_t events = NI_UINT_ARRAY_INIT;

	new_flags = dev->link.ifflags;
	flags_changed = old_flags ^ new_flags;

	if (dev->created) {
		dev->created = 0;
		ni_uint_array_append(&events, NI_EVENT_DEVICE_CREATE);
	}

	/* transition up */
	for (i = 0; i < flags; ++i) {
		edge = &flag_transitions[i];
		if ((flags_changed & edge->flag) == 0)
			continue;
		if (new_flags & edge->flag) {
			ni_uint_array_append(&events, edge->event_up);
		}
	}

	/* transition down */
	for (i = flags; i-- > 0;  ) {
		edge = &flag_transitions[i];
		if ((flags_changed & edge->flag) == 0)
			continue;
		if (old_flags & edge->flag) {
			if (dev->ipv6 && edge->event_down == NI_EVENT_DEVICE_DOWN)
				ni_ipv6_ra_info_flush(&dev->ipv6->radv);

			if (edge->event_down)
				ni_uint_array_append(&events, edge->event_down);
		}
	}

	if (dev->deleted) {
		dev->deleted = 0;
		ni_uint_array_append(&events, NI_EVENT_DEVICE_DELETE);
	} else
	if (events.count == 0) {
		__ni_netdev_event(nc, dev, NI_EVENT_DEVICE_CHANGE);
	}

	for (i = 0; i < events.count; ++i) {
		__ni_netdev_event(nc, dev, events.data[i]);
	}
	ni_uint_array_destroy(&events);
}
예제 #5
0
파일: wireless.c 프로젝트: gsanso/wicked
/*
 * Initiate a network scan
 */
int
__ni_wireless_do_scan(ni_netdev_t *dev)
{
	ni_wpa_interface_t *wpa_dev;
	ni_wireless_t *wlan;
	ni_wireless_scan_t *scan;
	time_t now;

	wlan = dev->wireless;
	if ((scan = wlan->scan) == NULL) {
		ni_error("%s: no wireless scan handle?!", __func__);
		return -1;
	}

	/* (Re-)arm the scan timer */
	__ni_wireless_scan_timer_arm(scan, dev, scan->interval);

	/* If the device is down, we cannot scan */
	if (!ni_netdev_device_is_up(dev))
		return 0;

	if (ni_rfkill_disabled(NI_RFKILL_TYPE_WIRELESS))
		return -NI_ERROR_RADIO_DISABLED;
	if (!(wpa_dev = ni_wireless_bind_supplicant(dev)))
		return -1;

	wlan->capabilities = wpa_dev->capabilities;

	/* We currently don't have a reasonable way to call back
	 * to a higher level from the depths of the wpa-supplicant
	 * code. Thus we have to result to polling here :-(
	 */
	if (ni_wpa_interface_scan_in_progress(wpa_dev)) {
		__ni_wireless_scan_timer_arm(scan, dev, 1);
		return 0;
	}

	/* Retrieve whatever is there. */
	if (ni_wpa_interface_retrieve_scan(wpa_dev, scan)) {
		ni_netconfig_t *nc = ni_global_state_handle(0);

		ni_debug_wireless("%s: list of networks changed", dev->name);
		__ni_netdev_event(nc, dev, NI_EVENT_LINK_SCAN_UPDATED);
	}

	/* If we haven't seen a scan in a long time, request one. */
	now = time(NULL);
	if (scan->timestamp + scan->interval < now) {
		/* We can do this only if the device is up */
		if (dev->link.ifflags & NI_IFF_DEVICE_UP) {
			if (scan->timestamp)
				ni_debug_wireless("%s: requesting wireless scan (last scan was %u seconds ago)",
						dev->name, (unsigned int) (now - scan->timestamp));
			else
				ni_debug_wireless("%s: requesting wireless scan", dev->name);
			ni_wpa_interface_request_scan(wpa_dev, scan);
		}
	}

	return 0;
}