/* ValidDHCPOffer(): * Target issued the DISCOVER, the incoming packet is the server's * OFFER reply. If the offer contains the vendor specific * VS_PPADHCPSRVR option and the string within that * option is correct, then accept the offer; by issuing a request. */ ValidDHCPOffer(struct dhcphdr *dhdr) { uchar *op, *op1; op = op1 = 0; op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1); if(op1) { op = DhcpGetOption(VS_PPADHCPSRVR,op1+2); } if(op) { if(!strncmp(op+2,PPADHCPSRVR_STR,sizeof(PPADHCPSRVR_STR)-1)) { return(1); } } return(0); }
/*! * \brief Send DHCP datagram and wait for a specified answer. * * \param slen Length of message to send. * \param xtype Expected response type. * * \return The number of data bytes received, 0 on timeout or -1 in * case of a failure. */ int DhcpTransact(u_short slen, u_char xtype) { u_char type; u_char retry; int rlen = 0; for (retry = 0; retry < 3; ) { /* * Send a message, if nothing has been received yet. */ if (rlen == 0) { if (UdpOutput(INADDR_BROADCAST, DHCP_SERVERPORT, DHCP_CLIENTPORT, slen) < 0) { /* Transmit failure, must be a NIC problem. Give up. */ return -1; } } /* * Do a retry on timouts or failures. A receive failures may be * caused by a hardware failure or a bad frame. */ if ((rlen = UdpInput(DHCP_CLIENTPORT, 5000)) <= 0) { retry++; continue; } /* * Check if the response contains the expected ID and * message type. */ if (rframe.u.bootp.bp_xid == sframe.u.bootp.bp_xid && DhcpGetOption(DHCPOPT_MSGTYPE, &type, 1) == 1 && type == xtype) { DEBUG("[DHCP]"); break; } } return rlen; }
/*! * \brief Query any DHCP server on the local net. * * On success, this routine will fill some global * variables: * * - my_ip * - server_ip * - bootfile * - my_netmask * * \return 0 on success, -1 otherwise. */ int DhcpQuery(void) { BOOTPHDR *bp; u_short slen; u_char i; u_long sid; register u_char *cp; /* * Nothing to do if we got a fixed IP address. */ if (confnet.cdn_cip_addr) { confnet.cdn_ip_addr = confnet.cdn_cip_addr; return 0; } confnet.cdn_ip_addr = 0; /* * Setup bootp message. */ bp = &sframe.u.bootp; bp->bp_op = 1; bp->bp_xid = *((u_long *)&confnet.cdn_mac[2]); bp->bp_htype = 1; bp->bp_hlen = sizeof(confnet.cdn_mac); memcpy_(bp->bp_chaddr, confnet.cdn_mac, 6); /* * Add DHCP option for discover message. */ bp->bp_cookie = 0x63538263; i = DHCP_DISCOVER; DhcpSetOption(bp->bp_options, DHCPOPT_MSGTYPE, &i, 1); /* * Send DHCP discover and wait for any response. */ slen = sizeof(BOOTPHDR) - sizeof(sframe.u.bootp.bp_options) + 4; if (DhcpTransact(slen, DHCP_OFFER) <= 0) { return -1; } /* * Get the server ID option. */ DhcpGetOption(DHCPOPT_SID, &sid, 4); /* * Reuse the bootp structure and add DHCP options for request message. */ DEBUGULONG(rframe.u.bootp.bp_yiaddr); i = DHCP_REQUEST; cp = DhcpSetOption(bp->bp_options, DHCPOPT_MSGTYPE, &i, 1); cp = DhcpSetOption(cp, DHCPOPT_REQUESTIP, (u_char *)&rframe.u.bootp.bp_yiaddr, 4); DhcpSetOption(cp, DHCPOPT_SID, (u_char *)&sid, 4); /* * Send DHCP request and wait for ACK. */ slen = sizeof(BOOTPHDR) - sizeof(sframe.u.bootp.bp_options) + 16; if (DhcpTransact(slen, DHCP_ACK) <= 0) { return -1; } /* * Retrieve local IP, bootp server IP, bootfile name and netmask. */ confnet.cdn_ip_addr = rframe.u.bootp.bp_yiaddr; confboot.cb_tftp_ip = rframe.u.bootp.bp_siaddr; for (cp = rframe.u.bootp.bp_file, i = 0; *cp && i < sizeof(confboot.cb_image) - 1; cp++, i++) { confboot.cb_image[i] = *cp; } confboot.cb_image[i] = 0; DhcpGetOption(DHCPOPT_NETMASK, &confnet.cdn_ip_mask, 4); #if 0 /* * I'd say that tftpd32 is buggy, because it sends siaddr * set to zero. This hack will fix it. */ if (confboot.cb_tftp_ip == 0) confboot.cb_tftp_ip = rframe.ip_hdr.ip_src; #endif return 0; }
/* processDHCP(): * Actually this is processBOOTP, but we call it processDHCP here so that * the same code in enetcore.c can be used to call either function (depending * on what has been configured into the uMon build). */ int processDHCP(struct ether_header *ehdr,ushort size) { char getbootfile = 0; struct ip *ihdr; struct Udphdr *uhdr; struct bootphdr *bhdr; ulong ip, temp_ip, cookie; uchar buf[16], bootsrvrip[16], *op; ihdr = (struct ip *)(ehdr + 1); uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); bhdr = (struct bootphdr *)(uhdr+1); /* Verify incoming transaction id matches the previous outgoing value: */ if (xidCheck((char *)&bhdr->transaction_id,1) < 0) return(-1); /* If bootfile is nonzero, store it into BOOTFILE shell var: */ if (bhdr->bootfile[0]) getbootfile++; /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */ memcpy((char *)&temp_ip,(char *)&bhdr->server_ip,4); if (temp_ip) getbootfile++; IpToString(temp_ip,(char *)bootsrvrip); /* Assign IP address loaded in "your_ip" to the IPADD shell var: */ memcpy((char *)BinIpAddr,(char *)&bhdr->your_ip,4); memcpy((char *)&temp_ip,(char *)&bhdr->your_ip,4); printf("IP: %s\n",IpToString(temp_ip,(char *)buf)); /* If STANDARD_MAGIC_COOKIE exists, then process options... */ memcpy((char *)&cookie,(char *)bhdr->vsa,4); if (cookie == ecl(STANDARD_MAGIC_COOKIE)) { /* Assign subnet mask option to NETMASK shell var (if found): */ op = DhcpGetOption(DHCPOPT_SUBNETMASK,&bhdr->vsa[4]); if (op) { memcpy((char *)BinNetMask,(char *)op+2,4); memcpy((char *)&ip,(char *)op+2,4); printf("NETMASK: %s\n",IpToString(ip,(char *)buf)); } /* Assign first router option to GIPADD shell var (if found): */ /* (the router option can have multiple entries, and they are */ /* supposed to be in order of preference, so use the first one) */ op = DhcpGetOption(DHCPOPT_ROUTER,&bhdr->vsa[4]); if (op) { memcpy((char *)BinGipAddr,(char *)op+2,4); memcpy((char *)&ip,(char *)op+2,4); printf("GIPADD: %s\n",IpToString(ip,(char *)buf)); } } /* Call loadBootFile() which will then kick off a tftp client * transfer if both BOOTFILE and BOOTSRVR shell variables are * loaded; otherwise, we are done. */ /* If the bootp server gave us the bootfile and boot server IP, * then call loadBootFile()... */ if (getbootfile == 2) loadBootFile((char *)bhdr->bootfile,(char *)bootsrvrip); else DHCPState = BOOTPSTATE_COMPLETE; return(0); }