📄 ipconfig.c
字号:
drop_unlock: /* Show's over. Nothing to see here. */ spin_unlock(&ic_recv_lock);drop: /* Throw the packet out. */ kfree_skb(skb); return 0;}/* * Send RARP request packet over a single interface. */static void __init ic_rarp_send_if(struct ic_device *d){ struct net_device *dev = d->dev; arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, dev->dev_addr, dev->dev_addr);}#endif/* * DHCP/BOOTP support. */#ifdef IPCONFIG_BOOTPstruct bootp_pkt { /* BOOTP packet format */ struct iphdr iph; /* IP header */ struct udphdr udph; /* UDP header */ u8 op; /* 1=request, 2=reply */ u8 htype; /* HW address type */ u8 hlen; /* HW address length */ u8 hops; /* Used only by gateways */ __be32 xid; /* Transaction ID */ __be16 secs; /* Seconds since we started */ __be16 flags; /* Just what it says */ __be32 client_ip; /* Client's IP address if known */ __be32 your_ip; /* Assigned IP address */ __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ __be32 relay_ip; /* IP address of BOOTP relay */ u8 hw_addr[16]; /* Client's HW address */ u8 serv_name[64]; /* Server host name */ u8 boot_file[128]; /* Name of boot file */ u8 exten[312]; /* DHCP options / BOOTP vendor extensions */};/* packet ops */#define BOOTP_REQUEST 1#define BOOTP_REPLY 2/* DHCP message types */#define DHCPDISCOVER 1#define DHCPOFFER 2#define DHCPREQUEST 3#define DHCPDECLINE 4#define DHCPACK 5#define DHCPNAK 6#define DHCPRELEASE 7#define DHCPINFORM 8static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);static struct packet_type bootp_packet_type __initdata = { .type = __constant_htons(ETH_P_IP), .func = ic_bootp_recv,};/* * Initialize DHCP/BOOTP extension fields in the request. */static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 };#ifdef IPCONFIG_DHCPstatic void __initic_dhcp_init_options(u8 *options){ u8 mt = ((ic_servaddr == NONE) ? DHCPDISCOVER : DHCPREQUEST); u8 *e = options;#ifdef IPCONFIG_DEBUG printk("DHCP: Sending message type %d\n", mt);#endif memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ e += 4; *e++ = 53; /* DHCP message type */ *e++ = 1; *e++ = mt; if (mt == DHCPREQUEST) { *e++ = 54; /* Server ID (IP address) */ *e++ = 4; memcpy(e, &ic_servaddr, 4); e += 4; *e++ = 50; /* Requested IP address */ *e++ = 4; memcpy(e, &ic_myaddr, 4); e += 4; } /* always? */ { static const u8 ic_req_params[] = { 1, /* Subnet mask */ 3, /* Default gateway */ 6, /* DNS server */ 12, /* Host name */ 15, /* Domain name */ 17, /* Boot path */ 40, /* NIS domain name */ }; *e++ = 55; /* Parameter request list */ *e++ = sizeof(ic_req_params); memcpy(e, ic_req_params, sizeof(ic_req_params)); e += sizeof(ic_req_params); } *e++ = 255; /* End of the list */}#endif /* IPCONFIG_DHCP */static void __init ic_bootp_init_ext(u8 *e){ memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ e += 4; *e++ = 1; /* Subnet mask request */ *e++ = 4; e += 4; *e++ = 3; /* Default gateway request */ *e++ = 4; e += 4; *e++ = 5; /* Name server request */ *e++ = 8; e += 8; *e++ = 12; /* Host name request */ *e++ = 32; e += 32; *e++ = 40; /* NIS Domain name request */ *e++ = 32; e += 32; *e++ = 17; /* Boot path */ *e++ = 40; e += 40; *e++ = 57; /* set extension buffer size for reply */ *e++ = 2; *e++ = 1; /* 128+236+8+20+14, see dhcpd sources */ *e++ = 150; *e++ = 255; /* End of the list */}/* * Initialize the DHCP/BOOTP mechanism. */static inline void ic_bootp_init(void){ int i; for (i = 0; i < CONF_NAMESERVERS_MAX; i++) ic_nameservers[i] = NONE; dev_add_pack(&bootp_packet_type);}/* * DHCP/BOOTP cleanup. */static inline void ic_bootp_cleanup(void){ dev_remove_pack(&bootp_packet_type);}/* * Send DHCP/BOOTP request to single interface. */static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_diff){ struct net_device *dev = d->dev; struct sk_buff *skb; struct bootp_pkt *b; int hh_len = LL_RESERVED_SPACE(dev); struct iphdr *h; /* Allocate packet */ skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL); if (!skb) return; skb_reserve(skb, hh_len); b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt)); memset(b, 0, sizeof(struct bootp_pkt)); /* Construct IP header */ skb_reset_network_header(skb); h = ip_hdr(skb); h->version = 4; h->ihl = 5; h->tot_len = htons(sizeof(struct bootp_pkt)); h->frag_off = htons(IP_DF); h->ttl = 64; h->protocol = IPPROTO_UDP; h->daddr = htonl(INADDR_BROADCAST); h->check = ip_fast_csum((unsigned char *) h, h->ihl); /* Construct UDP header */ b->udph.source = htons(68); b->udph.dest = htons(67); b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr)); /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */ /* Construct DHCP/BOOTP header */ b->op = BOOTP_REQUEST; if (dev->type < 256) /* check for false types */ b->htype = dev->type; else if (dev->type == ARPHRD_IEEE802_TR) /* fix for token ring */ b->htype = ARPHRD_IEEE802; else if (dev->type == ARPHRD_FDDI) b->htype = ARPHRD_ETHER; else { printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name); b->htype = dev->type; /* can cause undefined behavior */ } b->hlen = dev->addr_len; b->your_ip = NONE; b->server_ip = NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies_diff / HZ); b->xid = d->xid; /* add DHCP options or BOOTP extensions */#ifdef IPCONFIG_DHCP if (ic_proto_enabled & IC_USE_DHCP) ic_dhcp_init_options(b->exten); else#endif ic_bootp_init_ext(b->exten); /* Chain packet down the line... */ skb->dev = dev; skb->protocol = htons(ETH_P_IP); if (dev_hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0 || dev_queue_xmit(skb) < 0) printk("E");}/* * Copy BOOTP-supplied string if not already set. */static int __init ic_bootp_string(char *dest, char *src, int len, int max){ if (!len) return 0; if (len > max-1) len = max-1; memcpy(dest, src, len); dest[len] = '\0'; return 1;}/* * Process BOOTP extensions. */static void __init ic_do_bootp_ext(u8 *ext){ u8 servers; int i;#ifdef IPCONFIG_DEBUG u8 *c; printk("DHCP/BOOTP: Got extension %d:",*ext); for (c=ext+2; c<ext+2+ext[1]; c++) printk(" %02x", *c); printk("\n");#endif switch (*ext++) { case 1: /* Subnet mask */ if (ic_netmask == NONE) memcpy(&ic_netmask, ext+1, 4); break; case 3: /* Default gateway */ if (ic_gateway == NONE) memcpy(&ic_gateway, ext+1, 4); break; case 6: /* DNS server */ servers= *ext/4; if (servers > CONF_NAMESERVERS_MAX) servers = CONF_NAMESERVERS_MAX; for (i = 0; i < servers; i++) { if (ic_nameservers[i] == NONE) memcpy(&ic_nameservers[i], ext+1+4*i, 4); } break; case 12: /* Host name */ ic_bootp_string(utsname()->nodename, ext+1, *ext, __NEW_UTS_LEN); ic_host_name_set = 1; break; case 15: /* Domain name (DNS) */ ic_bootp_string(ic_domain, ext+1, *ext, sizeof(ic_domain)); break; case 17: /* Root path */ if (!root_server_path[0]) ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); break; case 40: /* NIS Domain name (_not_ DNS) */ ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); break; }}/* * Receive BOOTP reply. */static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev){ struct bootp_pkt *b; struct iphdr *h; struct ic_device *d; int len, ext_len; if (dev->nd_net != &init_net) goto drop; /* Perform verifications before taking the lock. */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) return NET_RX_DROP; if (!pskb_may_pull(skb, sizeof(struct iphdr) + sizeof(struct udphdr))) goto drop; b = (struct bootp_pkt *)skb_network_header(skb); h = &b->iph; if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP) goto drop; /* Fragments are not supported */ if (h->frag_off & htons(IP_OFFSET | IP_MF)) { if (net_ratelimit()) printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented " "reply.\n"); goto drop; } if (skb->len < ntohs(h->tot_len)) goto drop; if (ip_fast_csum((char *) h, h->ihl)) goto drop; if (b->udph.source != htons(67) || b->udph.dest != htons(68)) goto drop; if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr)) goto drop; len = ntohs(b->udph.len) - sizeof(struct udphdr); ext_len = len - (sizeof(*b) - sizeof(struct iphdr) - sizeof(struct udphdr) - sizeof(b->exten)); if (ext_len < 0) goto drop; /* Ok the front looks good, make sure we can get at the rest. */ if (!pskb_may_pull(skb, skb->len)) goto drop; b = (struct bootp_pkt *)skb_network_header(skb); h = &b->iph; /* One reply at a time, please. */ spin_lock(&ic_recv_lock); /* If we already have a reply, just drop the packet */ if (ic_got_reply) goto drop_unlock; /* Find the ic_device that the packet arrived on */ d = ic_first_dev; while (d && d->dev != dev) d = d->next; if (!d) goto drop_unlock; /* should never happen */ /* Is it a reply to our BOOTP request? */ if (b->op != BOOTP_REPLY || b->xid != d->xid) { if (net_ratelimit()) printk(KERN_ERR "DHCP/BOOTP: Reply not for us, " "op[%x] xid[%x]\n", b->op, b->xid); goto drop_unlock; } /* Parse extensions */ if (ext_len >= 4 && !memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */ u8 *end = (u8 *) b + ntohs(b->iph.tot_len); u8 *ext;#ifdef IPCONFIG_DHCP if (ic_proto_enabled & IC_USE_DHCP) { __be32 server_id = NONE; int mt = 0; ext = &b->exten[4]; while (ext < end && *ext != 0xff) { u8 *opt = ext++; if (*opt == 0) /* Padding */ continue; ext += *ext + 1; if (ext >= end) break; switch (*opt) { case 53: /* Message type */ if (opt[1]) mt = opt[2]; break; case 54: /* Server ID (IP address) */ if (opt[1] >= 4) memcpy(&server_id, opt + 2, 4); break; } }#ifdef IPCONFIG_DEBUG printk("DHCP: Got message type %d\n", mt);#endif switch (mt) { case DHCPOFFER: /* While in the process of accepting one offer, * ignore all others. */ if (ic_myaddr != NONE) goto drop_unlock; /* Let's accept that offer. */ ic_myaddr = b->your_ip; ic_servaddr = server_id;#ifdef IPCONFIG_DEBUG printk("DHCP: Offered address %u.%u.%u.%u", NIPQUAD(ic_myaddr)); printk(" by server %u.%u.%u.%u\n", NIPQUAD(ic_servaddr));#endif /* The DHCP indicated server address takes * precedence over the bootp header one if * they are different. */ if ((server_id != NONE) && (b->server_ip != server_id)) b->server_ip = ic_servaddr; break; case DHCPACK: if (memcmp(dev->dev_addr, b->hw_addr, dev->addr_len) != 0) goto drop_unlock; /* Yeah! */ break; default: /* Urque. Forget it*/ ic_myaddr = NONE; ic_servaddr = NONE; goto drop_unlock; } ic_dhcp_msgtype = mt; }#endif /* IPCONFIG_DHCP */ ext = &b->exten[4]; while (ext < end && *ext != 0xff) { u8 *opt = ext++; if (*opt == 0) /* Padding */ continue; ext += *ext + 1; if (ext < end) ic_do_bootp_ext(opt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -