コード例 #1
0
void
handle_carrier(int carrier, int flags, const char *ifname)
{
	struct interface *ifp;

	if (!(options & DHCPCD_LINK))
		return;
	ifp = find_interface(ifname);
	if (ifp == NULL) {
		handle_interface(1, ifname);
		return;
	}
	if (!(ifp->options->options & DHCPCD_LINK))
		return;

	if (carrier == LINK_UNKNOWN)
		carrier = carrier_status(ifp); /* will set ifp->flags */
	else
		ifp->flags = flags;

	if (carrier == LINK_UNKNOWN)
		syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
	/* IFF_RUNNING is checked, if needed, earlier and is OS dependant */
	else if (carrier == LINK_DOWN || (ifp->flags & IFF_UP) == 0) {
		if (ifp->carrier != LINK_DOWN) {
			if (ifp->carrier == LINK_UP)
				syslog(LOG_INFO, "%s: carrier lost", ifp->name);
			ifp->carrier = LINK_DOWN;
			dhcp_close(ifp);
			dhcp6_drop(ifp, "EXPIRE6");
			ipv6rs_drop(ifp);
			/* Don't blindly delete our knowledge of LL addresses.
			 * We need to listen to what the kernel does with
			 * them as some OS's will remove, mark tentative or
			 * do nothing. */
			ipv6_free_ll_callbacks(ifp);
			dhcp_drop(ifp, "NOCARRIER");
		}
	} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
		if (ifp->carrier != LINK_UP) {
			syslog(LOG_INFO, "%s: carrier acquired", ifp->name);
			ifp->carrier = LINK_UP;
#if !defined(__linux__) && !defined(__NetBSD__)
			/* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the
			 * hardware address changes so we have to go
			 * through the disovery process to work it out. */
			handle_interface(0, ifp->name);
#endif
			if (ifp->wireless)
				getifssid(ifp->name, ifp->ssid);
			configure_interface(ifp, margc, margv);
			script_runreason(ifp, "CARRIER");
			start_interface(ifp);
		}
	}
}
コード例 #2
0
bool part_ui::render_floating_images()
{
	events::raise_draw_event();
	update_whole_screen();

	skip_ = false;
	last_key_ = true;

	size_t fi_n = 0;
	foreach(floating_image::render_input& ri, imgs_) {
		const floating_image& fi = p_.get_floating_images()[fi_n];

		if(!ri.image.null()) {
			sdl_blit(ri.image, NULL, video_.getSurface(), &ri.rect);
			update_rect(ri.rect);
		}

		if (!skip_)
		{
			int delay = fi.display_delay(), delay_step = 20;
			for (int i = 0; i != (delay + delay_step - 1) / delay_step; ++i)
			{
				if (handle_interface()) return false;
				if (skip_) break;
				disp_.delay(std::min<int>(delay_step, delay - i * delay_step));
			}
		}

		++fi_n;
	}

	return true;
}
コード例 #3
0
ファイル: if-linux.c プロジェクト: RTEMS/rtems-libbsd
static int
handle_rename(unsigned int ifindex, const char *ifname)
{
	struct interface *ifp;

	TAILQ_FOREACH(ifp, ifaces, next) {
		if (ifp->index == ifindex && strcmp(ifp->name, ifname)) {
			handle_interface(-1, ifp->name);
			/* Let dev announce the interface for renaming */
			if (!dev_listening())
				handle_interface(1, ifname);
			return 1;
		}
	}
	return 0;
}
コード例 #4
0
void part_ui::wait_for_input()
{
	LOG_NG << "ENTER part_ui()::wait_for_input()\n";

	last_key_ = true;
	skip_ = true;
	while (!handle_interface()) {}
}
コード例 #5
0
int
manage_link(int fd)
{
	char *p, *e, *cp;
	char ifname[IF_NAMESIZE];
	ssize_t bytes;
	struct rt_msghdr *rtm;
	struct if_announcemsghdr *ifan;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct rt rt;
	struct sockaddr *sa, *rti_info[RTAX_MAX];
	int len;
#ifdef RTM_CHGADDR
	struct sockaddr_dl sdl;
	unsigned char *hwaddr;
#endif

	for (;;) {
		if (ioctl(fd, FIONREAD, &len) == -1)
			return -1;
		if (link_buflen < len) {
			p = realloc(link_buf, len);
			if (p == NULL)
				return -1;
			link_buf = p;
			link_buflen = len;
		}
		bytes = read(fd, link_buf, link_buflen);
		if (bytes == -1) {
			if (errno == EAGAIN)
				return 0;
			if (errno == EINTR)
				continue;
			return -1;
		}
		e = link_buf + bytes;
		for (p = link_buf; p < e; p += rtm->rtm_msglen) {
			rtm = (struct rt_msghdr *)(void *)p;
			switch(rtm->rtm_type) {
#ifdef RTM_IFANNOUNCE
			case RTM_IFANNOUNCE:
				ifan = (struct if_announcemsghdr *)(void *)p;
				switch(ifan->ifan_what) {
				case IFAN_ARRIVAL:
					handle_interface(1, ifan->ifan_name);
					break;
				case IFAN_DEPARTURE:
					handle_interface(-1, ifan->ifan_name);
					break;
				}
				break;
#endif
			case RTM_IFINFO:
				ifm = (struct if_msghdr *)(void *)p;
				memset(ifname, 0, sizeof(ifname));
				if (if_indextoname(ifm->ifm_index, ifname))
					handle_interface(0, ifname);
				break;
			case RTM_DELETE:
				if (!(rtm->rtm_addrs & RTA_DST) ||
				    !(rtm->rtm_addrs & RTA_GATEWAY) ||
				    !(rtm->rtm_addrs & RTA_NETMASK))
					break;
				if (rtm->rtm_pid == getpid())
					break;
				cp = (char *)(void *)(rtm + 1);
				sa = (struct sockaddr *)(void *)cp;
				if (sa->sa_family != AF_INET)
					break;
				get_addrs(rtm->rtm_addrs, cp, rti_info);
				rt.iface = NULL;
				rt.next = NULL;
				COPYOUT(rt.dest, rti_info[RTAX_DST]);
				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
				COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
				route_deleted(&rt);
				break;
#ifdef RTM_CHGADDR
			case RTM_CHGADDR:	/* FALLTHROUGH */
#endif
			case RTM_DELADDR:	/* FALLTHROUGH */
			case RTM_NEWADDR:
				ifam = (struct ifa_msghdr *)(void *)p;
				if (!if_indextoname(ifam->ifam_index, ifname))
					break;
				cp = (char *)(void *)(ifam + 1);
				get_addrs(ifam->ifam_addrs, cp, rti_info);
				if (rti_info[RTAX_IFA] == NULL)
					break;
				switch (rti_info[RTAX_IFA]->sa_family) {
#ifdef RTM_CHGADDR
				case AF_LINK:
					if (rtm->rtm_type != RTM_CHGADDR)
						break;
					memcpy(&sdl, rti_info[RTAX_IFA],
					    rti_info[RTAX_IFA]->sa_len);
					hwaddr = xmalloc(sdl.sdl_alen);
					memcpy(hwaddr, LLADDR(&sdl),
					    sdl.sdl_alen);
					handle_hwaddr(ifname, hwaddr,
					    sdl.sdl_alen);
					break;
#endif
				case AF_INET:
				case 255: /* FIXME: Why 255? */
					COPYOUT(rt.dest, rti_info[RTAX_IFA]);
					COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
					COPYOUT(rt.gate, rti_info[RTAX_BRD]);
					handle_ifa(rtm->rtm_type, ifname,
					    &rt.dest, &rt.net, &rt.gate);
					break;
				}
				break;
			}
		}
	}
}
コード例 #6
0
ファイル: render.cpp プロジェクト: jorge-barroso/wesnoth
void part_ui::render_story_box()
{
#ifdef SDL_GPU
	LOG_NG << "ENTER part_ui()::render_story_box()\n";

	GPU_Target *target = get_render_target();

	const std::string& storytxt = p_.text();
	if(storytxt.empty()) {
		video_.flip();
		wait_for_input();
		return;
	}

	const part::BLOCK_LOCATION tbl = p_.story_text_location();
	const int max_width = buttons_x_ - storybox_padding - text_x_;
	const int max_height = screen_area().h - storybox_padding;

	skip_ = false;
	last_key_ = true;

	font::ttext t;
	if(!t.set_text(p_.text(), true)) {
		ERR_NG << "Text: Invalid markup in '"
				<< p_.text() << "' rendered as is.\n";
		t.set_text(p_.text(), false);
	}
	t.set_font_style(font::ttext::STYLE_NORMAL)
		 .set_font_size(storybox_font_size)
		 .set_foreground_color(storybox_font_color)
		 .set_maximum_width(max_width)
		 .set_maximum_height(max_height, true);
	sdl::timage txttxt = t.render_as_texture();

	if(txttxt.null()) {
		ERR_NG << "storyscreen text area rendering resulted in a null texture" << std::endl;
		return;
	}

	int fix_text_y = text_y_;
	if(fix_text_y + 2*(storybox_padding+1) + txttxt.height() > screen_area().h && tbl != part::BLOCK_TOP) {
		fix_text_y =
			(screen_area().h > txttxt.height() + 1) ?
			(std::max(0, screen_area().h - txttxt.height() - 2*(storybox_padding+1))) :
			(0);
	}
	int fix_text_h;
	switch(tbl) {
	case part::BLOCK_TOP:
		fix_text_h = std::max(txttxt.height() + 2*storybox_padding, screen_area().h/4);
		break;
	case part::BLOCK_MIDDLE:
		fix_text_h = std::max(txttxt.height() + 2*storybox_padding, screen_area().h/3);
		break;
	default:
		fix_text_h = screen_area().h - fix_text_y;
		break;
	}

	SDL_Rect update_area = sdl::create_rect(0
			, fix_text_y
			, screen_area().w
			, fix_text_h);

	/* do */ {
		// this should kill the tiniest flickering caused
		// by the buttons being hidden and unhidden in this scope.
		update_locker locker(video_);

		next_button_.hide();
		back_button_.hide();
		play_button_.hide();

		//TODO: blurring

		const SDL_Rect box = sdl::create_rect(0, fix_text_y, screen_area().w,
											  fix_text_h);

		sdl::fill_rect(*target, box, storyshadow_r, storyshadow_g,
					   storyshadow_b, storyshadow_a);

		render_story_box_borders(update_area); // no-op if LOW_MEM is defined

		next_button_.hide(false);
		back_button_.hide(false);
		play_button_.hide(false);
	}

	// Time to do some f*****g visual effect.
	const int scan_height = 1, scan_width = txttxt.width();
	SDL_Rect scan = sdl::create_rect(0, 0, scan_width, scan_height);
	SDL_Rect dstrect = sdl::create_rect(text_x_, 0, scan_width, scan_height);
	bool scan_finished = false;
	while(true) {
		scan_finished = scan.y >= txttxt.base_height();
		if (!scan_finished)
		{
			dstrect.y = fix_text_y + scan.y + storybox_padding;
			txttxt.set_clip(scan);
			video_.draw_texture(txttxt, dstrect.x, dstrect.y);
			video_.flip();
			++scan.y;
		}
		else skip_ = true;

		if (handle_interface()) break;

		if (!skip_ || scan_finished) {
			disp_.delay(20);
		}
	}

	const SDL_Rect rect = sdl::create_rect(0, 0, video_.getx(), video_.gety());
	sdl::fill_rect(*target, rect, 0, 0, 0, 255);
#else
	LOG_NG << "ENTER part_ui()::render_story_box()\n";

	const std::string& storytxt = p_.text();
	if(storytxt.empty()) {
		update_whole_screen();
		wait_for_input();
		return;
	}

	const part::BLOCK_LOCATION tbl = p_.story_text_location();
	const int max_width = buttons_x_ - storybox_padding - text_x_;
	const int max_height = screen_area().h - storybox_padding;

	skip_ = false;
	last_key_ = true;

	font::ttext t;
	if(!t.set_text(p_.text(), true)) {
		ERR_NG << "Text: Invalid markup in '"
				<< p_.text() << "' rendered as is.\n";
		t.set_text(p_.text(), false);
	}
	t.set_font_style(font::ttext::STYLE_NORMAL)
	     .set_font_size(storybox_font_size)
		 .set_foreground_color(storybox_font_color)
		 .set_maximum_width(max_width)
		 .set_maximum_height(max_height, true);
	surface txtsurf = t.render();

	if(txtsurf.null()) {
		ERR_NG << "storyscreen text area rendering resulted in a null surface" << std::endl;
		return;
	}

	int fix_text_y = text_y_;
	if(fix_text_y + 2*(storybox_padding+1) + txtsurf->h > screen_area().h && tbl != part::BLOCK_TOP) {
		fix_text_y =
			(screen_area().h > txtsurf->h + 1) ?
			(std::max(0, screen_area().h - txtsurf->h - 2*(storybox_padding+1))) :
			(0);
	}
	int fix_text_h;
	switch(tbl) {
	case part::BLOCK_TOP:
		fix_text_h = std::max(txtsurf->h + 2*storybox_padding, screen_area().h/4);
		break;
	case part::BLOCK_MIDDLE:
		fix_text_h = std::max(txtsurf->h + 2*storybox_padding, screen_area().h/3);
		break;
	default:
		fix_text_h = screen_area().h - fix_text_y;
		break;
	}

	SDL_Rect update_area = sdl::create_rect(0
			, fix_text_y
			, screen_area().w
			, fix_text_h);

	/* do */ {
		// this should kill the tiniest flickering caused
		// by the buttons being hidden and unhidden in this scope.
		update_locker locker(video_);

		next_button_.hide();
		back_button_.hide();
		play_button_.hide();

#ifndef LOW_MEM
		blur_area(video_, fix_text_y, fix_text_h);
#endif

		sdl::draw_solid_tinted_rectangle(
			0, fix_text_y, screen_area().w, fix_text_h,
			storyshadow_r, storyshadow_g, storyshadow_b,
			storyshadow_opacity,
			video_.getSurface()
		);

		render_story_box_borders(update_area); // no-op if LOW_MEM is defined

		next_button_.hide(false);
		back_button_.hide(false);
		play_button_.hide(false);
	}

	if(imgs_.empty()) {
		update_whole_screen();
	} else if(update_area.h > 0) {
		update_rect(update_area);
	}

	// Time to do some f*****g visual effect.
	const int scan_height = 1, scan_width = txtsurf->w;
	SDL_Rect scan = sdl::create_rect(0, 0, scan_width, scan_height);
	SDL_Rect dstrect = sdl::create_rect(text_x_, 0, scan_width, scan_height);
	surface scan_dst = video_.getSurface();
	bool scan_finished = false;
	while(true) {
		scan_finished = scan.y >= txtsurf->h;
		if (!scan_finished)
		{
			//dstrect.x = text_x_;
			dstrect.y = fix_text_y + scan.y + storybox_padding;
			// NOTE: ::blit_surface() screws up with antialiasing and hinting when
			//       on backgroundless (e.g. black) screens; ttext::draw()
			//       uses it nonetheless, no idea why...
			//       Here we'll use CVideo::blit_surface() instead.
			video_.blit_surface(dstrect.x, dstrect.y, txtsurf, &scan);
			update_rect(dstrect);
			++scan.y;
		}
		else skip_ = true;

		if (handle_interface()) break;

		if (!skip_ || scan_finished) {
			disp_.delay(20);
		}
	}

	sdl::draw_solid_tinted_rectangle(
		0, 0, video_.getx(), video_.gety(), 0, 0, 0,
		1.0, video_.getSurface()
	);
#endif
}
コード例 #7
0
ファイル: if-bsd.c プロジェクト: RTEMS/rtems-libbsd
int
manage_link(int fd)
{
	char *p, *e, *cp;
	char ifname[IF_NAMESIZE];
	ssize_t bytes;
	struct rt_msghdr *rtm;
	struct if_announcemsghdr *ifan;
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;
	struct sockaddr *sa, *rti_info[RTAX_MAX];
	int len;
	struct sockaddr_dl sdl;
#ifdef INET
	struct rt rt;
#endif
#if defined(INET6) && !defined(LISTEN_DAD)
	struct in6_addr ia6;
	struct sockaddr_in6 *sin6;
	int ifa_flags;
#endif

	for (;;) {
		if (ioctl(fd, FIONREAD, &len) == -1)
			return -1;
		if (link_buflen < len) {
			p = realloc(link_buf, len);
			if (p == NULL)
				return -1;
			link_buf = p;
			link_buflen = len;
		}
		bytes = read(fd, link_buf, link_buflen);
		if (bytes == -1) {
			if (errno == EAGAIN)
				return 0;
			if (errno == EINTR)
				continue;
			return -1;
		}
		e = link_buf + bytes;
		for (p = link_buf; p < e; p += rtm->rtm_msglen) {
			rtm = (struct rt_msghdr *)(void *)p;
			// Ignore messages generated by us
			if (rtm->rtm_pid == getpid())
				break;
			switch(rtm->rtm_type) {
#ifdef RTM_IFANNOUNCE
			case RTM_IFANNOUNCE:
				ifan = (struct if_announcemsghdr *)(void *)p;
				switch(ifan->ifan_what) {
				case IFAN_ARRIVAL:
					handle_interface(1, ifan->ifan_name);
					break;
				case IFAN_DEPARTURE:
					handle_interface(-1, ifan->ifan_name);
					break;
				}
				break;
#endif
			case RTM_IFINFO:
				ifm = (struct if_msghdr *)(void *)p;
				memset(ifname, 0, sizeof(ifname));
				if (!(if_indextoname(ifm->ifm_index, ifname)))
					break;
				switch (ifm->ifm_data.ifi_link_state) {
				case LINK_STATE_DOWN:
					len = LINK_DOWN;
					break;
				case LINK_STATE_UP:
					len = LINK_UP;
					break;
				default:
					/* handle_carrier will re-load
					 * the interface flags and check for
					 * IFF_RUNNING as some drivers that
					 * don't handle link state also don't
					 * set IFF_RUNNING when this routing
					 * message is generated.
					 * As such, it is a race ...*/
					len = LINK_UNKNOWN;
					break;
				}
				handle_carrier(len, ifm->ifm_flags, ifname);
				break;
			case RTM_DELETE:
				if (~rtm->rtm_addrs &
				    (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
					break;
				cp = (char *)(void *)(rtm + 1);
				sa = (struct sockaddr *)(void *)cp;
				if (sa->sa_family != AF_INET)
					break;
#ifdef INET
				get_addrs(rtm->rtm_addrs, cp, rti_info);
				memset(&rt, 0, sizeof(rt));
				rt.iface = NULL;
				COPYOUT(rt.dest, rti_info[RTAX_DST]);
				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
				COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
				ipv4_routedeleted(&rt);
#endif
				break;
#ifdef RTM_CHGADDR
			case RTM_CHGADDR:	/* FALLTHROUGH */
#endif
			case RTM_DELADDR:	/* FALLTHROUGH */
			case RTM_NEWADDR:
				ifam = (struct ifa_msghdr *)(void *)p;
				if (!if_indextoname(ifam->ifam_index, ifname))
					break;
				cp = (char *)(void *)(ifam + 1);
				get_addrs(ifam->ifam_addrs, cp, rti_info);
				if (rti_info[RTAX_IFA] == NULL)
					break;
				switch (rti_info[RTAX_IFA]->sa_family) {
				case AF_LINK:
#ifdef RTM_CHGADDR
					if (rtm->rtm_type != RTM_CHGADDR)
						break;
#else
					if (rtm->rtm_type != RTM_NEWADDR)
						break;
#endif
					memcpy(&sdl, rti_info[RTAX_IFA],
					    rti_info[RTAX_IFA]->sa_len);
					handle_hwaddr(ifname,
					    (const unsigned char*)CLLADDR(&sdl),
					    sdl.sdl_alen);
					break;
#ifdef INET
				case AF_INET:
				case 255: /* FIXME: Why 255? */
					COPYOUT(rt.dest, rti_info[RTAX_IFA]);
					COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
					COPYOUT(rt.gate, rti_info[RTAX_BRD]);
					ipv4_handleifa(rtm->rtm_type,
					    NULL, ifname,
					    &rt.dest, &rt.net, &rt.gate);
					break;
#endif
#if defined(INET6) && !defined(LISTEN_DAD)
				case AF_INET6:
					sin6 = (struct sockaddr_in6*)(void *)
					    rti_info[RTAX_IFA];
					memcpy(ia6.s6_addr,
					    sin6->sin6_addr.s6_addr,
					    sizeof(ia6.s6_addr));
					if (rtm->rtm_type == RTM_NEWADDR) {
						ifa_flags = in6_addr_flags(
								ifname,
								&ia6);
						if (ifa_flags == -1)
							break;
					} else
						ifa_flags = 0;
					ipv6_handleifa(rtm->rtm_type, NULL,
					    ifname, &ia6, ifa_flags);
					break;
#endif
				}
				break;
			}
		}
	}
}
コード例 #8
0
ファイル: render.cpp プロジェクト: sunny975/wesnoth
bool part_ui::render_floating_images()
{
#ifdef SDL_GPU
	skip_ = false;
	last_key_ = true;

	size_t fi_n = 0;
	BOOST_FOREACH(floating_image::render_input& ri, imgs_) {
		const floating_image& fi = p_.get_floating_images()[fi_n];

		if(!ri.image.null()) {
			ri.image.draw(video_, ri.rect.x, ri.rect.y);
			video_.flip();
		}

		if (!skip_)
		{
			int delay = fi.display_delay(), delay_step = 20;
			for (int i = 0; i != (delay + delay_step - 1) / delay_step; ++i)
			{
				if (handle_interface()) return false;
				if (skip_) break;
				CVideo::delay(std::min<int>(delay_step, delay - i * delay_step));
			}
		}

		++fi_n;
	}

	return true;
#else
	events::raise_draw_event();

	skip_ = false;
	last_key_ = true;

	size_t fi_n = 0;
	BOOST_FOREACH(floating_image::render_input& ri, imgs_) {
		const floating_image& fi = p_.get_floating_images()[fi_n];

		if(!ri.image.null()) {
			render_background();
			for (size_t i = 0; i <= fi_n; i++)
			{
				floating_image::render_input& old_ri = imgs_[i];
				sdl_blit(old_ri.image, NULL, video_.getSurface(), &old_ri.rect);
				update_rect(old_ri.rect);
			}
		}

		if (!skip_)
		{
			int delay = fi.display_delay(), delay_step = 20;
			for (int i = 0; i != (delay + delay_step - 1) / delay_step; ++i)
			{
				if (handle_interface()) return false;
				if (skip_) break;
				CVideo::delay(std::min<int>(delay_step, delay - i * delay_step));
			}
		}

		++fi_n;
	}

	return true;
#endif
}
コード例 #9
0
ファイル: if-linux.c プロジェクト: RTEMS/rtems-libbsd
static int
link_netlink(struct nlmsghdr *nlm)
{
	int len;
	struct rtattr *rta, *hwaddr;
	struct ifinfomsg *ifi;
	char ifn[IF_NAMESIZE + 1];
	struct interface *ifp;

	len = link_route(nlm);
	if (len != 0)
		return len;
	len = link_addr(nlm);
	if (len != 0)
		return len;

	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
		return 0;
	len = nlm->nlmsg_len - sizeof(*nlm);
	if ((size_t)len < sizeof(*ifi)) {
		errno = EBADMSG;
		return -1;
	}
	ifi = NLMSG_DATA(nlm);
	if (ifi->ifi_flags & IFF_LOOPBACK)
		return 1;
	rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
	*ifn = '\0';
	hwaddr = NULL;

	while (RTA_OK(rta, len)) {
		switch (rta->rta_type) {
		case IFLA_WIRELESS:
			/* Ignore wireless messages */
			if (nlm->nlmsg_type == RTM_NEWLINK &&
			    ifi->ifi_change == 0)
				return 1;
			break;
		case IFLA_IFNAME:
			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
			break;
		case IFLA_ADDRESS:
			hwaddr = rta;
			break;
		}
		rta = RTA_NEXT(rta, len);
	}

	if (nlm->nlmsg_type == RTM_DELLINK) {
		handle_interface(-1, ifn);
		return 1;
	}

	/* Virtual interfaces may not get a valid hardware address
	 * at this point.
	 * To trigger a valid hardware address pickup we need to pretend
	 * that that don't exist until they have one. */
	if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
		handle_interface(-1, ifn);
		return 1;
	}

	/* Check for interface name change */
	if (handle_rename(ifi->ifi_index, ifn))
		    return 1;

	/* Check for a new interface */
	ifp = find_interface(ifn);
	if (ifp == NULL) {
		/* If are listening to a dev manager, let that announce
		 * the interface rather than the kernel. */
		if (dev_listening() < 1)
			handle_interface(1, ifn);
		return 1;
	}

	/* Re-read hardware address and friends */
	if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
		len = l2addr_len(ifi->ifi_type);
		if (hwaddr->rta_len == RTA_LENGTH(len))
			handle_hwaddr(ifn, RTA_DATA(hwaddr), len);
	}

	handle_carrier(ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
	    ifi->ifi_flags, ifn);
	return 1;
}