📄 dhcp_prot.c
字号:
else { timeout_random++; pstate->secs = ptv->tv_sec * 2 - 2 + (timeout_random & 3); pstate->countdown = 2; // later fast retries ptv->tv_sec = 0; } return (pstate->secs < DHCP_TIMEOUT_IN_SEC); // If longer, too many tries...}// ------------------------------------------------------------------------// Lease expiry and alarms to notify itstatic cyg_alarm_t alarm_function;static void alarm_function(cyg_handle_t alarm, cyg_addrword_t data){ struct dhcp_lease *lease = (struct dhcp_lease *)data;#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("alarm_function\n");#endif lease->which |= lease->next; if ( lease->needs_attention ) cyg_semaphore_post( lease->needs_attention ); // Step the lease on into its next state of being alarmed ;-) if ( lease->next & DHCP_LEASE_EX ) { cyg_alarm_disable( alarm ); } else if ( lease->next & DHCP_LEASE_T2 ) { lease->next = DHCP_LEASE_EX; cyg_alarm_initialize( lease->alarm, lease->expiry, 0 ); cyg_alarm_enable( lease->alarm ); } else if ( lease->next & DHCP_LEASE_T1 ) { lease->next = DHCP_LEASE_T2; cyg_alarm_initialize( lease->alarm, lease->t2, 0 ); cyg_alarm_enable( lease->alarm ); }}static inline void no_lease( struct dhcp_lease *lease ){ if ( lease->alarm ) { // Already set: delete this. cyg_alarm_disable( lease->alarm ); cyg_alarm_delete( lease->alarm ); lease->alarm = 0; }}static inline void new_lease( struct bootp *bootp, struct dhcp_lease *lease ){ cyg_tick_count_t now = cyg_current_time(); cyg_tick_count_t then; cyg_uint32 tag = 0; cyg_uint32 expiry_then; cyg_resolution_t resolution = cyg_clock_get_resolution(cyg_real_time_clock()); cyg_handle_t h; unsigned int length;#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("new_lease \n");#endif // Silence any jabbering from past lease on this interface no_lease( lease ); lease->which = lease->next = 0; cyg_clock_to_counter(cyg_real_time_clock(), &h); cyg_alarm_create( h, alarm_function, (cyg_addrword_t)lease, &lease->alarm, &lease->alarm_obj ); // extract the lease time and scale it &c to now. length = sizeof(tag); if (!get_bootp_option( bootp, TAG_DHCP_LEASE_TIME, &tag )) tag = 0xffffffff; if ( 0xffffffff == tag ) { lease->expiry = 0xffffffffffffffff; lease->t2 = 0xffffffffffffffff; lease->t1 = 0xffffffffffffffff; return ; // it's an infinite lease, hurrah! } then = (cyg_uint64)(ntohl(tag)); expiry_then = then; then *= 1000000000; // into nS - we know there is room in a tick_count_t then = (then / resolution.dividend) * resolution.divisor; // into system ticks lease->expiry = now + then; length = sizeof(tag); if (get_bootp_option( bootp, TAG_DHCP_REBIND_TIME, &tag )) then = (cyg_uint64)(ntohl(tag)); else then = expiry_then - expiry_then / 4; then *= 1000000000; // into nS - we know there is room in a tick_count_t then = (then / resolution.dividend) * resolution.divisor; // into system ticks lease->t2 = now + then; length = sizeof(tag); if (get_bootp_option( bootp, TAG_DHCP_RENEWAL_TIME, &tag )) then = (cyg_uint64)(ntohl(tag)); else then = expiry_then / 2; then *= 1000000000; // into nS - we know there is room in a tick_count_t then = (then / resolution.dividend) * resolution.divisor; // into system ticks lease->t1 = now + then;#if 0 // for testing this mechanism lease->expiry = now + 5000; // 1000 here makes for failure in the DHCP test lease->t2 = now + 3500; lease->t1 = now + 2500;#endif#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("new_lease:\n"); diag_printf(" expiry = %d\n", lease->expiry); diag_printf(" t1 = %d\n", lease->t1); diag_printf(" t2 = %d\n", lease->t2);#endif lease->next = DHCP_LEASE_T1; cyg_alarm_initialize( lease->alarm, lease->t1, 0 ); cyg_alarm_enable( lease->alarm );}// ------------------------------------------------------------------------// Set all the tags we want to use when sending a packet.// This has expanded to a large, explicit set to interwork better// with a variety of DHCP servers.static void set_default_dhcp_tags( struct bootp *xmit ){ // Explicitly request full set of params that are default for LINUX // dhcp servers, but not default for others. This is rather arbitrary, // but it preserves behaviour for people using those servers. // Perhaps configury of this set will be needed in future? // // Here's the set: static cyg_uint8 req_list[] = {#ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE ,#else TAG_DHCP_SERVER_ID , // DHCP server id: 10.16.19.66 TAG_DHCP_LEASE_TIME , // DHCP time 51: 60 TAG_DHCP_RENEWAL_TIME , // DHCP time 58: 30 TAG_DHCP_REBIND_TIME , // DHCP time 59: 52 TAG_SUBNET_MASK , // subnet mask: 255.255.255.0 // TAG_GATEWAY , // gateway: 10.16.19.66 TAG_DOMAIN_SERVER , // domain server: 10.16.19.66 TAG_DOMAIN_NAME , // domain name: hmt10.cambridge.redhat.com TAG_IP_BROADCAST , // IP broadcast: 10.16.19.255#endif#ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL ,#endif }; if ( req_list[0] ) // So that one may easily turn it all off by configury set_variable_tag( xmit, TAG_DHCP_PARM_REQ_LIST, &req_list[0], sizeof( req_list ) ); // Explicitly specify our max message size.#ifndef BP_MAXPKTSZ#define BP_MAXPKTSZ 364#endif set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MAXPKTSZ, 2 );}#ifndef ORIG_DHCP_CODE/* this code is intended to overcome the failure of socket interface to sent to a a specific interface. we cannot use the "default route " because it harms routing in the LAN *//* buffer type definition */typedef struct { unsigned int key; unsigned int totalLen;#ifdef GATEWAY unsigned int interface;/*0 - LAN ;1 - WAN*/#endif unsigned char data[1600];} dsQ_LlcData_t;/* buff allocation function type definition */extern dsQ_LlcData_t *ds_GetLlcDataBuf(void);/* driver send function type definition */extern int dsQ_LlcDataWriteNoBlock(dsQ_LlcData_t *txbd);/* IP header format */typedef struct dhcp_iphdr { char verhdrlen; char service; unsigned short len; unsigned short ident; unsigned short frags; char ttl; char protocol; unsigned short chksum; cyg_uint32 saddr; cyg_uint32 daddr;}P_ip_hdr_dhcp;/* IP checksum calculation */unsigned short dhcp_ipchksum(register unsigned short *ip, register int len){ unsigned long sum = 0; len >>= 1; while (len--) { sum += *(ip++); if (sum > 0xFFFF) sum -= 0xFFFF; } return((~sum) & 0x0000FFFF);}int dhcp_send_broadcast_to_driver( cyg_uint32 datalen, cyg_uint8 *data_PTR, cyg_uint8 *my_mac_addr){ /* build the packet and send it directly to WAN driver */ dsQ_LlcData_t *txbd; P_ip_hdr_dhcp *ip_hdr_PTR; cyg_uint16 *u16_PTR;#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("\n dhcp_send_broadcast_to_driver\n");#endif /*allocate application buffer */ txbd = ds_GetLlcDataBuf(); if (txbd == NULL) { return -1;#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("dhcp_send_broadcast_to_driver: failed to alloc buffer\n");#endif } /* fill buffer parameters */ txbd->key = 0; /* key 0 mean no notification on Transmit completed */ #ifdef GATEWAY txbd->interface = 1; /* WAN eth interface */#endif txbd->totalLen = datalen + 42; /* Eth size = 14 , ip size 20 , udp size= 8 = 42*/ /* copy dhcp data */ memcpy(txbd->data + 42, data_PTR, datalen); /* clear header areas */ memset(txbd->data, 0,42);/* build IP UDP and ETHernet */ /* ========= */ /* build UDP */ /* ========= */ /* src port 68 */ txbd->data[35] = 68; /* dest port 67 */ txbd->data[37] = 67; /* length */ u16_PTR =(cyg_uint16 *) &(txbd->data[38]); datalen += 8;/* data size including UDP length */ *u16_PTR = htons(datalen); /* leave checksum to 0 */ /* ========= */ /* build IP */ /* ========= */ ip_hdr_PTR = (P_ip_hdr_dhcp *)(txbd->data + 14); ip_hdr_PTR->verhdrlen = 0x45; ip_hdr_PTR->service = 0; datalen += 20;/* add ip header size to data size */ ip_hdr_PTR->len = htons(datalen); ip_hdr_PTR->ident = 0x7179;// ip_hdr_PTR->frags = htons(0x4000); ip_hdr_PTR->ttl = 1; ip_hdr_PTR->protocol = 17;/* UDP */ /* dest IP 255.255.255.255 - limited broadcast not doe directly due to problems in ARM arc which wrote it aligned to 2 bytes below*/ memset(txbd->data + 30 ,0xff, 4); ip_hdr_PTR->chksum = dhcp_ipchksum((unsigned short *)ip_hdr_PTR, 20); /* ========= */ /* build Eth */ /* ========= */ txbd->data[12] = 0x08; /* ip Ethertype 0800 */ /* src Eth address */ memcpy( (txbd->data + 6),my_mac_addr, 6); /* dest addr Eth address */ u16_PTR = (cyg_uint16 *)(txbd->data); u16_PTR[0] = 0xFFFF; u16_PTR[1] = 0xFFFF; u16_PTR[2] = 0xFFFF; /*try to send the frame to the bridge task*/ dsQ_LlcDataWriteNoBlock(txbd); return 1;}#endif// ------------------------------------------------------------------------// the DHCP state machine - this does all the workintdo_dhcp(const char *intf, struct bootp *res, cyg_uint8 *pstate, struct dhcp_lease *lease){ struct ifreq ifr; struct sockaddr_in cli_addr, broadcast_addr, server_addr, rx_addr; int s, addrlen; unsigned char mincookie[] = {99, 130, 83, 99, 255} ; struct timeval tv; struct timeout_state timeout_scratch; cyg_uint8 oldstate = *pstate; cyg_uint8 msgtype = 0, seen_bootp_reply = 0; unsigned int length; cyg_uint32 xid;#define CHECK_XID() ( /* and other details */ \ received->bp_xid != xid || /* not the same transaction */ \ received->bp_htype != xmit->bp_htype || /* not the same ESA type */ \ received->bp_hlen != xmit->bp_hlen || /* not the same length */ \ bcmp( &received->bp_chaddr, &xmit->bp_chaddr, xmit->bp_hlen ) \ ) // IMPORTANT: xmit is the same as res throughout this; *received is a // scratch buffer for reception; its contents are always copied to res // when we are happy with them. So we always transmit from the // existing state. struct bootp rx_local; struct bootp *received = &rx_local; struct bootp *xmit = res; struct bootp xmit2; int xlen; // First, get a socket on the interface in question. But Zeroth, if // needs be, bring it to the half-up broadcast only state if needs be.#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("do_dhcp: on interface %s\n",intf);#endif if ( DHCPSTATE_INIT == oldstate || DHCPSTATE_FAILED == oldstate || 0 == oldstate ) { // either explicit init state or the beginning of time or retry *pstate = DHCPSTATE_INIT; } if ( ! bring_half_up( intf, &ifr,&s, *pstate ) ){ if(s >= 0) close(s); return false; } memset((char *) &cli_addr, 0, sizeof(cli_addr)); cli_addr.sin_family = AF_INET; cli_addr.sin_len = sizeof(cli_addr); cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); cli_addr.sin_port = htons(IPPORT_BOOTPC); memset((char *) &broadcast_addr, 0, sizeof(broadcast_addr)); broadcast_addr.sin_family = AF_INET; broadcast_addr.sin_len = sizeof(broadcast_addr); broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); broadcast_addr.sin_port = htons(IPPORT_BOOTPS); memset((char *) &server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_len = sizeof(server_addr); server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // overwrite later server_addr.sin_port = htons(IPPORT_BOOTPS); if (bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) { perror("bind error"); close(s); return false; } // Now, we can launch into the DHCP state machine. I think this will // be the neatest way to do it; it returns from within the switch arms // when all is well, or utterly failed. reset_timeout( &tv, &timeout_scratch );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -