Mercurial > flash_v2
diff packages/net/tcpip/current/src/lib/bootp_support.c @ 97:ced4577552cd ecos-sw-2000-06-06
Merge from eCos master repository on 2000-06-06-08:44:00-BST
| author | jlarmour |
|---|---|
| date | Tue, 06 Jun 2000 08:39:36 +0000 |
| parents | |
| children | 84e4bde58b26 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/net/tcpip/current/src/lib/bootp_support.c @@ -0,0 +1,406 @@ +//========================================================================== +// +// lib/bootp_support.c +// +// Minimal BOOTP functions +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//####BSDCOPYRIGHTBEGIN#### +// +// ------------------------------------------- +// +// Portions of this software may have been derived from OpenBSD or other sources, +// and are covered by the appropriate copyright disclaimers included herein. +// +// ------------------------------------------- +// +//####BSDCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 2000-01-10 +// Purpose: +// Description: +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +// BOOTP support + +#include <network.h> + +// This function sets up the interface it the simplest configuration. +// Just enough to broadcast a BOOTP request and get a response. +// It returns 'true' if a response was obtained. +cyg_bool_t +do_bootp(const char *intf, struct bootp *recv) +{ + struct sockaddr_in *addrp; + struct ifreq ifr; + struct sockaddr_in cli_addr, serv_addr, bootp_server_addr; + struct ecos_rtentry route; + int s, addrlen; + int one = 1; + struct bootp bootp_xmit; + unsigned char mincookie[] = {99,130,83,99,255} ; + struct timeval tv; + + // Ensure clean slate + route_reinit(); // Force any existing routes to be forgotten + + 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"); + 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; + addrp->sin_addr.s_addr = INADDR_ANY; + + strcpy(ifr.ifr_name, intf); + if (ioctl(s, SIOCSIFADDR, &ifr)) { + perror("SIOCSIFADDR"); + return false; + } + + if (ioctl(s, SIOCSIFNETMASK, &ifr)) { + perror("SIOCSIFNETMASK"); + return false; + } + + /* the broadcast address is 255.255.255.255 */ + memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr)); + if (ioctl(s, SIOCSIFBRDADDR, &ifr)) { + perror("SIOCSIFBRDADDR"); + return false; + } + + ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; + if (ioctl(s, SIOCSIFFLAGS, &ifr)) { + perror("SIOCSIFFLAGS"); + return false; + } + + if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { + perror("SIOCGIFHWADDR"); + return false; + } + + // Set up routing + /* the broadcast address is 255.255.255.255 */ + memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr)); + memset(&route, 0, sizeof(route)); + memcpy(&route.rt_gateway, addrp, sizeof(*addrp)); + + addrp->sin_family = AF_INET; + addrp->sin_port = 0; + addrp->sin_addr.s_addr = INADDR_ANY; + memcpy(&route.rt_dst, addrp, sizeof(*addrp)); + memcpy(&route.rt_genmask, 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)) { + if (errno != EEXIST) { + perror("SIOCADDRT 3"); + return false; + } + } + + memset((char *) &cli_addr, 0, sizeof(cli_addr)); + cli_addr.sin_family = AF_INET; + cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); + cli_addr.sin_port = htons(IPPORT_BOOTPC); + + if(bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) { + perror("bind error"); + return false; + } + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + perror("setsockopt SO_REUSEADDR"); + return false; + } + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { + perror("setsockopt SO_REUSEPORT"); + return false; + } + + memset((char *) &serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + serv_addr.sin_port = htons(IPPORT_BOOTPS); + + // Fill in the BOOTP request + bzero(&bootp_xmit, sizeof(bootp_xmit)); + if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { + perror("SIOCGIFHWADDR"); + return false; + } + bootp_xmit.bp_htype = ifr.ifr_hwaddr.sa_family; + bootp_xmit.bp_hlen = IFHWADDRLEN; + bcopy(ifr.ifr_hwaddr.sa_data, &bootp_xmit.bp_chaddr, bootp_xmit.bp_hlen); + + bootp_xmit.bp_secs = 0; + bcopy(mincookie, bootp_xmit.bp_vend, sizeof(mincookie)); + + bootp_xmit.bp_op = BOOTREQUEST; + + if(sendto(s, &bootp_xmit, sizeof(struct bootp), 0, + (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + perror("sendto error"); + return false; + } + + tv.tv_sec = 5; + tv.tv_usec = 0; + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + + addrlen = sizeof(bootp_server_addr); + if (recvfrom(s, recv, sizeof(struct bootp), 0, + (struct sockaddr *)&bootp_server_addr, &addrlen) < 0) { + perror("recvfrom error"); + return false; + } + + + 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; + + strcpy(ifr.ifr_name, intf); + if (ioctl(s, SIOCDIFADDR, &ifr)) { + perror("SIOCDIFADDR"); + } + + // Shut down interface so it can be reinitialized + ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING); + if (ioctl(s, SIOCSIFFLAGS, &ifr)) { + perror("SIOCSIFFLAGS"); + return false; + } + + // All done with socket + close(s); + return true; +} + +static char *_bootp_op[] = {"", "REQUEST", "REPLY"}; +static char *_bootp_hw_type[] = {"", "Ethernet", "Exp Ethernet", "AX25", + "Pronet", "Chaos", "IEEE802", "Arcnet"}; + +void +show_bootp(const char *intf, struct bootp *bp) +{ + int i, len; + unsigned char *op, *ap = 0; + unsigned char name[128]; + struct in_addr addr[32]; + diag_printf("BOOTP[%s] op: %s\n", intf, _bootp_op[bp->bp_op]); + diag_printf(" hw_type: %s\n", _bootp_hw_type[bp->bp_htype]); + diag_printf(" hw_addr: "); + for (i = 0; i < bp->bp_hlen; i++) { + diag_printf("%02x", bp->bp_chaddr[i]); + if (i != (bp->bp_hlen-1)) diag_printf(":"); + } + diag_printf("\n"); + diag_printf(" client IP: %s\n", inet_ntoa(bp->bp_ciaddr)); + diag_printf(" my IP: %s\n", inet_ntoa(bp->bp_yiaddr)); + diag_printf(" server IP: %s\n", inet_ntoa(bp->bp_siaddr)); + diag_printf(" gateway IP: %s\n", inet_ntoa(bp->bp_giaddr)); + if (bp->bp_sname[0]) { + diag_printf(" server: %s\n", bp->bp_sname); + } + if (bp->bp_file[0]) { + diag_printf(" file: %s\n", bp->bp_file); + } + if (bp->bp_vend[0]) { + diag_printf(" options:\n"); + op = &bp->bp_vend[4]; + while (*op != TAG_END) { + switch (*op) { + case TAG_SUBNET_MASK: + case TAG_GATEWAY: + case TAG_IP_BROADCAST: + case TAG_DOMAIN_SERVER: + ap = (unsigned char *)&addr[0]; + len = *(op+1); + for (i = 0; i < len; i++) { + *ap++ = *(op+i+2); + } + if (*op == TAG_SUBNET_MASK) ap = " subnet mask"; + if (*op == TAG_GATEWAY) ap = " gateway"; + if (*op == TAG_IP_BROADCAST) ap = " IP broadcast"; + if (*op == TAG_DOMAIN_SERVER) ap = "domain server"; + diag_printf(" %s: ", ap); + ap = (unsigned char *)&addr[0]; + while (len > 0) { + diag_printf("%s", inet_ntoa(*(struct in_addr *)ap)); + len -= sizeof(struct in_addr); + ap += sizeof(struct in_addr); + if (len) diag_printf(", "); + } + diag_printf("\n"); + break; + case TAG_DOMAIN_NAME: + case TAG_HOST_NAME: + for (i = 0; i < *(op+1); i++) { + name[i] = *(op+i+2); + } + name[*(op+1)] = '\0'; + if (*op == TAG_DOMAIN_NAME) ap = " domain name"; + if (*op == TAG_HOST_NAME) ap = " host name"; + diag_printf(" %s: %s\n", ap, name); + break; + default: + diag_printf("Unknown option: %x.%d\n", *op, *(op+1)); + } + op += *(op+1)+2; + } + } +} + +cyg_bool_t +get_bootp_option(struct bootp *bp, unsigned char tag, void *opt) +{ + unsigned char *op; + unsigned char *val = (unsigned char *)opt; + int i; + op = &bp->bp_vend[4]; + while (*op != TAG_END) { + if (*op == tag) { + for (i = 0; i < *(op+1); i++) { + *val++ = *(op+i+2); + } + return true; + } + op += *(op+1)+2; + } + return false; +} + +// [Re]initialize the network interface with the info passed from BOOTP +cyg_bool_t +init_net(const char *intf, struct bootp *bp) +{ + 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"); + 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; + addrp->sin_addr = bp->bp_yiaddr; // The address BOOTP gave us + + strcpy(ifr.ifr_name, intf); + if (ioctl(s, SIOCSIFADDR, &ifr)) { + perror("SIOCIFADDR"); + return false; + } + + if (get_bootp_option(bp, TAG_SUBNET_MASK, &addrp->sin_addr)) { + netmask = addrp->sin_addr; + if (ioctl(s, SIOCSIFNETMASK, &ifr)) { + perror("SIOCSIFNETMASK"); + return false; + } + } + + if (get_bootp_option(bp, TAG_IP_BROADCAST, &addrp->sin_addr)) { + if (ioctl(s, SIOCSIFBRDADDR, &ifr)) { + perror("SIOCSIFBRDADDR"); + return false; + } + + } + + ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; + if (ioctl(s, SIOCSIFFLAGS, &ifr)) { + perror("SIOCSIFFLAGS"); + return false; + } + + // Set up routing + if (get_bootp_option(bp, TAG_GATEWAY, &gateway)) { + memset(&route, 0, sizeof(route)); + addrp->sin_family = AF_INET; + addrp->sin_port = 0; + addrp->sin_addr.s_addr = *(unsigned int *)&bp->bp_yiaddr & *(unsigned int *)&netmask; + 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"); + return false; + } + } + } + close(s); + return true; +}
