📄 dhcp_prot.c
字号:
*pstate = DHCPSTATE_RENEWING; break; } // Check for well-formed packet with correct termination (not truncated) length = dhcp_size( received );#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf( "---------DHCPSTATE_RENEW_RECV received:\n" ); if ( length <= 0 ) diag_printf( "WARNING! malformed or truncated packet\n" ); diag_printf( "...rx_addr is family %d, addr %08x, port %d\n", rx_addr.sin_family, rx_addr.sin_addr.s_addr, rx_addr.sin_port ); show_bootp( intf, received );#endif if ( length <= 0 ) break; if ( CHECK_XID() ) // not the same transaction; break; // listen again... if ( 0 == received->bp_siaddr.s_addr ) { // then fill in from the options... length = sizeof(received->bp_siaddr.s_addr); get_bootp_option( received, TAG_DHCP_SERVER_ID, &received->bp_siaddr.s_addr); } // check it was a DHCP reply length = sizeof(msgtype); if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) ) { if ( DHCPACK == msgtype // Same offer? && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) { // we like the packet, so reset the timeout for next time reset_timeout( &tv, &timeout_scratch ); // Record the new lease and set up timers &c new_lease( received, lease ); *pstate = DHCPSTATE_BOUND; break; } if ( DHCPNAK == msgtype ) { // we're bounced! *pstate = DHCPSTATE_NOTBOUND; // So quit out. break; } // otherwise it's something else, maybe another offer. // Just listen again, which implicitly discards it. } break; case DHCPSTATE_REBINDING: // Just send what you got with a DHCPREQUEST in the message type. // Then wait for an ACK. This one is BROADCAST. // Fill in the BOOTP request - DHCPREQUEST packet xmit->bp_xid = xid; xmit->bp_op = BOOTREQUEST; xmit->bp_flags = htons(0); // no BROADCAST FLAG // Use the *client* address here: xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr; set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 ); // These must not be set in this context unset_tag( xmit, TAG_DHCP_REQ_IP ); unset_tag( xmit, TAG_DHCP_SERVER_ID ); // Set all the tags we want to use when sending a packet set_default_dhcp_tags( xmit );#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf( "---------DHCPSTATE_REBINDING sending:\n" ); show_bootp( intf, xmit );#endif // Send back a [modified] copy. Note that some fields are explicitly // cleared, as per the RFC. We need the copy because these fields are // still useful to us (and currently stored in the 'result' structure) xlen = dhcp_size_for_send( xmit ); bcopy( xmit, &xmit2, xlen ); xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0; xmit2.bp_hops = 0;#ifdef ORIG_DHCP_CODE if (sendto(s, &xmit2, xlen, 0, (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0)#else if(dhcp_send_broadcast_to_driver(xlen,(cyg_uint8 *) &xmit2,ifr.ifr_hwaddr.sa_data) < 0 )#endif { *pstate = DHCPSTATE_FAILED; break; } *pstate = DHCPSTATE_REBIND_RECV; break; case DHCPSTATE_REBIND_RECV: // wait for an ACK or a NACK - retry by going back to // DHCPSTATE_REBINDING; NACK means go to NOTBOUND. // No answer means just wait for expiry; we tried! setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); addrlen = sizeof(rx_addr); if (recvfrom(s, received, sizeof(struct bootp), 0, (struct sockaddr *)&rx_addr, &addrlen) < 0) { // No packet arrived // go to the next larger timeout and re-send: if ( ! next_timeout( &tv, &timeout_scratch ) ) { // If we timed out completely, just give up until EX // expires - retain the lease meanwhile. The normal // lease mechanism will invoke NOTBOUND state as and // when necessary. *pstate = DHCPSTATE_BOUND; break; } *pstate = DHCPSTATE_REBINDING; break; } // Check for well-formed packet with correct termination (not truncated) length = dhcp_size( received );#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf( "---------DHCPSTATE_REBIND_RECV received:\n" ); if ( length <= 0 ) diag_printf( "WARNING! malformed or truncated packet\n" ); diag_printf( "...rx_addr is family %d, addr %08x, port %d\n", rx_addr.sin_family, rx_addr.sin_addr.s_addr, rx_addr.sin_port ); show_bootp( intf, received );#endif if ( length <= 0 ) break; if ( CHECK_XID() ) // not the same transaction; break; // listen again... if ( 0 == received->bp_siaddr.s_addr ) { // then fill in from the options... //int length = sizeof(received->bp_siaddr.s_addr ); get_bootp_option( received, TAG_DHCP_SERVER_ID, &received->bp_siaddr.s_addr); } // check it was a DHCP reply length = sizeof(msgtype); if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) ) { if ( DHCPACK == msgtype // Same offer? && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) { // we like the packet, so reset the timeout for next time reset_timeout( &tv, &timeout_scratch ); // Record the new lease and set up timers &c new_lease( received, lease ); *pstate = DHCPSTATE_BOUND; break; } else if ( DHCPNAK == msgtype ) { // we're bounced! *pstate = DHCPSTATE_NOTBOUND; // So back the start of the rigmarole. break; } // otherwise it's something else, maybe another offer. // Just listen again, which implicitly discards it. } break; case DHCPSTATE_BOOTP_FALLBACK: // All done with socket close(s); // And no lease should have become active, but JIC no_lease( lease ); // Re-initialize the interface with the new state if ( DHCPSTATE_BOOTP_FALLBACK != oldstate ) { // Then need to go down and up do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used if ( 0 != oldstate ) { // Then not called from init_all_network_interfaces() // so we must initialize the interface ourselves if (!init_net(intf, res)) { do_dhcp_down_net( intf, res, pstate, lease ); *pstate = DHCPSTATE_FAILED; return false; } } } // Otherwise, nothing whatsoever to do... return true; case DHCPSTATE_NOTBOUND: // All done with socket close(s); // No lease active no_lease( lease ); // Leave interface up so app can tidy. return false; case DHCPSTATE_FAILED: // All done with socket close(s); // No lease active no_lease( lease ); // Unconditionally down the interface. do_dhcp_down_net( intf, res, &oldstate, lease ); return false; case DHCPSTATE_DO_RELEASE: // We have been forced here by external means, to release the // lease for graceful shutdown. // Just send what you got with a DHCPRELEASE in the message // type UNICAST straight to the server. No ACK. Then go to // NOTBOUND state. NEW_XID( xid ); xmit->bp_xid = xid; xmit->bp_op = BOOTREQUEST; xmit->bp_flags = htons(0); // no BROADCAST FLAG // Use the *client* address here: xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr; set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPRELEASE, 1 ); // Set unicast address to *server* server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf( "---------DHCPSTATE_DO_RELEASE sending:\n" ); diag_printf( "UNICAST to family %d, addr %08x, port %d\n", server_addr.sin_family, server_addr.sin_addr.s_addr, server_addr.sin_port ); show_bootp( intf, xmit );#endif // Send back a [modified] copy. Note that some fields are explicitly // cleared, as per the RFC. We need the copy because these fields are // still useful to us (and currently stored in the 'result' structure) xlen = dhcp_size_for_send( xmit ); bcopy( xmit, &xmit2, xlen ); xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0; xmit2.bp_hops = 0; if (sendto(s, &xmit2, xlen, 0, // UNICAST address of the server: (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { *pstate = DHCPSTATE_FAILED; break; } *pstate = DHCPSTATE_NOTBOUND; break; default: no_lease( lease ); close(s); return false; } } /* NOTREACHED */ return false;}// ------------------------------------------------------------------------// Bring an interface down, failed to initialize it or lease is expired// Also part of normal startup, bring down for proper reinitializationint do_dhcp_down_net(const char *intf, struct bootp *res, cyg_uint8 *pstate, struct dhcp_lease *lease){ struct sockaddr_in *addrp; struct ifreq ifr; int s;#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("do_dhcp_down_net: on interface %s, state %d\n",intf, *pstate);#endif // Ensure clean slate/* Nimrod S removed route_reinit call - cleans also LAN side configuration */// route_reinit(); // Force any existing routes to be forgotten s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return false; } addrp = (struct sockaddr_in *) &ifr.ifr_addr; // Remove any existing address if ( DHCPSTATE_FAILED == *pstate || DHCPSTATE_INIT == *pstate || 0 == *pstate ) { // it was configured for broadcast only, "half-up" memset(addrp, 0, sizeof(*addrp)); addrp->sin_family = AF_INET; addrp->sin_len = sizeof(*addrp); addrp->sin_port = 0; addrp->sin_addr.s_addr = INADDR_ANY; } else { // get the specific address that was used strcpy(ifr.ifr_name, intf); if (ioctl(s, SIOCGIFADDR, &ifr)) { perror("SIOCGIFADDR 1"); close(s); return false; } } strcpy(ifr.ifr_name, intf); if (ioctl(s, SIOCDIFADDR, &ifr)) { /* delete IF addr */ perror("SIOCDIFADDR1"); }#ifdef INET6 { int s6; s6 = socket(AF_INET6, SOCK_DGRAM, 0); if (s6 < 0) { perror("socket AF_INET6"); return false; } // Now delete the ipv6 addr strcpy(ifr.ifr_name, intf); if (ioctl(s6, SIOCGLIFADDR, &ifr)) { perror("SIOCGIFADDR_IN6 1"); return false; } strcpy(ifr.ifr_name, intf); if (ioctl(s6, SIOCDLIFADDR, &ifr)) { /* delete IF addr */ perror("SIOCDIFADDR_IN61"); } close(s6); }#endif /* IP6 */ // Shut down interface so it can be reinitialized ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING); if (ioctl(s, SIOCSIFFLAGS, &ifr)) { /* set ifnet flags */ perror("SIOCSIFFLAGS down"); close(s); return false; } // All done with socket close(s); if ( 0 != *pstate ) // preserve initial state *pstate = DHCPSTATE_INIT; return true;}// ------------------------------------------------------------------------// Release (relinquish) a leased address - if we have one - and bring down// the interface.int do_dhcp_release(const char *intf, struct bootp *res, cyg_uint8 *pstate, struct dhcp_lease *lease){#ifdef CYGDBG_NET_DHCP_CHATTER diag_printf("do_dhcp_release: on interface %s\n",intf);#endif if ( 0 != *pstate && DHCPSTATE_INIT != *pstate && DHCPSTATE_NOTBOUND != *pstate && DHCPSTATE_FAILED != *pstate && DHCPSTATE_BOOTP_FALLBACK != *pstate ) { *pstate = DHCPSTATE_DO_RELEASE; do_dhcp( intf, res, pstate, lease ); // to send the release packet cyg_thread_delay( 100 ); // to let it leave the building } return true;}// ------------------------------------------------------------------------#endif // CYGPKG_NET_DHCP// EOF dhcp_prot.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -