Example #1
0
void call_set_mtu(char *name, uint16_t mtu)
{
    cli_service_t svcp;

    memset(&svcp,0,sizeof(cli_service_t));

    memcpy(svcp.svc_mtu.bridge_name, name, strlen(name));
    svcp.svc_mtu.mtu = mtu;

    set_mtu(&svcp);

}
IOReturn AgereET131x::setMaxPacketSize (UInt32 maxSize){
    UInt32 newMtu = maxSize - (ETH_HLEN + ETH_FCS_LEN);
	if(newMtu == mtu)
		return kIOReturnSuccess;

	adapter_memory_free();

	set_mtu(newMtu);

	adapter_memory_alloc();

	return kIOReturnSuccess;
}
Example #3
0
File: mtu.c Project: ncopa/pingu
static void do_discover_and_write(void)
{
	int mtu;
	char iface[IFNAMSIZ];

	mtu = discover_mtu();
	if (mtu < 0) {
		fprintf(stderr, "Failed to determine MTU\n");
		return;
	}

	if (!netlink_route_get((struct sockaddr *)&to, NULL, iface)) {
		fprintf(stderr, "Failed to determine route interface\n");
		return;
	}

	printf("Writing %d to %s\n", mtu, iface);
	set_mtu(iface, mtu);
}
Example #4
0
/* Return value becomes exitcode. It's okay to not return at all */
static int do_set(char **argv)
{
	char *dev = NULL;
	uint32_t mask = 0;
	uint32_t flags = 0;
	int qlen = -1;
	int mtu = -1;
	char *newaddr = NULL;
	char *newbrd = NULL;
	struct ifreq ifr0, ifr1;
	char *newname = NULL;
	int htype, halen;
	static const char keywords[] ALIGN1 =
		"up\0""down\0""name\0""mtu\0""multicast\0"
		"arp\0""address\0""dev\0";
	enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast,
		ARG_arp, ARG_addr, ARG_dev };
	static const char str_on_off[] ALIGN1 = "on\0""off\0";
	enum { PARM_on = 0, PARM_off };
	smalluint key;

	while (*argv) {
		/* substring search ensures that e.g. "addr" and "address"
		 * are both accepted */
		key = index_in_substrings(keywords, *argv);
		if (key == ARG_up) {
			mask |= IFF_UP;
			flags |= IFF_UP;
		}
		if (key == ARG_down) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		}
		if (key == ARG_name) {
			NEXT_ARG();
			newname = *argv;
		}
		if (key == ARG_mtu) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			mtu = get_unsigned(*argv, "mtu");
		}
		if (key == ARG_multicast) {
			int param;
			NEXT_ARG();
			mask |= IFF_MULTICAST;
			param = index_in_strings(str_on_off, *argv);
			if (param < 0)
				die_must_be_on_off("multicast");
			if (param == PARM_on)
				flags |= IFF_MULTICAST;
			else
				flags &= ~IFF_MULTICAST;
		}
		if (key == ARG_arp) {
			int param;
			NEXT_ARG();
			mask |= IFF_NOARP;
			param = index_in_strings(str_on_off, *argv);
			if (param < 0)
				die_must_be_on_off("arp");
			if (param == PARM_on)
				flags &= ~IFF_NOARP;
			else
				flags |= IFF_NOARP;
		}
		if (key == ARG_addr) {
			NEXT_ARG();
			newaddr = *argv;
		}
		if (key >= ARG_dev) {
			if (key == ARG_dev) {
				NEXT_ARG();
			}
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		}
		argv++;
	}

	if (!dev) {
		bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
	}

	if (newaddr || newbrd) {
		halen = get_address(dev, &htype);
		if (newaddr) {
			parse_address(dev, htype, halen, newaddr, &ifr0);
		}
		if (newbrd) {
			parse_address(dev, htype, halen, newbrd, &ifr1);
		}
	}

	if (newname && strcmp(dev, newname)) {
		do_changename(dev, newname);
		dev = newname;
	}
	if (qlen != -1) {
		set_qlen(dev, qlen);
	}
	if (mtu != -1) {
		set_mtu(dev, mtu);
	}
	if (newaddr || newbrd) {
		if (newbrd) {
			set_address(&ifr1, 1);
		}
		if (newaddr) {
			set_address(&ifr0, 0);
		}
	}
	if (mask)
		do_chflags(dev, flags, mask);
	return 0;
}
Example #5
0
static int do_set(int argc, char **argv)
{
	char *dev = NULL;
	__u32 mask = 0;
	__u32 flags = 0;
	int qlen = -1;
	int mtu = -1;
	char *newaddr = NULL;
	char *newbrd = NULL;
	struct ifreq ifr0, ifr1;
	char *newname = NULL;
	int htype, halen;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			mask |= IFF_UP;
			flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			newname = *argv;
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			mask |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast");
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			mask |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				flags |= IFF_NOARP;
			} else
				return on_off("noarp");
		} else if (strcmp(*argv, "addr") == 0) {
			NEXT_ARG();
			newaddr = *argv;
		} else {
                        if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		}
		argc--; argv++;
	}

	if (!dev) {
		bb_error_msg("Not enough of information: \"dev\" argument is required.");
		exit(-1);
	}

	if (newaddr || newbrd) {
		halen = get_address(dev, &htype);
		if (halen < 0)
			return -1;
		if (newaddr) {
			if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
				return -1;
		}
		if (newbrd) {
			if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
				return -1;
		}
	}

	if (newname && strcmp(dev, newname)) {
		if (do_changename(dev, newname) < 0)
			return -1;
		dev = newname;
	}
	if (qlen != -1) {
		if (set_qlen(dev, qlen) < 0)
			return -1;
	}
	if (mtu != -1) {
		if (set_mtu(dev, mtu) < 0)
			return -1;
	}
	if (newaddr || newbrd) {
		if (newbrd) {
			if (set_address(&ifr1, 1) < 0)
				return -1;
		}
		if (newaddr) {
			if (set_address(&ifr0, 0) < 0)
				return -1;
		}
	}
	if (mask)
		return do_chflags(dev, flags, mask);
	return 0;
}
Example #6
0
static int do_set(int argc, char **argv)
{
	char *dev = NULL;
	__u32 mask = 0;
	__u32 flags = 0;
	int qlen = -1;
	int mtu = -1;
	char *newaddr = NULL;
	char *newbrd = NULL;
	struct ifreq ifr0, ifr1;
	char *newname = NULL;
	int htype, halen;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			mask |= IFF_UP;
			flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			newname = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			newaddr = *argv;
		} else if (matches(*argv, "broadcast") == 0 ||
			   strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			newbrd = *argv;
		} else if (matches(*argv, "txqueuelen") == 0 ||
			   strcmp(*argv, "qlen") == 0 ||
			   matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			mask |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast", *argv);
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			mask |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast", *argv);
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			mask |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc", *argv);
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			mask |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers", *argv);
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			mask |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				flags |= IFF_NOARP;
			} else
				return on_off("noarp", *argv);
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			mask |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic", *argv);
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		}
		argc--; argv++;
	}

	if (!dev) {
		fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
		exit(-1);
	}

	if (newaddr || newbrd) {
		halen = get_address(dev, &htype);
		if (halen < 0)
			return -1;
		if (newaddr) {
			if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
				return -1;
		}
		if (newbrd) {
			if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
				return -1;
		}
	}

	if (newname && strcmp(dev, newname)) {
		if (strlen(newname) == 0)
			invarg("\"\" is not a valid device identifier\n", "name");
		if (do_changename(dev, newname) < 0)
			return -1;
		dev = newname;
	}
	if (qlen != -1) {
		if (set_qlen(dev, qlen) < 0)
			return -1;
	}
	if (mtu != -1) {
		if (set_mtu(dev, mtu) < 0)
			return -1;
	}
	if (newaddr || newbrd) {
		if (newbrd) {
			if (set_address(&ifr1, 1) < 0)
				return -1;
		}
		if (newaddr) {
			if (set_address(&ifr0, 0) < 0)
				return -1;
		}
	}
	if (mask)
		return do_chflags(dev, flags, mask);
	return 0;
}
Example #7
0
size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
					 unsigned long xid, char type,
					 const options_t *options)
{
	dhcpmessage_t message;
	struct udp_dhcp_packet packet;
	unsigned char *m = (unsigned char *) &message;
	unsigned char *p = (unsigned char *) &message.options;
	unsigned char *n_params = NULL;
	unsigned long l;
	struct in_addr from;
	struct in_addr to;
	long up = uptime() - iface->start_uptime;
	uint32_t ul;
	uint16_t sz;
	unsigned int message_length;

	if (!iface || !options || !dhcp)
		return -1;

	memset (&from, 0, sizeof (from));
	memset (&to, 0, sizeof (to));

	if (type == DHCP_RELEASE)
		to.s_addr = dhcp->serveraddress.s_addr;

	memset (&message, 0, sizeof (dhcpmessage_t));

	if (type == DHCP_INFORM ||
		type == DHCP_RELEASE ||
		type == DHCP_REQUEST)
	{
		message.ciaddr = iface->previous_address.s_addr;
		from.s_addr = iface->previous_address.s_addr;
	}

	message.op = DHCP_BOOTREQUEST;
	message.hwtype = iface->family;
	switch (iface->family) {
		case ARPHRD_ETHER:
		case ARPHRD_IEEE802:
			message.hwlen = ETHER_ADDR_LEN;
			memcpy (&message.chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
			break;
		case ARPHRD_IEEE1394:
		case ARPHRD_INFINIBAND:
			if (message.ciaddr == 0)
				message.flags = htons (BROADCAST_FLAG);
			message.hwlen = 0;
			break;
		default:
			logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family);
	}

	if (up < 0 || up > UINT16_MAX)
		message.secs = htons ((short) UINT16_MAX);
	else
		message.secs = htons (up);
	message.xid = xid;
	message.cookie = htonl (MAGIC_COOKIE);

	*p++ = DHCP_MESSAGETYPE; 
	*p++ = 1;
	*p++ = type;

	if (type == DHCP_REQUEST) {
		*p++ = DHCP_MAXMESSAGESIZE;
		*p++ = 2;
		sz = get_mtu (iface->name);
		if (sz < MTU_MIN) {
			if (set_mtu (iface->name, MTU_MIN) == 0)
				sz = MTU_MIN;
		}
		sz = htons (sz);
		memcpy (p, &sz, 2);
		p += 2;
	}

#define PUTADDR(_type, _val) \
	{ \
		*p++ = _type; \
		*p++ = 4; \
		memcpy (p, &_val.s_addr, 4); \
		p += 4; \
	}
	if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0
		&& type != DHCP_RELEASE)
		PUTADDR (DHCP_ADDRESS, dhcp->address);

	if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 &&
		(iface->previous_address.s_addr == 0 || type == DHCP_RELEASE))
		PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress);
#undef PUTADDR

	if (type == DHCP_REQUEST || type == DHCP_DISCOVER) {
		if (options->leasetime != 0) {
			*p++ = DHCP_LEASETIME;
			*p++ = 4;
			ul = htonl (options->leasetime);
			memcpy (p, &ul, 4);
			p += 4;
		}
	}

	if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) {
		*p++ = DHCP_PARAMETERREQUESTLIST;
		n_params = p;
		*p++ = 0;

		/* Only request DNSSERVER in discover to keep the packets small.
		   RFC2131 Section 3.5 states that the REQUEST must include the list
		   from the DISCOVER message, so I think we can safely do this. */

		if (type == DHCP_DISCOVER)
			*p++ = DHCP_DNSSERVER;
		else {
			*p++ = DHCP_RENEWALTIME;
			*p++ = DHCP_REBINDTIME;
			*p++ = DHCP_NETMASK;
			*p++ = DHCP_BROADCAST;
			*p++ = DHCP_CSR;
			/* RFC 3442 states classless static routes should be before routers
			 * and static routes as classless static routes override them both */
			*p++ = DHCP_STATICROUTE;
			*p++ = DHCP_ROUTERS;
			*p++ = DHCP_HOSTNAME;
			*p++ = DHCP_DNSSEARCH;
			*p++ = DHCP_DNSDOMAIN;
			*p++ = DHCP_DNSSERVER;
			*p++ = DHCP_NISDOMAIN;
			*p++ = DHCP_NISSERVER;
			*p++ = DHCP_NTPSERVER;
			*p++ = DHCP_MTU;
			*p++ = DHCP_ROOTPATH;
			/* These parameters were requested by dhcpcd-2.0 and earlier
			   but we never did anything with them */
			/*    *p++ = DHCP_DEFAULTIPTTL;
			 *p++ = DHCP_MASKDISCOVERY;
			 *p++ = DHCP_ROUTERDISCOVERY; */
		}

		*n_params = p - n_params - 1;

		if (*options->hostname) {
			if (options->fqdn == FQDN_DISABLE) {
				*p++ = DHCP_HOSTNAME;
				*p++ = l = strlen (options->hostname);
				memcpy (p, options->hostname, l);
				p += l;
			} else {
				/* Draft IETF DHC-FQDN option (81) */
				*p++ = DHCP_FQDN;
				*p++ = (l = strlen (options->hostname)) + 3;
				/* Flags: 0000NEOS
				 * S: 1 => Client requests Server to update A RR in DNS as well as PTR
				 * O: 1 => Server indicates to client that DNS has been updated
				 * E: 1 => Name data is DNS format
				 * N: 1 => Client requests Server to not update DNS
				 */
				*p++ = options->fqdn & 0x9;
				*p++ = 0; /* rcode1, response from DNS server for PTR RR */
				*p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */
				memcpy (p, options->hostname, l);
				p += l;
			}
		}
	}

	if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
		if (options->userclass_len > 0) {
			*p++ = DHCP_USERCLASS;
			*p++ = options->userclass_len;
			memcpy (p, &options->userclass, options->userclass_len);
			p += options->userclass_len;
		}

		*p++ = DHCP_CLASSID;
		*p++ = l = strlen (options->classid);
		memcpy (p, options->classid, l);
		p += l;
	}

	*p++ = DHCP_CLIENTID;
	if (options->clientid[0]) {
		l = strlen (options->clientid);
		*p++ = l + 1;
		*p++ = 0; /* string */
		memcpy (p, options->clientid, l);
		p += l;
	} else {
		*p++ = iface->hwlen + 1;
		*p++ = iface->family;
		memcpy (p, iface->hwaddr, iface->hwlen);
		p += iface->hwlen;
	}

#ifdef BOOTP_MESSAGE_LENTH_MIN
	/* Some crappy DHCP servers think they have to obey the BOOTP minimum
	 * messag length. They are wrong, but we should still cater for them */
	while (p - m < BOOTP_MESSAGE_LENTH_MIN - 1)
		*p++ = DHCP_PAD;
#endif

	*p++ = DHCP_END;
	message_length = p - m;

	memset (&packet, 0, sizeof (struct udp_dhcp_packet));
	make_dhcp_packet (&packet, (unsigned char *) &message, message_length,
					  from, to);

	logger (LOG_DEBUG, "sending %s with xid 0x%lx", dhcp_message[(int) type], xid);
	return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet,
						message_length + sizeof (struct ip) +
						sizeof (struct udphdr));
}
ssize_t
make_message(struct dhcp_message **message,
	     const struct interface *iface, const struct dhcp_lease *lease,
	     uint32_t xid, uint8_t type, const struct options *options)
{
	struct dhcp_message *dhcp;
	uint8_t *m, *lp, *p;
	uint8_t *n_params = NULL;
	time_t up = uptime() - iface->start_uptime;
	uint32_t ul;
	uint16_t sz;
	const struct dhcp_opt *opt;
	size_t len;
	const char *hp;

	dhcp = xzalloc(sizeof (*dhcp));
	m = (uint8_t *)dhcp;
	p = dhcp->options;

	if ((type == DHCP_INFORM ||
	     type == DHCP_RELEASE ||
	     type == DHCP_REQUEST) &&
	    !IN_LINKLOCAL(ntohl(iface->addr.s_addr)))
	{
		dhcp->ciaddr = iface->addr.s_addr;
		/* Just incase we haven't actually configured the address yet */
		if (type == DHCP_INFORM && iface->addr.s_addr == 0)
			dhcp->ciaddr = lease->addr.s_addr;
		/* Zero the address if we're currently on a different subnet */
		if (type == DHCP_REQUEST &&
		    iface->net.s_addr != lease->net.s_addr)
			dhcp->ciaddr = 0;
	}

	dhcp->op = DHCP_BOOTREQUEST;
	dhcp->hwtype = iface->family;
	switch (iface->family) {
	case ARPHRD_ETHER:
	case ARPHRD_IEEE802:
		dhcp->hwlen = ETHER_ADDR_LEN;
		memcpy(&dhcp->chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
		break;
	case ARPHRD_IEEE1394:
	case ARPHRD_INFINIBAND:
		dhcp->hwlen = 0;
		if (dhcp->ciaddr == 0 &&
		    type != DHCP_DECLINE && type != DHCP_RELEASE)
			dhcp->flags = htons(BROADCAST_FLAG);
		break;
	}

	if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
		if (up < 0 || up > (time_t)UINT16_MAX)
			dhcp->secs = htons((uint16_t)UINT16_MAX);
		else
			dhcp->secs = htons(up);
	}
	dhcp->xid = xid;
	dhcp->cookie = htonl(MAGIC_COOKIE);

	*p++ = DHO_MESSAGETYPE; 
	*p++ = 1;
	*p++ = type;

	if (iface->clientid) {
		*p++ = DHO_CLIENTID;
		memcpy(p, iface->clientid, iface->clientid[0] + 1);
		p += iface->clientid[0] + 1;
	}

	if (lease->addr.s_addr && !IN_LINKLOCAL(htonl(lease->addr.s_addr))) {
		if (type == DHCP_DECLINE ||
		    type == DHCP_DISCOVER ||
		    (type == DHCP_REQUEST &&
		     lease->addr.s_addr != iface->addr.s_addr))
		{
			PUTADDR(DHO_IPADDRESS, lease->addr);
			if (lease->server.s_addr)
				PUTADDR(DHO_SERVERID, lease->server);
		}
	}

	if (type == DHCP_DECLINE) {
		*p++ = DHO_MESSAGE;
		len = strlen(DAD);
		*p++ = len;
		memcpy(p, DAD, len);
		p += len;
	}

	if (type == DHCP_RELEASE) {
		if (lease->server.s_addr)
			PUTADDR(DHO_SERVERID, lease->server);
	}

	if (type == DHCP_DISCOVER ||
	    type == DHCP_INFORM ||
	    type == DHCP_REQUEST)
	{
		*p++ = DHO_MAXMESSAGESIZE;
		*p++ = 2;
		sz = get_mtu(iface->name);
		if (sz < MTU_MIN) {
			if (set_mtu(iface->name, MTU_MIN) == 0)
				sz = MTU_MIN;
		}
		sz = htons(sz);
		memcpy(p, &sz, 2);
		p += 2;

		if (options->userclass[0]) {
			*p++ = DHO_USERCLASS;
			memcpy(p, options->userclass, options->userclass[0] + 1);
			p += options->userclass[0] + 1;
		}

		if (options->vendorclassid[0]) {
			*p++ = DHO_VENDORCLASSID;
			memcpy(p, options->vendorclassid,
			       options->vendorclassid[0] + 1);
			p += options->vendorclassid[0] + 1;
		}

		if (type != DHCP_INFORM) {
			if (options->leasetime != 0) {
				*p++ = DHO_LEASETIME;
				*p++ = 4;
				ul = htonl(options->leasetime);
				memcpy(p, &ul, 4);
				p += 4;
			}
		}

		/* Regardless of RFC2132, we should always send a hostname
		 * upto the first dot (the short hostname) as otherwise
		 * confuses some DHCP servers when updating DNS.
		 * The FQDN option should be used if a FQDN is required. */
		if (options->hostname[0]) {
			*p++ = DHO_HOSTNAME;
			hp = strchr(options->hostname, '.');
			if (hp)
				len = hp - options->hostname;
			else
				len = strlen(options->hostname);
			*p++ = len;
			memcpy(p, options->hostname, len);
			p += len;
		}
		if (options->fqdn != FQDN_DISABLE) {
			/* IETF DHC-FQDN option (81), RFC4702 */
			*p++ = DHO_FQDN;
			lp = p;
			*p++ = 3;
			/*
			 * Flags: 0000NEOS
			 * S: 1 => Client requests Server to update
			 *         a RR in DNS as well as PTR
			 * O: 1 => Server indicates to client that
			 *         DNS has been updated
			 * E: 1 => Name data is DNS format
			 * N: 1 => Client requests Server to not
			 *         update DNS
			 */
			*p++ = (options->fqdn & 0x09) | 0x04;
			*p++ = 0; /* from server for PTR RR */
			*p++ = 0; /* from server for A RR if S=1 */
			ul = encode_rfc1035(options->hostname, p);
			*lp += ul;
			p += ul;
		}

		/* vendor is already encoded correctly, so just add it */
		if (options->vendor[0]) {
			*p++ = DHO_VENDOR;
			memcpy(p, options->vendor, options->vendor[0] + 1);
			p += options->vendor[0] + 1;
		}

		*p++ = DHO_PARAMETERREQUESTLIST;
		n_params = p;
		*p++ = 0;
		for (opt = dhcp_opts; opt->option; opt++) {
			if (!(opt->type & REQUEST || 
			      has_option_mask(options->requestmask, opt->option)))
				continue;
			switch (opt->option) {
			case DHO_RENEWALTIME:	/* FALLTHROUGH */
			case DHO_REBINDTIME:
				if (type == DHCP_INFORM)
					continue;
				break;
			}
			*p++ = opt->option;
		}
		*n_params = p - n_params - 1;
	}
	*p++ = DHO_END;

#ifdef BOOTP_MESSAGE_LENTH_MIN
	/* Some crappy DHCP servers think they have to obey the BOOTP minimum
	 * message length.
	 * They are wrong, but we should still cater for them. */
	while (p - m < BOOTP_MESSAGE_LENTH_MIN)
		*p++ = DHO_PAD;
#endif

	*message = dhcp;
	return p - m;
}
Example #9
0
File: ifc.c Project: dbittman/sea
int main(int argc, char **argv)
{
	int c;
	int read = 1; /* by default, we read data and print it out. operation modes that
				   * write settings change this to 0. */
	const char *name = 0;
	/* parse options to look for the interface name... */
	opterr = 0;
	while((c = getopt(argc, argv, "hi:")) != -1) {
		switch(c) {
			case 'h':
				usage();
				break;
			case 'i':
				name = optarg;
				break;
		}
	}

	/* reset getopt() and set the things */
	optind = 0;
	opterr = 1;
	while((c = getopt(argc, argv, "u:s:n:m:i:hb:")) != -1) {
		switch(c) {
			case 'u':
				read = 0;
				if(!name) {
					fprintf(stderr, "ifc: no interface specified\n");
					exit(1);
				}
				if(set_flag(name, optarg, 1))
					exit(1);
				break;
			case 's':
				read = 0;
				if(!name) {
					fprintf(stderr, "ifc: no interface specified\n");
					exit(1);
				}
				if(set_flag(name, optarg, 0))
					exit(1);
				break;
			case 'n':
				read = 0;
				if(!name) {
					fprintf(stderr, "ifc: no interface specified\n");
					exit(1);
				}
				if(set_addr(name, optarg))
					exit(1);
				break;
			case 'b':
				read = 0;
				if(!name) {
					fprintf(stderr, "ifc: no interface specified\n");
					exit(1);
				}
				if(set_broad_addr(name, optarg))
					exit(1);
				break;
			case 'm':
				read = 0;
				if(!name) {
					fprintf(stderr, "ifc: no interface specified\n");
					exit(1);
				}
				if(set_mask(name, optarg))
					exit(1);
				break;
			case 't':
				read = 0;
				if(!name) {
					fprintf(stderr, "ifc: no interface specified\n");
					exit(1);
				}
				if(set_mtu(name, optarg))
					exit(1);
				break;
			case 'i': break;
			default:
				exit(1);
		}
	}
	if(read)
		read_stats(name);
	return 0;
}
Example #10
0
size_t send_message (const interface_t *iface, const dhcp_t *dhcp,
					 unsigned long xid, char type,
					 const options_t *options)
{
	struct udp_dhcp_packet *packet;
	dhcpmessage_t *message;
	unsigned char *m;
	unsigned char *p;
	unsigned char *n_params = NULL;
	unsigned long l;
	struct in_addr from;
	struct in_addr to;
	time_t up = uptime() - iface->start_uptime;
	uint32_t ul;
	uint16_t sz;
	unsigned int message_length;
	size_t retval;

	if (!iface || !options || !dhcp)
		return -1;

	memset (&from, 0, sizeof (from));
	memset (&to, 0, sizeof (to));

	if (type == DHCP_RELEASE)
		to.s_addr = dhcp->serveraddress.s_addr;

	message = xmalloc (sizeof (dhcpmessage_t));
	memset (message, 0, sizeof (dhcpmessage_t));
	m = (unsigned char *) message;
	p = (unsigned char *) &message->options;

	if ((type == DHCP_INFORM ||
		type == DHCP_RELEASE ||
		type == DHCP_REQUEST) &&
		! IN_LINKLOCAL (iface->previous_address.s_addr))
	{
		message->ciaddr = iface->previous_address.s_addr;
		from.s_addr = iface->previous_address.s_addr;

		/* Just incase we haven't actually configured the address yet */
		if (type == DHCP_INFORM && iface->previous_address.s_addr == 0)
			message->ciaddr = dhcp->address.s_addr;
		
		/* Zero the address if we're currently on a different subnet */
		if (type == DHCP_REQUEST &&
			iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
			message->ciaddr = from.s_addr = 0;
	}

	message->op = DHCP_BOOTREQUEST;
	message->hwtype = iface->family;
	switch (iface->family) {
		case ARPHRD_ETHER:
		case ARPHRD_IEEE802:
			message->hwlen = ETHER_ADDR_LEN;
			memcpy (&message->chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
			break;
		case ARPHRD_IEEE1394:
		case ARPHRD_INFINIBAND:
			if (message->ciaddr == 0)
				message->flags = (int16_t) htons (BROADCAST_FLAG);
			message->hwlen = 0;
			break;
		default:
			logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family);
	}

	if (up < 0 || up > UINT16_MAX)
		message->secs = htons ((short) UINT16_MAX);
	else
		message->secs = htons (up);
	message->xid = xid;
	message->cookie = htonl (MAGIC_COOKIE);

	*p++ = DHCP_MESSAGETYPE; 
	*p++ = 1;
	*p++ = type;

	if (type == DHCP_REQUEST) {
		*p++ = DHCP_MAXMESSAGESIZE;
		*p++ = 2;
		sz = get_mtu (iface->name);
		if (sz < MTU_MIN) {
			if (set_mtu (iface->name, MTU_MIN) == 0)
				sz = MTU_MIN;
		}
		sz = htons (sz);
		memcpy (p, &sz, 2);
		p += 2;
	}

	if (type != DHCP_INFORM) {
#define PUTADDR(_type, _val) \
		{ \
			*p++ = _type; \
			*p++ = 4; \
			memcpy (p, &_val.s_addr, 4); \
			p += 4; \
		}
		if (IN_LINKLOCAL (dhcp->address.s_addr))
			logger (LOG_ERR, "cannot request a link local address");
		else {
			if (dhcp->address.s_addr != iface->previous_address.s_addr &&
				type != DHCP_RELEASE)
				PUTADDR (DHCP_ADDRESS, dhcp->address);

			if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 &&
				(iface->previous_address.s_addr == 0 || type == DHCP_RELEASE))
				PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress);
		}
#undef PUTADDR
	}

	if (type == DHCP_REQUEST || type == DHCP_DISCOVER) {
		if (options->leasetime != 0) {
			*p++ = DHCP_LEASETIME;
			*p++ = 4;
			ul = htonl (options->leasetime);
			memcpy (p, &ul, 4);
			p += 4;
		}
	}

	if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) {
		*p++ = DHCP_PARAMETERREQUESTLIST;
		n_params = p;
		*p++ = 0;

		/* Only request DNSSERVER in discover to keep the packets small.
		   RFC2131 Section 3.5 states that the REQUEST must include the list
		   from the DISCOVER message, so I think we can safely do this. */

		if (type == DHCP_DISCOVER && ! options->test)
			*p++ = DHCP_DNSSERVER;
		else {
			if (type != DHCP_INFORM) {
				*p++ = DHCP_RENEWALTIME;
				*p++ = DHCP_REBINDTIME;
			}
			*p++ = DHCP_NETMASK;
			*p++ = DHCP_BROADCAST;
			*p++ = DHCP_CSR;
			/* RFC 3442 states classless static routes should be before routers
			 * and static routes as classless static routes override them both */
			*p++ = DHCP_STATICROUTE;
			*p++ = DHCP_ROUTERS;
			*p++ = DHCP_HOSTNAME;
			*p++ = DHCP_DNSSEARCH;
			*p++ = DHCP_DNSDOMAIN;
			*p++ = DHCP_DNSSERVER;
			*p++ = DHCP_NISDOMAIN;
			*p++ = DHCP_NISSERVER;
			*p++ = DHCP_NTPSERVER;
			*p++ = DHCP_MTU;
			*p++ = DHCP_ROOTPATH;
			*p++ = DHCP_SIPSERVER;
		}

		*n_params = p - n_params - 1;

		if (options->hostname[0]) {
			if (options->fqdn == FQDN_DISABLE) {
				*p++ = DHCP_HOSTNAME;
				*p++ = l = strlen (options->hostname);
				memcpy (p, options->hostname, l);
				p += l;
			} else {
				/* Draft IETF DHC-FQDN option (81) */
				*p++ = DHCP_FQDN;
				*p++ = (l = strlen (options->hostname)) + 3;
				/* Flags: 0000NEOS
				 * S: 1 => Client requests Server to update A RR in DNS as well as PTR
				 * O: 1 => Server indicates to client that DNS has been updated
				 * E: 1 => Name data is DNS format
				 * N: 1 => Client requests Server to not update DNS
				 */
				*p++ = options->fqdn & 0x9;
				*p++ = 0; /* rcode1, response from DNS server for PTR RR */
				*p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */
				memcpy (p, options->hostname, l);
				p += l;
			}
		}
	}

	if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
		if (options->userclass_len > 0) {
			*p++ = DHCP_USERCLASS;
			*p++ = options->userclass_len;
			memcpy (p, &options->userclass, options->userclass_len);
			p += options->userclass_len;
		}

		if (options->classid_len > 0) {
			*p++ = DHCP_CLASSID;
			*p++ = options->classid_len;
			memcpy (p, options->classid, options->classid_len);
			p += options->classid_len;
		}
	}

	*p++ = DHCP_CLIENTID;
	if (options->clientid_len > 0) {
		*p++ = options->clientid_len + 1;
		*p++ = 0; /* string */
		memcpy (p, options->clientid, options->clientid_len);
		p += options->clientid_len;
#ifdef ENABLE_DUID
	} else if (iface->duid && options->clientid_len != -1) {
		*p++ = iface->duid_length + 5;
		*p++ = 255; /* RFC 4361 */

		/* IAID is 4 bytes, so if the interface name is 4 bytes then use it */
		if (strlen (iface->name) == 4) {
			memcpy (p, iface->name, 4);
		} else {
			/* Name isn't 4 bytes, so use the index */
			ul = htonl (if_nametoindex (iface->name));
			memcpy (p, &ul, 4);
		}
		p += 4;

		memcpy (p, iface->duid, iface->duid_length);
		p += iface->duid_length;
#endif
	} else {
		*p++ = iface->hwlen + 1;
		*p++ = iface->family;
		memcpy (p, iface->hwaddr, iface->hwlen);
		p += iface->hwlen;
	}

	*p++ = DHCP_END;

#ifdef BOOTP_MESSAGE_LENTH_MIN
	/* Some crappy DHCP servers think they have to obey the BOOTP minimum
	 * messag length. They are wrong, but we should still cater for them */
	while (p - m < BOOTP_MESSAGE_LENTH_MIN)
		*p++ = DHCP_PAD;
#endif

	message_length = p - m;

	packet = xmalloc (sizeof (struct udp_dhcp_packet));
	memset (packet, 0, sizeof (struct udp_dhcp_packet));
	make_dhcp_packet (packet, (unsigned char *) message, message_length,
					  from, to);
	free (message);

	logger (LOG_DEBUG, "sending %s with xid 0x%lx",
			dhcp_message[(int) type], xid);
	retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet,
						  message_length + sizeof (struct ip) +
						  sizeof (struct udphdr));
	free (packet);
	return (retval);
}
Example #11
0
struct if_head *
discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
{
	struct ifaddrs *ifaddrs, *ifa;
	char *p;
	int i, sdl_type;
	struct if_head *ifs;
	struct interface *ifp;
#ifdef __linux__
	char ifn[IF_NAMESIZE];
#endif
#ifdef INET
	const struct sockaddr_in *addr;
	const struct sockaddr_in *net;
	const struct sockaddr_in *dst;
#endif
#ifdef INET6
	const struct sockaddr_in6 *sin6;
	int ifa_flags;
#endif
#ifdef AF_LINK
	const struct sockaddr_dl *sdl;
#ifdef SIOCGIFPRIORITY
	struct ifreq ifr;
	int s_inet;
#endif
#ifdef IFLR_ACTIVE
	struct if_laddrreq iflr;
	int s_link;
#endif

#ifdef SIOCGIFPRIORITY
	if ((s_inet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
		return NULL;
#endif
#ifdef IFLR_ACTIVE
	if ((s_link = socket(AF_LINK, SOCK_DGRAM, 0)) == -1) {
#ifdef SIOCGIFPRIORITY
		close(s_inet);
#endif
		return NULL;
	}
	memset(&iflr, 0, sizeof(iflr));
#endif
#elif AF_PACKET
	const struct sockaddr_ll *sll;
#endif

	if (getifaddrs(&ifaddrs) == -1)
		return NULL;
	ifs = malloc(sizeof(*ifs));
	if (ifs == NULL)
		return NULL;
	TAILQ_INIT(ifs);

	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
		if (ifa->ifa_addr != NULL) {
#ifdef AF_LINK
			if (ifa->ifa_addr->sa_family != AF_LINK)
				continue;
#elif AF_PACKET
			if (ifa->ifa_addr->sa_family != AF_PACKET)
				continue;
#endif
		}

		/* Ensure that the interface name has settled */
		if (!dev_initialized(ctx, ifa->ifa_name))
			continue;

		/* It's possible for an interface to have >1 AF_LINK.
		 * For our purposes, we use the first one. */
		TAILQ_FOREACH(ifp, ifs, next) {
			if (strcmp(ifp->name, ifa->ifa_name) == 0)
				break;
		}
		if (ifp)
			continue;
		if (argc > 0) {
			for (i = 0; i < argc; i++) {
#ifdef __linux__
				/* Check the real interface name */
				strlcpy(ifn, argv[i], sizeof(ifn));
				p = strchr(ifn, ':');
				if (p)
					*p = '\0';
				if (strcmp(ifn, ifa->ifa_name) == 0)
					break;
#else
				if (strcmp(argv[i], ifa->ifa_name) == 0)
					break;
#endif
			}
			if (i == argc)
				continue;
			p = argv[i];
		} else {
			p = ifa->ifa_name;
			/* -1 means we're discovering against a specific
			 * interface, but we still need the below rules
			 * to apply. */
			if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
				continue;
		}
		for (i = 0; i < ctx->ifdc; i++)
			if (!fnmatch(ctx->ifdv[i], p, 0))
				break;
		if (i < ctx->ifdc)
			continue;
		for (i = 0; i < ctx->ifac; i++)
			if (!fnmatch(ctx->ifav[i], p, 0))
				break;
		if (ctx->ifac && i == ctx->ifac)
			continue;

		if (if_vimaster(ifa->ifa_name) == 1) {
			syslog(argc ? LOG_ERR : LOG_DEBUG,
				"%s: is a Virtual Interface Master, skipping",
				ifa->ifa_name);
			continue;
		}

		ifp = calloc(1, sizeof(*ifp));
		if (ifp == NULL) {
			syslog(LOG_ERR, "%s: %m", __func__);
			break;
		}
		ifp->ctx = ctx;
		strlcpy(ifp->name, p, sizeof(ifp->name));
		ifp->flags = ifa->ifa_flags;

		/* Bring the interface up if not already */
		if (!(ifp->flags & IFF_UP)
#ifdef SIOCGIFMEDIA
		    && carrier_status(ifp) != LINK_UNKNOWN
#endif
		   )
		{
			if (up_interface(ifp) == 0)
				ctx->options |= DHCPCD_WAITUP;
			else
				syslog(LOG_ERR, "%s: up_interface: %m",
				    ifp->name);
		}

		sdl_type = 0;
		/* Don't allow loopback unless explicit */
		if (ifp->flags & IFF_LOOPBACK) {
			if (argc == 0 && ctx->ifac == 0) {
				free_interface(ifp);
				continue;
			}
		} else if (ifa->ifa_addr != NULL) {
#ifdef AF_LINK
			sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;

#ifdef IFLR_ACTIVE
			/* We need to check for active address */
			strlcpy(iflr.iflr_name, ifp->name,
			    sizeof(iflr.iflr_name));
			memcpy(&iflr.addr, ifa->ifa_addr,
			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
			iflr.flags = IFLR_PREFIX;
			iflr.prefixlen = sdl->sdl_alen * NBBY;
			if (ioctl(s_link, SIOCGLIFADDR, &iflr) == -1 ||
			    !(iflr.flags & IFLR_ACTIVE))
			{
				free_interface(ifp);
				continue;
			}
#endif

			ifp->index = sdl->sdl_index;
			sdl_type = sdl->sdl_type;
			switch(sdl->sdl_type) {
			case IFT_BRIDGE: /* FALLTHROUGH */
			case IFT_L2VLAN: /* FALLTHOUGH */
			case IFT_L3IPVLAN: /* FALLTHROUGH */
			case IFT_ETHER:
				ifp->family = ARPHRD_ETHER;
				break;
			case IFT_IEEE1394:
				ifp->family = ARPHRD_IEEE1394;
				break;
#ifdef IFT_INFINIBAND
			case IFT_INFINIBAND:
				ifp->family = ARPHRD_INFINIBAND;
				break;
#endif
			}
			ifp->hwlen = sdl->sdl_alen;
#ifndef CLLADDR
#  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
#endif
			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
#elif AF_PACKET
			sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
			ifp->index = sll->sll_ifindex;
			ifp->family = sdl_type = sll->sll_hatype;
			ifp->hwlen = sll->sll_halen;
			if (ifp->hwlen != 0)
				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
#endif
		}
#ifdef __linux__
		/* PPP addresses on Linux don't have hardware addresses */
		else
			ifp->index = if_nametoindex(ifp->name);
#endif

		/* We only work on ethernet by default */
		if (!(ifp->flags & IFF_POINTOPOINT) &&
		    ifp->family != ARPHRD_ETHER)
		{
			if (argc == 0 && ctx->ifac == 0) {
				free_interface(ifp);
				continue;
			}
			switch (ifp->family) {
			case ARPHRD_IEEE1394: /* FALLTHROUGH */
			case ARPHRD_INFINIBAND:
				/* We don't warn for supported families */
				break;
			default:
				syslog(LOG_WARNING,
				    "%s: unsupported interface type %.2x"
				    ", falling back to ethernet",
				    ifp->name, sdl_type);
				ifp->family = ARPHRD_ETHER;
				break;
			}
		}

		/* Handle any platform init for the interface */
		if (if_init(ifp) == -1) {
			syslog(LOG_ERR, "%s: if_init: %m", p);
			free_interface(ifp);
			continue;
		}

		/* Ensure that the MTU is big enough for DHCP */
		if (get_mtu(ifp->name) < MTU_MIN &&
		    set_mtu(ifp->name, MTU_MIN) == -1)
		{
			syslog(LOG_ERR, "%s: set_mtu: %m", p);
			free_interface(ifp);
			continue;
		}

#ifdef SIOCGIFPRIORITY
		/* Respect the interface priority */
		memset(&ifr, 0, sizeof(ifr));
		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
		if (ioctl(s_inet, SIOCGIFPRIORITY, &ifr) == 0)
			ifp->metric = ifr.ifr_metric;
#else
		/* We reserve the 100 range for virtual interfaces, if and when
		 * we can work them out. */
		ifp->metric = 200 + ifp->index;
		if (getifssid(ifp->name, ifp->ssid) != -1) {
			ifp->wireless = 1;
			ifp->metric += 100;
		}
#endif

		TAILQ_INSERT_TAIL(ifs, ifp, next);
	}

	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
		if (ifa->ifa_addr == NULL)
			continue;
		switch(ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			addr = (const struct sockaddr_in *)
			    (void *)ifa->ifa_addr;
			net = (const struct sockaddr_in *)
			    (void *)ifa->ifa_netmask;
			if (ifa->ifa_flags & IFF_POINTOPOINT)
				dst = (const struct sockaddr_in *)
				    (void *)ifa->ifa_dstaddr;
			else
				dst = NULL;
			ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
				&addr->sin_addr,
				&net->sin_addr,
				dst ? &dst->sin_addr : NULL);
			break;
#endif
#ifdef INET6
		case AF_INET6:
			sin6 = (const struct sockaddr_in6 *)
			    (void *)ifa->ifa_addr;
			ifa_flags = in6_addr_flags(ifa->ifa_name,
			    &sin6->sin6_addr);
			if (ifa_flags != -1)
				ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
				    ifa->ifa_name,
				    &sin6->sin6_addr, ifa_flags);
			break;
#endif
		}
	}

	freeifaddrs(ifaddrs);

#ifdef SIOCGIFPRIORITY
	close(s_inet);
#endif
#ifdef IFLR_ACTIVE
	close(s_link);
#endif

	return ifs;
}
bool AgereET131x::start(IOService* provider)
{
	//IOLog("%s::%s()\n",getName(),__FUNCTION__);
    bool success = false;
	
	if (super::start(provider) == false) {
		IOLog("supper::start failed.\n");
		return false;
	}
	pciDevice = OSDynamicCast(IOPCIDevice, provider);
	if (pciDevice == NULL)
		return false;
	
	
	pciDevice->retain();
	if (pciDevice->open(this) == false)
		return false;

	adapter.VendorID = pciDevice->configRead16(kIOPCIConfigVendorID);
	adapter.DeviceID = pciDevice->configRead16(kIOPCIConfigDeviceID);
	adapter.SubVendorID = pciDevice->configRead16(kIOPCIConfigSubSystemVendorID);
	adapter.SubSystemID = pciDevice->configRead16(kIOPCIConfigSubSystemID);
	adapter.RevisionID = pciDevice->configRead8(kIOPCIConfigRevisionID);
	
	
	// adapter.hw.device_id will be used later
	IOLog("vendor:device: 0x%x:0x%x.\n", adapter.VendorID, adapter.DeviceID);
	
	do {
		if(!initEventSources(provider)){
			break;
		}
		
		csrPCIAddress = pciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);
		if (csrPCIAddress == NULL) {
			IOLog("csrPCIAddress.\n");
			break;
		}
		adapter.CSRAddress = (ADDRESS_MAP_t*)csrPCIAddress->getVirtualAddress();
		
		adapter.netdev = this;
		adapter.pdev = pciDevice;
		
		set_mtu( ETH_DATA_LEN );

		// Init PCI config space:
        if ( false == initPCIConfigSpace() )
            break;
		
		
		// reset the hardware with the new settings
		addNetworkMedium(kIOMediumEthernetAuto, 0, MEDIUM_INDEX_AUTO);
		addNetworkMedium(kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex,
						 10 * MBit, MEDIUM_INDEX_10HD);
		addNetworkMedium(kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex,
						 10 * MBit, MEDIUM_INDEX_10FD);
		addNetworkMedium(kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex,
						 100 * MBit, MEDIUM_INDEX_100HD);
		addNetworkMedium(kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex,
						 100 * MBit, MEDIUM_INDEX_100FD);
		addNetworkMedium(kIOMediumEthernet1000BaseT | kIOMediumOptionFullDuplex,
						 1000 * MBit, MEDIUM_INDEX_1000FD);
		
		if (!publishMediumDictionary(mediumDict)) {
			IOLog("publishMediumDictionary.\n");
			break;
		}
		
		success = true;
	} while(false);
	
	// Close our provider, it will be re-opened on demand when
	// our enable() is called by a client.
	pciDevice->close(this);

	do {
		if ( false == success )
			break;
		
		// Allocate and attach an IOEthernetInterface instance.
		if (attachInterface((IONetworkInterface **)(&netif), true) == false) {
			IOLog("Failed to attach data link layer.\n");
			break;
		}
		
		success = true;
	} while(false);

	if(false == success){
		adapter_memory_free();
	}
	return success;
}
void windows_tap_adapter::open(const std::string& _name, boost::system::error_code& ec)
{
    ec = boost::system::error_code();

    if (_name.empty())
    {
        open(ec);

        return;
    }

    PIP_ADAPTER_INFO piai = NULL;
    ULONG size = 0;
    DWORD status;

    status = GetAdaptersInfo(piai, &size);

    if (status != ERROR_BUFFER_OVERFLOW)
    {
        ec = boost::system::error_code(status, boost::system::system_category());

        return;
    }

    std::vector<unsigned char> piai_data(size);
    piai = reinterpret_cast<PIP_ADAPTER_INFO>(&piai_data[0]);

    status = GetAdaptersInfo(piai, &size);

    if (status != ERROR_SUCCESS)
    {
        ec = boost::system::error_code(status, boost::system::system_category());

        return;
    }

    piai_data.resize(size);

    try
    {
        const guid_pair_type adapter = find_tap_adapter_by_guid(_name);

        for (PIP_ADAPTER_INFO pi = piai; pi; pi = pi->Next)
        {
            if (adapter.first == std::string(pi->AdapterName))
            {
                const HANDLE handle = CreateFileA(
                                          (USERMODEDEVICEDIR + adapter.first + TAPSUFFIX).c_str(),
                                          GENERIC_READ | GENERIC_WRITE,
                                          0,
                                          0,
                                          OPEN_EXISTING,
                                          FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
                                          0
                                      );

                if (handle == INVALID_HANDLE_VALUE)
                {
                    ec = boost::system::error_code(::GetLastError(), boost::system::system_category());

                    return;
                }

                if (descriptor().assign(handle, ec))
                {
                    return;
                }

                set_name(adapter.first);
                m_display_name = adapter.second;
                m_interface_index = pi->Index;

                if (::ConvertInterfaceIndexToLuid(m_interface_index, &m_interface_luid) != NO_ERROR)
                {
                    ec = boost::system::error_code(::GetLastError(), boost::system::system_category());

                    return;
                }

                if (pi->AddressLength != ethernet_address().data().size())
                {
                    if (close(ec))
                    {
                        return;
                    }

                    ec = make_error_code(asiotap_error::no_ethernet_address);

                    return;
                }

                osi::ethernet_address _ethernet_address;
                std::memcpy(_ethernet_address.data().data(), pi->Address, pi->AddressLength);
                set_ethernet_address(_ethernet_address);

                DWORD read_mtu;
                DWORD len;

                if (!DeviceIoControl(descriptor().native_handle(), TAP_IOCTL_GET_MTU, &read_mtu, sizeof(read_mtu), &read_mtu, sizeof(read_mtu), &len, NULL))
                {
                    ec = boost::system::error_code(::GetLastError(), boost::system::system_category());

                    return;
                }

                set_mtu(static_cast<size_t>(read_mtu));

                break;
            }
        }
    }
    catch (const boost::system::system_error& ex)
    {
        ec = ex.code();

        return;
    }

    if (!is_open())
    {
        ec = make_error_code(asiotap_error::no_such_tap_adapter);
    }
}
Example #14
0
int configure (const options_t *options, interface_t *iface,
	       const dhcp_t *dhcp)
{
  route_t *route = NULL;
  route_t *new_route = NULL;
  route_t *old_route = NULL;
  struct hostent *he = NULL;
  char newhostname[HOSTNAME_MAX_LEN] = {0};
  char curhostname[HOSTNAME_MAX_LEN] = {0};
  char *dname = NULL;
  int dnamel = 0;

  if (! options || ! iface || ! dhcp)
    return -1;

  /* Remove old routes
     Always do this as the interface may have >1 address not added by us
     so the routes we added may still exist */
  if (iface->previous_routes)
    {
      for (route = iface->previous_routes; route; route = route->next)
	if (route->destination.s_addr || options->dogateway)
	  {
	    int have = 0;
	    if (dhcp->address.s_addr != 0)
	      for (new_route = dhcp->routes; new_route; new_route = new_route->next)
		if (new_route->destination.s_addr == route->destination.s_addr
		    && new_route->netmask.s_addr == route->netmask.s_addr
		    && new_route->gateway.s_addr == route->gateway.s_addr)
		  {
		    have = 1;
		    break;
		  }
	    if (! have)
	      del_route (iface->name, route->destination, route->netmask,
			 route->gateway, options->metric);
	  }
    }

  /* If we don't have an address, then return */
  if (dhcp->address.s_addr == 0)
    {
      if (iface->previous_routes)
	{
	  free_route (iface->previous_routes);
	  iface->previous_routes = NULL;
	}

      /* Only reset things if we had set them before */
      if (iface->previous_address.s_addr != 0)
	{
	  del_address (iface->name, iface->previous_address,
		       iface->previous_netmask);
	  memset (&iface->previous_address, 0, sizeof (struct in_addr));
	  memset (&iface->previous_netmask, 0, sizeof (struct in_addr));

	  restore_resolv (iface->name);

	  /* we currently don't have a resolvconf style programs for ntp/nis */
	  exec_script (options->script, iface->infofile, "down");
	}
      return 0;
    }

  if (dhcp->mtu)
    set_mtu (iface->name, dhcp->mtu);

  if (add_address (iface->name, dhcp->address, dhcp->netmask,
		   dhcp->broadcast) < 0 && errno != EEXIST)
    return -1;

  /* Now delete the old address if different */
  if (iface->previous_address.s_addr != dhcp->address.s_addr
      && iface->previous_address.s_addr != 0)
    del_address (iface->name, iface->previous_address, iface->previous_netmask);

#ifdef __linux__
  /* On linux, we need to change the subnet route to have our metric. */
  if (iface->previous_address.s_addr != dhcp->address.s_addr
      && options->metric > 0 && dhcp->netmask.s_addr != INADDR_BROADCAST)
    {
      struct in_addr td;
      struct in_addr tg;
      memset (&td, 0, sizeof (td));
      memset (&tg, 0, sizeof (tg));
      td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
      add_route (iface->name, td, dhcp->netmask, tg, options->metric);
      del_route (iface->name, td, dhcp->netmask, tg, 0);
    }
#endif

  /* Remember added routes */
  if (dhcp->routes)
    {
      route_t *new_routes = NULL;
      int remember;

      for (route = dhcp->routes; route; route = route->next)
	{
	  /* Don't set default routes if not asked to */
	  if (route->destination.s_addr == 0 && route->netmask.s_addr == 0
	      && ! options->dogateway)
	    continue;

	  remember = add_route (iface->name, route->destination,
				route->netmask,  route->gateway,
				options->metric);
	  /* If we failed to add the route, we may have already added it
	     ourselves. If so, remember it again. */
	  if (remember < 0)
	    for (old_route = iface->previous_routes; old_route;
		 old_route = old_route->next)
	      if (old_route->destination.s_addr == route->destination.s_addr
		  && old_route->netmask.s_addr == route->netmask.s_addr
		  && old_route->gateway.s_addr == route->gateway.s_addr)
		{
		  remember = 1;
		  break;
		}

	  if (remember >= 0)
	    {
	      if (! new_routes)
		{
		  new_routes = xmalloc (sizeof (route_t));
		  memset (new_routes, 0, sizeof (route_t));
		  new_route = new_routes;
		}
	      else
		{
		  new_route->next = xmalloc (sizeof (route_t));
		  new_route = new_route->next;
		}
	      memcpy (new_route, route, sizeof (route_t));
	      new_route -> next = NULL;
	    }
	}

      if (iface->previous_routes)
	free_route (iface->previous_routes);

      iface->previous_routes = new_routes;
    }

  if (options->dodns && dhcp->dnsservers)
    make_resolv(iface->name, dhcp);
  else
    logger (LOG_DEBUG, "no dns information to write");

  if (options->dontp && dhcp->ntpservers)
    make_ntp(iface->name, dhcp);

  if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
    make_nis(iface->name, dhcp);

  /* Now we have made a resolv.conf we can obtain a hostname if we need one */
  if (options->dohostname && ! dhcp->hostname)
    {
      he = gethostbyaddr (inet_ntoa (dhcp->address),
			  sizeof (struct in_addr), AF_INET);
      if (he)
	{
	  dname = he->h_name;
	  while (*dname > 32)
	    dname++;
	  dnamel = dname - he->h_name;
	  memcpy (newhostname, he->h_name, dnamel);
	  newhostname[dnamel] = 0;
	}
    }

  gethostname (curhostname, sizeof (curhostname));

  if (options->dohostname
      || strlen (curhostname) == 0
      || strcmp (curhostname, "(none)") == 0
      || strcmp (curhostname, "localhost") == 0)
    {
      if (dhcp->hostname)
	strcpy (newhostname, dhcp->hostname); 

      if (*newhostname)
	{
	  logger (LOG_INFO, "setting hostname to `%s'", newhostname);
	  sethostname (newhostname, strlen (newhostname));
	}
    }

  write_info (iface, dhcp, options);

  if (iface->previous_address.s_addr != dhcp->address.s_addr ||
      iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
    {
      memcpy (&iface->previous_address,
	      &dhcp->address, sizeof (struct in_addr));
      memcpy (&iface->previous_netmask,
	      &dhcp->netmask, sizeof (struct in_addr));
      exec_script (options->script, iface->infofile, "new");
    }
  else
    exec_script (options->script, iface->infofile, "up");

  return 0;
}