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; }
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); }
/* 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; }
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; }
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; }
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; }
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; }
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); }
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); } }
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; }