//========================================================================== // // Adapted from network_support.c // // Misc network support functions // $Id: network_support.c,v 1.7 2006/07/18 04:58:44 gellatly Exp $ //========================================================================== // BOOTP support #include #undef _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include // for 'sprintf()' #include #include #include #include #include #include "mydev.h" #define CYGHWR_NET_DRIVER_ETH0_BOOTP_SHOW 1 struct bootp eth0_bootp_data; cyg_bool_t eth0_up = false; const char *eth0_name = "eth0"; #define _string(s) #s #define string(s) _string(s) #ifndef CYGPKG_LIBC_STDIO #define perror(s) diag_printf(#s ": %s\n", strerror(errno)) #endif #ifdef CYGPKG_NET_NLOOP #if 0 < CYGPKG_NET_NLOOP // // Initialize loopback interface ---------- Added by sorin@netappi.com // cyg_bool_t init_loopback_interface(int lo) { struct sockaddr_in *addrp; struct ifreq ifr; int s; int one = 1; struct ecos_rtentry route; struct in_addr netmask, gateway; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return false; } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) { perror("setsockopt"); close(s); return false; } addrp = (struct sockaddr_in *) &ifr.ifr_addr; memset(addrp, 0, sizeof(*addrp)); addrp->sin_family = AF_INET; addrp->sin_len = sizeof(*addrp); addrp->sin_port = 0; // Make an address 127.0..1 to manage multiple loopback ifs. // (There is normally only 1, so it's the standard 127.0.0.1) addrp->sin_addr.s_addr = htonl((0x100 * lo) + INADDR_LOOPBACK) ; #if CYGPKG_NET_NLOOP > 1 // Init the one we were told to sprintf(ifr.ifr_name, "lo%d", lo); #else strcpy(ifr.ifr_name, "lo0"); #endif if (ioctl(s, SIOCSIFADDR, &ifr)) { perror("SIOCIFADDR"); close(s); return false; } #if 1 < CYGPKG_NET_NLOOP // We cheat to make different nets for multiple loopback devs addrp->sin_addr.s_addr = netmask.s_addr = htonl(IN_CLASSC_NET); #else // addrp->sin_addr.s_addr = netmask.s_addr = htonl(IN_CLASSA_NET); #endif if (ioctl(s, SIOCSIFNETMASK, &ifr)) { perror("SIOCSIFNETMASK"); return false; } ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; if (ioctl(s, SIOCSIFFLAGS, &ifr)) { perror("SIOCSIFFLAGS"); close(s); return false; } gateway.s_addr = htonl(INADDR_LOOPBACK); memset(&route, 0, sizeof(route)); addrp->sin_family = AF_INET; addrp->sin_len = sizeof(*addrp); addrp->sin_port = 0; addrp->sin_addr.s_addr = htonl((0x100 * lo) + INADDR_LOOPBACK) & netmask.s_addr; memcpy(&route.rt_dst, addrp, sizeof(*addrp)); addrp->sin_addr = netmask; memcpy(&route.rt_genmask, addrp, sizeof(*addrp)); addrp->sin_addr = gateway; memcpy(&route.rt_gateway, addrp, sizeof(*addrp)); route.rt_dev = ifr.ifr_name; route.rt_flags = RTF_UP|RTF_GATEWAY; route.rt_metric = 0; if (ioctl(s, SIOCADDRT, &route)) { diag_printf("Route - dst: %s", inet_ntoa(((struct sockaddr_in *)&route.rt_dst)->sin_addr)); diag_printf(", mask: %s", inet_ntoa(((struct sockaddr_in *)&route.rt_genmask)->sin_addr)); diag_printf(", gateway: %s\n", inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); if (errno != EEXIST) { perror("SIOCADDRT 3"); close(s); return false; } } close(s); return true; } #endif #endif // // Internal function which builds up a fake BOOTP database for // an interface. // static unsigned char * add_tag(unsigned char *vp, unsigned char tag, void *val, int len) { int i; unsigned char *xp = (unsigned char *)val; *vp++ = tag; *vp++ = len; for (i = 0; i < len; i++) { *vp++ = *xp++; } return vp; } static void build_bootp_struct(struct bootp *bp, const char * if_name, unsigned char addrs_ip[], unsigned char addrs_netmask[], unsigned char addrs_gateway[], unsigned char addrs_DNSsv1[], unsigned char addrs_DNSsv2[], unsigned char addrs_NTPsv1[], unsigned char addrs_NTPsv2[]){ int i, s; in_addr_t addr[2]; unsigned char *vp,ucAddrBuf[4]; unsigned char cookie[] = VM_RFC1048; struct ifreq ifr; bzero(bp, sizeof(struct bootp)); bp->bp_op = BOOTREPLY; bp->bp_htype = HTYPE_ETHERNET; bp->bp_hlen = 6; // Query the hardware address for (i = 0; i < bp->bp_hlen; i++) { bp->bp_chaddr[i] = 0xFF; // Unknown } s = socket(AF_INET, SOCK_DGRAM, 0); if (s >= 0) { strcpy(ifr.ifr_name, if_name); if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0) { bcopy(ifr.ifr_hwaddr.sa_data, bp->bp_chaddr, bp->bp_hlen); } close(s); } // Fill in the provided IP addresses memcpy(&bp->bp_ciaddr.s_addr,addrs_ip,4); memcpy(&bp->bp_yiaddr.s_addr,addrs_ip,4); memcpy(&bp->bp_siaddr.s_addr,addrs_DNSsv1,4); memcpy(&bp->bp_giaddr.s_addr,addrs_gateway,4); for(i=0;i<4;++i) ucAddrBuf[i]=addrs_ip[i] | (0xFF ^ addrs_netmask[i]); //Make the broadcast addr vp = &bp->bp_vend[0]; bcopy(&cookie, vp, sizeof(cookie)); vp += sizeof(cookie); vp = add_tag(vp, TAG_SUBNET_MASK, addrs_netmask, sizeof(in_addr_t)); vp = add_tag(vp, TAG_IP_BROADCAST, ucAddrBuf, sizeof(in_addr_t)); vp = add_tag(vp, TAG_GATEWAY, addrs_gateway, sizeof(in_addr_t)); i=0; if(*(long*)addrs_DNSsv1) memcpy(&addr[i++],addrs_DNSsv1, sizeof(in_addr_t)); if(*(long*)addrs_DNSsv2) memcpy(&addr[i++],addrs_DNSsv2, sizeof(in_addr_t)); if(i) vp = add_tag(vp, TAG_DOMAIN_SERVER, addr, (i==2)? sizeof(in_addr_t)+sizeof(in_addr_t):sizeof(in_addr_t)); i=0; if(*(long*)addrs_NTPsv1) memcpy(&addr[i++],addrs_NTPsv1, sizeof(in_addr_t)); if(*(long*)addrs_NTPsv2) memcpy(&addr[i++],addrs_NTPsv2, sizeof(in_addr_t)); if(i) vp = add_tag(vp, TAG_NTP_SERVER, addr, (i==2)? sizeof(in_addr_t)+sizeof(in_addr_t):sizeof(in_addr_t)); *vp = TAG_END; } void del_eth0( void ) { int s; struct ifreq ifr; s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0){ diag_printf("socket: %d\n",s); return; } memset(&ifr,0,sizeof( struct ifreq ) ); strcpy(ifr.ifr_name, "eth0"); if( ioctl( s, SIOCGIFADDR, &ifr ) == -1 ){ diag_printf("Impossible to obtain an IP address of '%s' because '%s'",ifr.ifr_name,strerror(errno)); } else { if( ioctl( s, SIOCDIFADDR, &ifr ) != 0 ){ diag_printf("Impossible to remove IP address '%s' because '%s'",ifr.ifr_name,strerror(errno)); } } diag_printf("del_eth0 complete.\n"); close(s); } // // Initialize network interface[s] using BOOTP/DHCP // void init_all_network_interfaces(void) { static volatile int in_init_all_network_interfaces = 0; #ifdef CYGOPT_NET_IPV6_ROUTING_THREAD int rs_wait = 40; #endif cyg_scheduler_lock(); // Make this call idempotent while ( in_init_all_network_interfaces ) { // Another thread is doing this... cyg_scheduler_unlock(); cyg_thread_delay( 10 ); cyg_scheduler_lock(); } in_init_all_network_interfaces = 1; cyg_scheduler_unlock(); if(eth0_up && ((MCB.icIPUseDHCP == 3) || ! MCB.icIPUseDHCP)){ // DHCP is coming up or not running del_eth0(); // Delete the old static address first } // Deal with DHCP start/stop first then static addressing if(MCB.icIPUseDHCP == 3){ // Change in state of DHCP to UP // Perform a complete initialization, using BOOTP/DHCP eth0_up = true; eth0_dhcpstate = 0; // Says that initialization is external to dhcp if (!do_dhcp(eth0_name, ð0_bootp_data, ð0_dhcpstate, ð0_lease)){ diag_printf("BOOTP/DHCP failed on eth0\n"); eth0_up = false; } }else if(MCB.icIPUseDHCP == 2){ // Change in state of DHCP to down if ( eth0_up ) { // eth0_dhcpstate = 0; // Says that initialization is external to dhcp do_dhcp_down_net(eth0_name, ð0_bootp_data, ð0_dhcpstate, ð0_lease); } eth0_up = true; } if(!(MCB.icIPUseDHCP & 1)){ // DHCP is down so set static address //Build the bootp data so gateway & mask tags are set correctly build_bootp_struct(ð0_bootp_data, eth0_name, MCB.ucSNMPIPV4Addr, MCB.ucSNMPIPV4Mask, MCB.ucSNMPIPV4Gate, MCB.ucIPV4DNSServ1Addr, MCB.ucIPV4DNSServ2Addr, MCB.ucIPV4NTPServ1Addr, MCB.ucIPV4NTPServ2Addr); eth0_up = true; } #ifdef CYGHWR_NET_DRIVER_ETH0_BOOTP_SHOW //Show what HDCP or static addresses have been setup show_bootp(eth0_name, ð0_bootp_data); #endif if (eth0_up) { if (!init_net(eth0_name, ð0_bootp_data)) { diag_printf("Network initialization failed for eth0\n"); eth0_up = false; } #ifdef CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX if (!init_net_IPv6(eth0_name, ð0_bootp_data, string(CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX))) { diag_printf("Static IPv6 network initialization failed for eth0\n"); eth0_up = false; // ??? } #endif } if(MCB.icIPUseDHCP == 3) dhcp_start_dhcp_mgt_thread(); #ifdef CYGOPT_NET_IPV6_ROUTING_THREAD ipv6_start_routing_thread(); // Wait for router solicit process to happen. while (rs_wait-- && !cyg_net_get_ipv6_advrouter(NULL)) { cyg_thread_delay(10); } if (rs_wait == 0 ) { diag_printf("No router solicit received\n"); } else { // Give Duplicate Address Detection time to work cyg_thread_delay(200); } #endif #ifdef CYGDAT_NS_DNS_DOMAINNAME_NAME { const char buf[] = "mycompany.com"; int len = strlen(buf); setdomainname(buf,len); } #endif // Open the monitor to other threads. in_init_all_network_interfaces = 0; } // EOF network_support.c