diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c index 7c2e531..653b7a8 100644 --- a/sbin/dhclient/bpf.c +++ b/sbin/dhclient/bpf.c @@ -87,7 +87,10 @@ if_register_bpf(struct interface_info *info, int flags) if (ioctl(sock, BIOCSETIF, info->ifp) < 0) error("Can't attach interface %s to bpf device %s: %m", info->name, filename); - + else + note("Attached interface %s to bpf device %s", + info->name, filename); + return (sock); } @@ -154,11 +177,11 @@ if_register_send(struct interface_info *info) p.bf_len = dhcp_bpf_wfilter_len; p.bf_insns = dhcp_bpf_wfilter; - if (dhcp_bpf_wfilter[7].k == 0x1fff) - dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); + //if (dhcp_bpf_wfilter[5].k == 0x1fff) + // dhcp_bpf_wfilter[5].k = htons(IP_MF|IP_OFFMASK); - if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0) - error("Can't install write filter program: %m"); + //if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0) + // error("Can't install write filter program: %m"); if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c index 4f234c7..1c85629 100644 --- a/sbin/dhclient/clparse.c +++ b/sbin/dhclient/clparse.c @@ -75,6 +75,9 @@ read_client_conf(void) memset(&top_level_config, 0, sizeof(top_level_config)); /* Set some defaults... */ + top_level_config.vlan_id = 0; + top_level_config.vlan_pcp = 0; + top_level_config.send_interface = NULL; top_level_config.timeout = 60; top_level_config.select_interval = 0; top_level_config.reboot_timeout = 10; @@ -186,6 +189,7 @@ read_client_leases(void) * RETRY number | * REBOOT number | * SELECT_TIMEOUT number | + * PRIORITY number | * SCRIPT string | * interface-declaration | * LEASE client-lease-statement | @@ -198,7 +202,8 @@ parse_client_statement(FILE *cfile, struct interface_info *ip, int token; char *val; struct option *option; - + time_t tmp; + switch (next_token(&val, cfile)) { case SEND: parse_option_decl(cfile, &config->send_options[0]); @@ -257,6 +262,17 @@ parse_client_statement(FILE *cfile, struct interface_info *ip, case REBOOT: parse_lease_time(cfile, &config->reboot_timeout); return; + case VLAN_PCP: + parse_lease_time(cfile, &tmp); + config->vlan_pcp = (int)tmp; + return; + case VLAN_ID: + parse_lease_time(cfile, &tmp); + config->vlan_id = (int)tmp; + return; + case SEND_INTERFACE: + config->send_interface = parse_string(cfile); + return; case BACKOFF_CUTOFF: parse_lease_time(cfile, &config->backoff_cutoff); return; diff --git a/sbin/dhclient/conflex.c b/sbin/dhclient/conflex.c index 3c8932d..4ee57cc 100644 --- a/sbin/dhclient/conflex.c +++ b/sbin/dhclient/conflex.c @@ -471,6 +470,8 @@ intern(char *atom, int dfv) case 's': if (!strcasecmp(atom + 1, "earch")) return (SEARCH); + if (!strcasecmp(atom + 1, "end-interface")) + return (SEND_INTERFACE); if (!strcasecmp(atom + 1, "tarts")) return (STARTS); if (!strcasecmp(atom + 1, "iaddr")) @@ -519,7 +520,11 @@ intern(char *atom, int dfv) case 'v': if (!strcasecmp(atom + 1, "endor-class")) return (VENDOR_CLASS); - break; + if (!strcasecmp(atom + 1, "lan-id")) + return (VLAN_ID); + if (!strcasecmp(atom + 1, "lan-pcp")) + return (VLAN_PCP); + break; case 'y': if (!strcasecmp(atom + 1, "iaddr")) return (YIADDR); diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h index 479753e..769ecf3 100644 --- a/sbin/dhclient/dhcpd.h +++ b/sbin/dhclient/dhcpd.h @@ -153,7 +153,10 @@ struct client_config { struct option_data send_options[256]; u_int8_t required_options[256]; u_int8_t requested_options[256]; - int requested_option_count; + int requested_option_count; + int vlan_id; + int vlan_pcp; + char *send_interface; time_t timeout; time_t initial_interval; time_t retry_interval; @@ -310,6 +313,7 @@ ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, /* dispatch.c */ extern void (*bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *); +void discover_interface(struct interface_info *, char *); void discover_interfaces(struct interface_info *); void reinitialize_interfaces(void); void dispatch(void); diff --git a/sbin/dhclient/dhctoken.h b/sbin/dhclient/dhctoken.h index 7b23242..db7780f 100644 --- a/sbin/dhclient/dhctoken.h +++ b/sbin/dhclient/dhctoken.h @@ -129,6 +129,9 @@ #define AUTHORITATIVE 333 #define TOKEN_NOT 334 #define ALWAYS_REPLY_RFC1048 335 +#define VLAN_ID 336 +#define VLAN_PCP 337 +#define SEND_INTERFACE 338 #define is_identifier(x) ((x) >= FIRST_TOKEN && \ (x) != STRING && \ diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c index 3ee0cf6..946cbd5 100644 --- a/sbin/dhclient/dispatch.c +++ b/sbin/dhclient/dispatch.c @@ -66,13 +66,15 @@ static int interface_status(struct interface_info *ifinfo); * register that interface with the network I/O software, figure out * what subnet it's on, and add it to the list of interfaces. */ -void -discover_interfaces(struct interface_info *iface) + void +discover_interface(struct interface_info *iface, char *name) { struct ifaddrs *ifap, *ifa; struct sockaddr_in foo; struct ifreq *tif; + strcpy(iface->name, name); + if (getifaddrs(&ifap) != 0) error("getifaddrs failed"); @@ -121,12 +124,47 @@ discover_interfaces(struct interface_info *iface) if (!iface->ifp) error("%s: not found", iface->name); + freeifaddrs(ifap); +} - /* Register the interface... */ + +void +discover_interfaces(struct interface_info *iface) +{ + char rname[256]; + char *sname = iface->client->config->send_interface; + + strcpy(rname, iface->name); /* Save original interface name */ + + /* Discover the receiving interface... */ + note("Discovering receive interface: %s", rname); + discover_interface(iface, rname); + + /* Register the receiving interface... */ + note(" Registering receive interface"); if_register_receive(iface); - if_register_send(iface); + note(" Adding protocol "); add_protocol(iface->name, iface->rfdesc, got_one, iface); - freeifaddrs(ifap); + + /* Register the sending interface... */ + if (sname != NULL) { + note("Discovering interface for sending: %s", sname); + free(iface->ifp); + iface->ifp = NULL; + discover_interface(iface, sname); + if_register_send(iface); + + /* Rediscover interface for receiving */ + note("Rediscovering receiving interface: %s", rname); + free(iface->ifp); + iface->ifp = NULL; + discover_interface(iface, rname); + } + else { + note(" Registering send interface"); + if_register_send(iface); + } + } void diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c index f79ca2f..bd68c34 100644 --- a/sbin/dhclient/packet.c +++ b/sbin/dhclient/packet.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #define ETHER_HEADER_SIZE (ETHER_ADDR_LEN * 2 + sizeof(u_int16_t)) @@ -93,18 +94,46 @@ assemble_hw_header(struct interface_info *interface, unsigned char *buf, int *bufix) { struct ether_header eh; - - memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); - if (interface->hw_address.hlen == sizeof(eh.ether_shost)) - memcpy(eh.ether_shost, interface->hw_address.haddr, - sizeof(eh.ether_shost)); - else - memset(eh.ether_shost, 0x00, sizeof(eh.ether_shost)); - - eh.ether_type = htons(ETHERTYPE_IP); - - memcpy(&buf[*bufix], &eh, ETHER_HEADER_SIZE); - *bufix += ETHER_HEADER_SIZE; + struct ether_vlan_header vh; + + int vlid = interface->client->config->vlan_id; + int vlpcp = interface->client->config->vlan_pcp; + + /* If vlan id is not default, use a 802.1q VLAN frame */ + if (vlid != 0) { + memset(vh.evl_dhost, 0xff, sizeof(vh.evl_dhost)); + if (interface->hw_address.hlen == sizeof(eh.ether_shost)) + memcpy(vh.evl_shost, interface->hw_address.haddr, + sizeof(vh.evl_shost)); + else + memset(vh.evl_shost, 0x00, sizeof(vh.evl_shost)); + + /* Set encapsulation header type to 802.1q */ + vh.evl_encap_proto = htons(ETHERTYPE_VLAN); + + /* Add VLAN tag */ + vh.evl_tag = htons(EVL_MAKETAG(vlid, vlpcp, 0)); /* VLID, PRI, CFI */ + + /* Set IP ethernet type tag */ + vh.evl_proto = htons(ETHERTYPE_IP); + + memcpy(&buf[*bufix], &vh, sizeof(vh)); + *bufix += sizeof(vh); + + } + else { + /* Standard IPv4 header */ + memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); + if (interface->hw_address.hlen == sizeof(eh.ether_shost)) + memcpy(eh.ether_shost, interface->hw_address.haddr, + sizeof(eh.ether_shost)); + else + memset(eh.ether_shost, 0x00, sizeof(eh.ether_shost)); + + eh.ether_type = htons(ETHERTYPE_IP); + memcpy(&buf[*bufix], &eh, ETHER_HEADER_SIZE); + *bufix += ETHER_HEADER_SIZE; + } } void diff --git a/sbin/dhclient/tables.c b/sbin/dhclient/tables.c index c7bac57..c46fbc2 100644 --- a/sbin/dhclient/tables.c +++ b/sbin/dhclient/tables.c @@ -335,6 +335,7 @@ unsigned char dhcp_option_default_priority_list[] = { DHO_DHCP_REBINDING_TIME, DHO_DHCP_CLASS_IDENTIFIER, DHO_DHCP_CLIENT_IDENTIFIER, + DHO_DHCP_USER_CLASS_ID, DHO_SUBNET_MASK, DHO_TIME_OFFSET, DHO_CLASSLESS_ROUTES,