📄 dhcpcboot.c
字号:
newEvent.length); if (status != newEvent.length) /* Error reading message - ignore. */ continue; msgAlign (&dhcpcMsgIn, &rbuf.buf [DHCPC_OFF]); option = (char *) pickup_opt (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp), _DHCP_MSGTYPE_TAG); if (option != NULL) { if (*OPTBODY (option) == DHCPNAK) {#ifdef DHCPC_DEBUG logMsg ("Got DHCPNAK from server\n", 0, 0, 0, 0, 0, 0);#endif option = (char *)pickup_opt (dhcpcMsgIn.dhcp, DHCPLEN(dhcpcMsgIn.udp), _DHCP_ERRMSG_TAG);#ifdef DHCPC_DEBUG if (option != NULL && nvttostr (OPTBODY (option), errmsg, (int)DHCPOPTLEN (option)) == 0) logMsg ("DHCPNAK contains the error message \"%s\"\n", (int)errmsg, 0, 0, 0, 0, 0);#endif clean_param (dhcpcBootParam); free (dhcpcBootParam); dhcpcBootParam = NULL; return (INIT); /* Next state is INIT */ } else { /* Fill in host requirements defaults. */ dhcpcBootDefaultsSet (&tmpparam); if (*OPTBODY (option) == DHCPACK && dhcp_msgtoparam (dhcpcMsgIn.dhcp, DHCPLEN (dhcpcMsgIn.udp), &tmpparam) == OK) { if ( (arpans = arp_check (&tmpparam.yiaddr)) == OK) { merge_param (dhcpcBootParam, &tmpparam); *dhcpcBootParam = tmpparam; dhcpcBootParam->lease_origin = dhcpcInitEpoch;#ifdef DHCPC_DEBUG inet_ntoa_b (dhcpcBootParam->yiaddr, newAddr); logMsg ("Got DHCPACK (IP = %s, duration = %d secs)\n", (int)newAddr, dhcpcBootParam->lease_duration, 0, 0, 0, 0);#endif dhcpcBindType = DHCP_NATIVE; return (BOUND); } else { /* make dhcp_declinfo and send DHCPDECLINE */ set_declinfo (&tmp_reqspec, errmsg, arpans); dhcp_decline (&tmp_reqspec); clean_param (dhcpcBootParam); free (dhcpcBootParam); dhcpcBootParam = NULL;#ifdef DHCPC_DEBUG logMsg ( "Received unacceptable DHCPACK. Entering INIT state.\n", 0, 0, 0, 0, 0, 0);#endif return(INIT); } } } } }#ifdef DHCPC_DEBUG if (status == DHCP_TIMEOUT) logMsg ("Retransmission from requesting state.\n", 0, 0, 0, 0, 0, 0);#endif retry++; return(REQUESTING); }/********************************************************************************* pickup_opt - extract an option from a DHCP message** This routine searches the fields in a DHCP message for the provided options* tag. If the file and sname message fields are overloaded with options,* they are searched as well. The search order is:** options field -> 'file' field -> 'sname' field** RETURNS: Pointer to first occurrence of option, or NULL if not found.** ERRNO: N/A** SEE ALSO: RFC 1533** NOMANUAL*/LOCAL char * pickup_opt ( struct dhcp * msg, /* Incoming message copied to structure */ int msglen, /* Length of message */ char tag /* RFC 1533 tag for desired option */ ) { BOOL sname_is_opt = FALSE; BOOL file_is_opt = FALSE; int i = 0; char * opt = NULL; char * found = NULL; /* search option field. */ opt = &msg->options[MAGIC_LEN]; for (i = 0; i < msglen - DFLTDHCPLEN + DFLTOPTLEN - MAGIC_LEN; i++) { if (*(opt + i) == tag) { found = (opt + i); break; } else if (*(opt + i) == _DHCP_END_TAG) break; else if (*(opt + i) == _DHCP_OPT_OVERLOAD_TAG) { i += 2 ; if (*(opt + i) == 1) file_is_opt = TRUE; else if (*(opt + i) == 2) sname_is_opt = TRUE; else if (*(opt + i) == 3) file_is_opt = sname_is_opt = TRUE; continue; } else if (*(opt + i) == _DHCP_PAD_TAG) continue; else i += *(u_char *)(opt + i + 1) + 1; } if (found != NULL) return (found); /* If necessary, search file field. */ if (file_is_opt) { opt = msg->file; for (i = 0; i < sizeof (msg->file); i++) { if (*(opt + i) == _DHCP_PAD_TAG) continue; else if (*(opt + i) == _DHCP_END_TAG) break; else if (*(opt + i) == tag) { found = (opt + i); break; } else i += *(u_char *)(opt + i + 1) + 1; } if (found != NULL) return (found); } /* If necessary, search sname field. */ if (sname_is_opt) { opt = msg->sname; for (i = 0; i < sizeof (msg->sname); i++) { if (*(opt + i) == _DHCP_PAD_TAG) continue; else if (*(opt + i) == _DHCP_END_TAG) break; else if (*(opt + i) == tag) { found = (opt + i); break; } else i += *(u_char *)(opt + i + 1) + 1; } if (found != NULL) return(found); } return(NULL); }/********************************************************************************* generate_xid - generate a transaction identifier ** This routine forms a transaction identifier for outgoing messages from the* DHCP client. It is called from multiple locations after the initialization * routines have retrieved the network interface hardware address.** RETURNS: 32-bit transaction identifier in host byte order. ** ERRNO: N/A** NOMANUAL*/LOCAL long generate_xid ( void ) { time_t current = 0; u_short result1 = 0; u_short result2 = 0; u_short tmp[6]; bcopy (dhcpcIntface.haddr.haddr, (char *)tmp, 6); time (¤t); result1 = checksum (tmp, 6); result2 = checksum ( (u_short *)¤t, 2); return ( (result1 << 16) + result2); }/********************************************************************************* msgAlign - set the buffer pointers to access message components** This routine sets the pointers in the given message descriptor* structure to access the various components of a received DHCP* message. It is used internally by the Ethernet input hooks and* the state machine routines.** RETURNS: N/A** ERRNO: N/A** NOMANUAL*/void msgAlign ( struct msg *rmsg, /* Components of received message */ char *rbuf /* Received Ethernet packet */ ) { rmsg->ether = (struct ether_header *) rbuf; rmsg->ip = (struct ip *) &rbuf[ETHERHL]; if ( (ntohs (rmsg->ip->ip_off) & 0x1fff) == 0 && ntohs (rmsg->ip->ip_len) >= DFLTBOOTPLEN + UDPHL + IPHL) {#if BSD<44 rmsg->udp = (struct udphdr *)&rbuf [ETHERHL + (rmsg->ip->ip_v_hl & 0xf) * WORD]; rmsg->dhcp = (struct dhcp *)&rbuf [ETHERHL + (rmsg->ip->ip_v_hl & 0xf) * WORD + UDPHL];#else rmsg->udp = (struct udphdr *) &rbuf [ETHERHL + rmsg->ip->ip_hl * WORD]; rmsg->dhcp = (struct dhcp *) &rbuf [ETHERHL + rmsg->ip->ip_hl * WORD + UDPHL];#endif } else { rmsg->udp = NULL; rmsg->dhcp = NULL; } return; }/********************************************************************************* udp_cksum - calculate the UDP header checksum** This routine calculates the checksum for the given UDP pseudo-header and* additional bytes of data contained in the provided buffer, interpreted* as unsigned shorts in network byte order.** RETURNS: Value of calculated checksum, or 0xffff instead of 0.** ERRNO: N/A** NOMANUAL*/LOCAL u_short udp_cksum ( struct ps_udph *pUdpPh, /* UDP pseudo-header */ char *buf, /* Additional data (received UDP header) */ int n /* Length of provided buffer */ ) { u_long sum = 0; u_short * tmp = NULL; u_short result; int i = 0; unsigned char pad [2]; tmp = (u_short *) pUdpPh; for (i = 0; i < 6; i++) { sum += *tmp++; } tmp = (u_short *)buf; while (n > 1) { sum += *tmp++; n -= sizeof (u_short); } if (n == 1) /* n % 2 == 1, so padding is needed */ { pad [0] = *tmp; pad [1] = 0; tmp = (u_short *)pad; sum += *tmp; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); result = (u_short) ~sum; if (result == 0) result = 0xffff; return (result); }/********************************************************************************* arp_check - use ARP to check if given address is in use** This routine broadcasts an ARP request and waits for a reply to determine if* an IP address offered by a DHCP server is already in use.** RETURNS: ERROR if ARP indicates client in use, or OK otherwise.** ERRNO: N/A** NOMANUAL*/LOCAL int arp_check ( struct in_addr *target ) { int i = 0; long tmp; char inbuf [ETHERHL + sizeof (struct ether_arp)]; struct ether_header *sether = NULL; struct ether_arp *sarp = NULL; STATUS result; bzero (inbuf, ETHERHL + sizeof (struct ether_arp)); sether = (struct ether_header *) inbuf; sarp = (struct ether_arp *) &inbuf [ETHERHL]; sarp->arp_hrd = htons (ARPHRD_ETHER); sarp->arp_pro = htons (ETHERTYPE_IP); sarp->arp_hln = 6; sarp->arp_pln = 4; sarp->arp_op = htons (ARPOP_REQUEST); /* Set sender H/W address to your address for ARP requests. (RFC 1541). */ for (i = 0; i < 6; i++) { sarp->arp_sha[i] = sether->ether_shost[i] = dhcpcIntface.haddr.haddr[i]; sarp->arp_tha[i] = 0; sether->ether_dhost[i] = 0xff; } /* Set sender IP address to 0 for ARP requests as per RFC 1541. */ tmp = 0; bcopy ( (char *)&tmp, (char *)sarp->arp_spa, sarp->arp_pln); bcopy ( (char *)&target->s_addr, (char *)sarp->arp_tpa, sarp->arp_pln); sether->ether_type = ETHERTYPE_ARP; if (etherOutput (dhcpcIntface.iface, sether, (char *)sarp, sizeof (struct ether_arp)) == ERROR) { return (OK); /* it is harmless to return 0 */ } /* Set sender address to our address for checking by etherHook. */ bcopy ( (char *)&target->s_addr, (char *)dhcpcBootArpSpa, sarp->arp_pln); /* Create signalling semaphore. */ dhcpcBootArpEventSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY); if (dhcpcBootArpEventSem == NULL) {#ifdef DHCPC_DEBUG logMsg ("Error creating ARP semaphore.\n", 0, 0, 0, 0, 0, 0);#endif return (OK); } /* Wait up to one-half a second for a reply. If none received, return 0. */ if (muxDevExists (dhcpcDevice.name, dhcpcDevice.unit)) etherInputHookAdd (dhcpcBootArpInputHook, dhcpcDevice.name, dhcpcDevice.unit); else etherInputHookAdd (dhcpcBootArpInputHook, NULL, dhcpcDevice.unit); result = semTake (dhcpcBootArpEventSem, sysClkRateGet() / 2); result = ERROR; semDelete (dhcpcBootArpEventSem); if (muxDevExists (dhcpcDevice.name, dhcpcDevice.unit)) etherInputHookDelete (dhcpcBootArpInputHook, dhcpcDevice.name, dhcpcDevice.unit); else etherInputHookDelete (dhcpcBootArpInputHook, NULL, dhcpcDevice.unit); /* Restore previous input hook. */ if (result == ERROR) /* Error indicates timeout occurred. */ return (OK); else /* ARP reply received - duplicate IP address. */ return (ERROR); }#ifdef DHCPC_DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -