OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/ecos-2.0/packages/net/common/v2_0/src
    from Rev 27 to Rev 174
    Reverse comparison

Rev 27 → Rev 174

/inet_ntop.c
0,0 → 1,258
//==========================================================================
//
// src/inet_ntop.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
 
/* $OpenBSD: inet_ntop.c,v 1.1 1997/03/13 19:07:32 downsj Exp $ */
 
/* Copyright (c) 1996 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
 
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <string.h>
#include <errno.h>
#ifndef CYGPKG_NET_FREEBSD_STACK
#include <stdio.h>
#endif
 
#ifndef IN6ADDRSZ
#define IN6ADDRSZ 16 /* IPv6 T_AAAA */
#endif
#ifndef INT16SZ
#define INT16SZ sizeof(u_int16_t)
#endif
 
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
 
static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
#ifdef CYGPKG_NET_INET6
static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
#endif
 
/* char *
* inet_ntop(af, src, dst, size)
* convert a network format address to presentation format.
* return:
* pointer to presentation format address (`dst'), or NULL (see errno).
* author:
* Paul Vixie, 1996.
*/
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
#ifdef CYGPKG_NET_INET6
case AF_INET6:
return (inet_ntop6(src, dst, size));
#endif
default:
errno = EAFNOSUPPORT;
return (NULL);
}
/* NOTREACHED */
}
 
//
// A more useful conversion routine
// Convert a network [socket] address to presentation format
// This routine handles all of the mapping required and isolates
// the knowledge of the structure format.
//
const char *
_inet_ntop(struct sockaddr *sa, char *dst, size_t size)
{
switch (sa->sa_family) {
case AF_INET:
return (inet_ntop(AF_INET, (char *)&((struct sockaddr_in *)sa)->sin_addr,
dst, size));
#ifdef CYGPKG_NET_INET6
case AF_INET6:
return (inet_ntop(AF_INET6, (char *)&((struct sockaddr_in6 *)sa)->sin6_addr,
dst, size));
#endif
default:
errno = EAFNOSUPPORT;
return (NULL);
}
}
 
u_int16_t
_inet_port(struct sockaddr *sa)
{
switch (sa->sa_family) {
case AF_INET:
return (ntohs(((struct sockaddr_in *)sa)->sin_port));
#ifdef CYGPKG_NET_INET6
case AF_INET6:
return (ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
#endif
default:
return 0; // Unknown!
}
}
 
/* const char *
* inet_ntop4(src, dst, size)
* format an IPv4 address, more or less like inet_ntoa()
* return:
* `dst' (as a const)
* notes:
* (1) uses no statics
* (2) takes a u_char* not an in_addr as input
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop4(src, dst, size)
const u_char *src;
char *dst;
size_t size;
{
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
 
if (sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
 
#ifdef CYGPKG_NET_INET6
/* const char *
* inet_ntop6(src, dst, size)
* convert IPv6 binary address into presentation (printable) format
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop6(const u_char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
#if 0 // This is too optimistic
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
#else
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"], *tp;
#endif
struct { int base, len; } best, cur;
u_int words[IN6ADDRSZ / INT16SZ];
int i;
 
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
cur.base = -1;
for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
 
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
return (NULL);
tp += strlen(tp);
break;
}
tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
*tp++ = ':';
*tp++ = '\0';
 
/*
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
#endif
/inet_pton.c
0,0 → 1,269
//==========================================================================
//
// src/inet_pton.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
 
/* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */
 
/*
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
 
//#if defined(LIBC_SCCS) && !defined(lint)
//static char rcsid[] = "$Id: inet_pton.c,v 1.1.1.1 2004-02-14 13:32:54 phoenix Exp $";
//#endif /* LIBC_SCCS and not lint */
 
//#ifdef HAVE_CONFIG_H
//#include <config.h>
//#endif
 
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <string.h>
#include <errno.h>
 
//#ifndef HAVE_PORTABLE_PROTOTYPE
//#include "cdecl_ext.h"
//#endif
 
//#ifndef HAVE_U_INT16_T
//#include "bittypes.h"
//#endif
 
//#if !(defined(HAVE_INADDRSZ) && defined(HAVE_IN6ADDRSZ))
//#include "addrsize.h"
//#endif
 
#define NS_INADDRSZ 4 /* IPv4 T_A */
#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */
 
#ifndef NS_INADDRSZ
#define NS_INADDRSZ INADDRSZ
#endif
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ IN6ADDRSZ
#endif
#ifndef NS_INT16SZ
#define NS_INT16SZ sizeof(u_int16_t)
#endif
 
/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
 
static int inet_pton4 __P((const char *src, u_char *dst));
#ifdef CYGPKG_NET_INET6
static int inet_pton6 __P((const char *src, u_char *dst));
#endif
 
/* int
* inet_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address wasn't valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* author:
* Paul Vixie, 1996.
*/
int
inet_pton(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
#ifdef CYGPKG_NET_INET6
case AF_INET6:
return (inet_pton6(src, dst));
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
}
/* NOTREACHED */
}
 
/* int
* inet_pton4(src, dst)
* like inet_aton() but without all the hexadecimal and shorthand.
* return:
* 1 if `src' is a valid dotted quad, else 0.
* notice:
* does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton4(const char *src, u_char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
u_char tmp[NS_INADDRSZ], *tp;
 
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
 
if ((pch = strchr(digits, ch)) != NULL) {
u_int new = *tp * 10 + (pch - digits);
 
if (new > 255)
return (0);
*tp = new;
if (! saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
 
#ifdef CYGPKG_NET_INET6
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
* (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton6(const char *src, u_char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
u_int val;
 
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
 
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
} else if (*src == '\0') {
return (0);
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
break; /* '\0' was seen by inet_pton4(). */
}
return (0);
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
 
if (tp == endp)
return (0);
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
#endif /*INET6*/
/tftp_server.c
0,0 → 1,610
//==========================================================================
//
// lib/tftp_server.c
//
// TFTP server support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas, hmt, andrew.lunn@ascom.ch (Andrew Lunn)
// Date: 2000-04-06
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
// TFTP server support
 
#include <network.h> // Basic networking support
#include <arpa/tftp.h> // TFTP protocol definitions
#include <tftp_support.h> // TFTPD structures
#include <cyg/kernel/kapi.h>
#include <stdlib.h> // For malloc
 
#define nCYGOPT_NET_TFTP_SERVER_INSTRUMENT
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
 
struct subinfo {
int rx;
int rx_repeat;
int rx_skip;
int send;
int resend;
};
 
struct info {
struct subinfo ack, data;
int err_send;
int total_transactions;
};
 
 
static struct info tftp_server_instrument = {
{ 0,0,0,0,0 },
{ 0,0,0,0,0 },
0, 0,
};
 
#endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT
 
#define STACK_SIZE (((CYGNUM_HAL_STACK_SIZE_TYPICAL+(3*(SEGSIZE+sizeof(struct tftphdr)))) + CYGARC_ALIGNMENT-1) & ~(CYGARC_ALIGNMENT-1))
static char *TFTP_tag = "TFTPD";
struct tftp_server {
char *tag;
char stack[STACK_SIZE];
cyg_thread thread_data;
cyg_handle_t thread_handle;
int port;
struct tftpd_fileops *ops;
};
 
static char * errmsg[] = {
"Undefined error code", // 0 nothing defined
"File not found", // 1 TFTP_ENOTFOUND
"Access violation", // 2 TFTP_EACCESS
"Disk full or allocation exceeded", // 3 TFTP_ENOSPACE
"Illegal TFTP operation", // 4 TFTP_EBADOP
"Unknown transfer ID", // 5 TFTP_EBADID
"File already exists", // 6 TFTP_EEXISTS
"No such user", // 7 TFTP_ENOUSER
};
 
/* Send an error packet to the client */
static void
tftpd_send_error(int s, struct tftphdr * reply, int err,
struct sockaddr_in *from_addr, int from_len)
{
CYG_ASSERT( 0 <= err, "err underflow" );
CYG_ASSERT( sizeof(errmsg)/sizeof(errmsg[0]) > err, "err overflow" );
 
reply->th_opcode = htons(ERROR);
reply->th_code = htons(err);
if ( (0 > err) || (sizeof(errmsg)/sizeof(errmsg[0]) <= err) )
err = 0; // Do not copy a random string from hyperspace
strcpy(reply->th_msg, errmsg[err]);
sendto(s, reply, 4+strlen(reply->th_msg)+1, 0,
(struct sockaddr *)from_addr, from_len);
}
 
//
// Receive a file from the client
//
static void
tftpd_write_file(struct tftp_server *server,
struct tftphdr *hdr,
struct sockaddr_in *from_addr, int from_len)
{
char data_out[SEGSIZE+sizeof(struct tftphdr)];
char data_in[SEGSIZE+sizeof(struct tftphdr)];
struct tftphdr *reply = (struct tftphdr *)data_out;
struct tftphdr *response = (struct tftphdr *)data_in;
int fd, len, ok, tries, closed, data_len, s;
unsigned short block;
struct timeval timeout;
fd_set fds;
int total_timeouts = 0;
struct sockaddr_in client_addr, local_addr;
int client_len;
 
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
diag_printf("TFTPD: can't open socket for 'write_file'\n");
return;
}
memset((char *)&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_len = sizeof(local_addr);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(INADDR_ANY);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
// Problem setting up my end
diag_printf("TFTPD: can't bind to reply port for 'write_file'\n");
close(s);
return;
}
if ((fd = (server->ops->open)(hdr->th_stuff, O_WRONLY)) < 0) {
tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);
close(s);
return;
}
ok = true;
closed = false;
block = 0;
while (ok) {
// Send ACK telling client he can send data
reply->th_opcode = htons(ACK);
reply->th_block = htons(block++); // postincrement
for (tries = 0; tries < TFTP_RETRIES_MAX; tries++) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.ack.send++;
#endif
sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len);
repeat_select:
timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
if (++total_timeouts > TFTP_TIMEOUT_MAX) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.err_send++;
#endif
tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
ok = false;
break;
}
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.ack.resend++;
#endif
continue; // retry the send, using up one retry.
}
// Some data has arrived
data_len = sizeof(data_in);
client_len = sizeof(client_addr);
if ((data_len = recvfrom(s, data_in, data_len, 0,
(struct sockaddr *)&client_addr, &client_len)) < 0) {
// What happened? No data here!
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.ack.resend++;
#endif
continue; // retry the send, using up one retry.
}
if (ntohs(response->th_opcode) == DATA &&
ntohs(response->th_block) < block) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.data.rx_repeat++;
#endif
// Then it is repeat DATA with an old block; listen again,
// but do not repeat sending the current ack, and do not
// use up a retry count. (we do re-send the ack if
// subsequently we time out)
goto repeat_select;
}
if (ntohs(response->th_opcode) == DATA &&
ntohs(response->th_block) == block) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.data.rx++;
#endif
// Good data - write to file
len = (server->ops->write)(fd, response->th_data, data_len-4);
if (len < (data_len-4)) {
// File is "full"
tftpd_send_error(s,reply,TFTP_ENOSPACE,
from_addr, from_len);
ok = false; // Give up
break; // out of the retries loop
}
if (data_len < (SEGSIZE+4)) {
// End of file
closed = true;
ok = false;
if ((server->ops->close)(fd) == -1) {
tftpd_send_error(s,reply,TFTP_EACCESS,
from_addr, from_len);
break; // out of the retries loop
}
// Exception to the loop structure: we must ACK the last
// packet, the one that implied EOF:
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.ack.send++;
#endif
reply->th_opcode = htons(ACK);
reply->th_block = htons(block++); // postincrement
sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len);
break; // out of the retries loop
}
// Happy! Break out of the retries loop.
break;
}
// Otherwise, we got something we do not understand! So repeat
// sending the current ACK, and use up a retry count.
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
if ( (ntohs(response->th_opcode) == DATA) )
tftp_server_instrument.data.rx_skip++;
tftp_server_instrument.ack.resend++;
#endif
} // End of the retries loop.
if (TFTP_RETRIES_MAX <= tries) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.err_send++;
#endif
tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
ok = false;
}
}
close(s);
if (!closed) {
(server->ops->close)(fd);
}
}
 
//
// Send a file to the client
//
static void
tftpd_read_file(struct tftp_server *server,
struct tftphdr *hdr,
struct sockaddr_in *from_addr, int from_len)
{
char data_out[SEGSIZE+sizeof(struct tftphdr)];
char data_in[SEGSIZE+sizeof(struct tftphdr)];
struct tftphdr *reply = (struct tftphdr *)data_out;
struct tftphdr *response = (struct tftphdr *)data_in;
int fd, len, tries, ok, data_len, s;
unsigned short block;
struct timeval timeout;
fd_set fds;
int total_timeouts = 0;
struct sockaddr_in client_addr, local_addr;
int client_len;
 
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
diag_printf("TFTPD: can't open socket for 'read_file'\n");
return;
}
memset((char *)&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_len = sizeof(local_addr);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(INADDR_ANY);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
// Problem setting up my end
diag_printf("TFTPD: can't bind to reply port for 'read_file'\n");
close(s);
return;
}
if ((fd = (server->ops->open)(hdr->th_stuff, O_RDONLY)) < 0) {
tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);
close(s);
return;
}
block = 0;
ok = true;
while (ok) {
// Read next chunk of file
len = (server->ops->read)(fd, reply->th_data, SEGSIZE);
reply->th_block = htons(++block); // preincrement
reply->th_opcode = htons(DATA);
for (tries = 0; tries < TFTP_RETRIES_MAX; tries++) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.data.send++;
#endif
if (sendto(s, reply, 4+len, 0,
(struct sockaddr *)from_addr, from_len) < 0) {
// Something went wrong with the network!
ok = false;
break;
}
repeat_select:
timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
if (++total_timeouts > TFTP_TIMEOUT_MAX) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.err_send++;
#endif
tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
ok = false;
break;
}
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.data.resend++;
#endif
continue; // retry the send, using up one retry.
}
data_len = sizeof(data_in);
client_len = sizeof(client_addr);
if ((data_len = recvfrom(s, data_in, data_len, 0,
(struct sockaddr *)&client_addr,
&client_len)) < 0) {
// What happened? Maybe someone lied to us...
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.data.resend++;
#endif
continue; // retry the send, using up one retry.
}
if ((ntohs(response->th_opcode) == ACK) &&
(ntohs(response->th_block) < block)) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.ack.rx_repeat++;
#endif
// Then it is a repeat ACK for an old block; listen again,
// but do not repeat sending the current block, and do not
// use up a retry count. (we do re-send the data if
// subsequently we time out)
goto repeat_select;
}
if ((ntohs(response->th_opcode) == ACK) &&
(ntohs(response->th_block) == block)) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.ack.rx++;
#endif
// Happy! Break out of the retries loop.
break;
}
// Otherwise, we got something we do not understand! So repeat
// sending the current block, and use up a retry count.
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
if ( (ntohs(response->th_opcode) == ACK) )
tftp_server_instrument.ack.rx_skip++;
tftp_server_instrument.data.resend++;
#endif
} // End of the retries loop.
if (TFTP_RETRIES_MAX <= tries) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.err_send++;
#endif
tftpd_send_error(s,reply,TFTP_EBADOP,from_addr, from_len);
ok = false;
}
if (len < SEGSIZE) {
break; // That's end of file then.
}
}
close(s);
(server->ops->close)(fd);
}
 
//
// Actual TFTP server
//
#define CYGSEM_TFTP_SERVER_MULTITHREADED
#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
static cyg_sem_t tftp_server_sem;
#endif
 
static void
tftpd_server(cyg_addrword_t p)
{
struct tftp_server *server = (struct tftp_server *)p;
int s;
int data_len, recv_len, from_len;
struct sockaddr_in local_addr, from_addr;
struct servent *server_info;
char data[SEGSIZE+sizeof(struct tftphdr)];
struct tftphdr *hdr = (struct tftphdr *)data;
 
#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
// Otherwise routine printfs fail the test - interrupts disabled too long.
diag_printf("TFTPD [%x]: port %d\n", p, server->port);
#endif
 
// Set up port
if (server->port == 0) {
server_info = getservbyname("tftp", "udp");
if (server_info == (struct servent *)0) {
diag_printf("TFTPD: can't get TFTP service information\n");
return;
}
// Network order in info; host order in server:
server->port = ntohs( server_info->s_port );
}
 
while (true) {
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
struct info o = tftp_server_instrument;
#endif
// Create socket
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
diag_printf("TFTPD [%x]: can't open socket\n", p);
return;
}
memset((char *)&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_len = sizeof(local_addr);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(server->port);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
// Problem setting up my end
close(s);
#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
diag_printf("TFTPD [%x]: waiting to bind to service port\n", p);
#endif
// Wait until the socket is free...
cyg_semaphore_wait( &tftp_server_sem );
continue; // try re-opening and rebinding the socket.
#else
diag_printf("TFTPD [%x]: can't bind to service port\n", p);
return;
#endif
}
 
recv_len = sizeof(data);
from_len = sizeof(from_addr);
data_len = recvfrom(s, hdr, recv_len, 0,
(struct sockaddr *)&from_addr, &from_len);
close(s); // so that other servers can bind to the TFTP socket
#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
// The socket is free...
cyg_semaphore_post( &tftp_server_sem );
#endif
 
if ( data_len < 0) {
diag_printf("TFTPD [%x]: can't read request\n", p);
} else {
#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
diag_printf("TFTPD [%x]: received %x from %s:%d\n", p,
ntohs(hdr->th_opcode), inet_ntoa(from_addr.sin_addr),
from_addr.sin_port);
#endif
switch (ntohs(hdr->th_opcode)) {
case WRQ:
tftpd_write_file(server, hdr, &from_addr, from_len);
break;
case RRQ:
tftpd_read_file(server, hdr, &from_addr, from_len);
break;
case ACK:
case DATA:
case ERROR:
// Ignore
break;
default:
diag_printf("TFTPD [%x]: bogus request %x from %s:%d\n", p,
ntohs(hdr->th_opcode),
inet_ntoa(from_addr.sin_addr),
from_addr.sin_port );
tftpd_send_error(s,hdr,TFTP_EBADOP,&from_addr,from_len);
}
}
#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
tftp_server_instrument.total_transactions++;
 
o.data.rx -= tftp_server_instrument.data.rx ;
o.data.rx_repeat -= tftp_server_instrument.data.rx_repeat;
o.data.rx_skip -= tftp_server_instrument.data.rx_skip ;
o.data.send -= tftp_server_instrument.data.send ;
o.data.resend -= tftp_server_instrument.data.resend ;
 
o.ack.rx -= tftp_server_instrument.ack.rx ;
o.ack.rx_repeat -= tftp_server_instrument.ack.rx_repeat ;
o.ack.rx_skip -= tftp_server_instrument.ack.rx_skip ;
o.ack.send -= tftp_server_instrument.ack.send ;
o.ack.resend -= tftp_server_instrument.ack.resend ;
 
o.err_send -= tftp_server_instrument.err_send ;
 
#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
if ( o.data.rx ) diag_printf( "data rx %4d\n", -o.data.rx );
if ( o.data.rx_repeat ) diag_printf( "data rx_repeat%4d\n", -o.data.rx_repeat );
if ( o.data.rx_skip ) diag_printf( "data rx_skip %4d\n", -o.data.rx_skip );
if ( o.data.send ) diag_printf( "data send %4d\n", -o.data.send );
if ( o.data.resend ) diag_printf( "data resend %4d\n", -o.data.resend );
 
if ( o.ack.rx ) diag_printf( " ack rx %4d\n", -o.ack.rx );
if ( o.ack.rx_repeat ) diag_printf( " ack rx_repeat%4d\n", -o.ack.rx_repeat );
if ( o.ack.rx_skip ) diag_printf( " ack rx_skip %4d\n", -o.ack.rx_skip );
if ( o.ack.send ) diag_printf( " ack send %4d\n", -o.ack.send );
if ( o.ack.resend ) diag_printf( " ack resend %4d\n", -o.ack.resend );
 
if ( o.err_send ) diag_printf( "*error sends %4d\n", -o.err_send );
#endif // CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
#endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT
}
}
 
//
// This function is used to create a new server [thread] which supports
// the TFTP protocol on the given port. A server 'id' will be returned
// which can later be used to destroy the server.
//
// Note: all [memory] resources for the server thread will be allocated
// dynamically. If there are insufficient resources, an error will be
// returned.
//
int
tftpd_start(int port, struct tftpd_fileops *ops)
{
struct tftp_server *server;
#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
static char init = 0;
if ( 0 == init ) {
init++;
cyg_semaphore_init( &tftp_server_sem, 0 );
}
#endif
 
if ((server = malloc(sizeof(struct tftp_server)))) {
server->tag = TFTP_tag;
server->port = port;
server->ops = ops;
cyg_thread_create(CYGPKG_NET_TFTPD_THREAD_PRIORITY, // Priority
tftpd_server, // entry
(cyg_addrword_t)server, // entry parameter
"TFTP server", // Name
&server->stack[0], // Stack
STACK_SIZE, // Size
&server->thread_handle, // Handle
&server->thread_data // Thread data structure
);
cyg_thread_resume(server->thread_handle); // Start it
 
}
return (int)server;
}
 
//
// Destroy a TFTP server, using a previously created server 'id'.
//
int
tftpd_stop(int p)
{
struct tftp_server *server = (struct tftp_server *)p;
// Simple sanity check
if (server->tag == TFTP_tag) {
cyg_thread_kill(server->thread_handle);
cyg_thread_set_priority(server->thread_handle, 0);
cyg_thread_delay(1); // Make sure it gets to die...
if (cyg_thread_delete(server->thread_handle)) {
// Success shutting down the thread
free(server); // Give up memory
return 1;
}
}
return 0;
}
 
// EOF tftp_server.c
/getproto.c
0,0 → 1,88
//==========================================================================
//
// lib/getproto.c
//
// getprotobyname(), getprotobynumber()
//
//==========================================================================
//####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####
//
//==========================================================================
 
#include <sys/param.h>
#include <netdb.h>
#include <errno.h>
 
static struct protoent protocols[] = {
{ "ip", 0}, // internet protocol, pseudo protocol number
{ "icmp", 1}, // internet control message protocol
{ "igmp", 2}, // Internet Group Management
{ "ggp", 3}, // gateway-gateway protocol
{ "ipencap", 4}, // IP encapsulated in IP (officially ``IP'')
{ "st", 5}, // ST datagram mode
{ "tcp", 6}, // transmission control protocol
{ "egp", 8}, // exterior gateway protocol
{ "pup", 12}, // PARC universal packet protocol
{ "udp", 17}, // user datagram protocol
{ "hmp", 20}, // host monitoring protocol
{ "xns-idp", 22}, // Xerox NS IDP
{ "rdp", 27}, // "reliable datagram" protocol
{ "iso-tp4", 29}, // ISO Transport Protocol class 4
{ "xtp", 36}, // Xpress Tranfer Protocol
{ "ddp", 37}, // Datagram Delivery Protocol
{ "idpr-cmtp", 39}, // IDPR Control Message Transport
{ "rspf", 73}, //Radio Shortest Path First.
{ "vmtp", 81}, // Versatile Message Transport
{ "ospf", 89}, // Open Shortest Path First IGP
{ "ipip", 94}, // Yet Another IP encapsulation
{ "encap", 98}, // Yet Another IP encapsulation
{ 0, 0}
};
 
struct protoent *
getprotobyname(const char *name)
{
struct protoent *p = protocols;
while (p->p_name) {
if (strcmp(name, p->p_name) == 0) {
return p;
}
p++;
}
errno = ENOENT;
return (struct protoent *)0;
}
 
struct protoent *
getprotobynumber(const int num)
{
struct protoent *p = protocols;
while (p->p_name) {
if (p->p_proto == num) {
return p;
}
p++;
}
errno = ENOENT;
return (struct protoent *)0;
}
/dhcp_support.c
0,0 → 1,252
/*==========================================================================
//
// dhcp_support.c
//
// Support code == friendly API for DHCP client
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): hmt
// Contributors: gthomas
// Date: 2000-07-01
// Purpose: DHCP support
// Description:
//
//####DESCRIPTIONEND####
//
//========================================================================*/
 
#include <pkgconf/system.h>
#include <pkgconf/net.h>
 
#ifdef CYGPKG_NET_DHCP
 
#include <network.h>
#include <dhcp.h>
 
// ---------------------------------------------------------------------------
#ifdef CYGHWR_NET_DRIVER_ETH0
cyg_uint8 eth0_dhcpstate = 0;
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
cyg_uint8 eth1_dhcpstate = 0;
#endif
 
cyg_sem_t dhcp_needs_attention;
 
#ifdef CYGHWR_NET_DRIVER_ETH0
struct dhcp_lease eth0_lease = { &dhcp_needs_attention, 0,0,0,0,0,0 };
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
struct dhcp_lease eth1_lease = { &dhcp_needs_attention, 0,0,0,0,0,0 };
#endif
 
// ---------------------------------------------------------------------------
//
// The point of this module is to deal with all the horrid written out in
// full stuff of having two interfaces; it's ugly but it's also most
// flexible. The dhcp_prot.c module should do all the work...
//
// ---------------------------------------------------------------------------
 
// return value: 1 => everything OK, no change.
// 0 => close your connections, then call do_dhcp_halt() to halt the
// interface(s) in question (it knows because the state will be NOTBOUND).
// After that you can return to the start and use
// init_all_network_interfaces(); as usual, or call do_dhcp_bind() by hand,
// or whatever...
int dhcp_bind( void )
{
#ifdef CYGHWR_NET_DRIVER_ETH0
cyg_uint8 old_eth0_dhcpstate = eth0_dhcpstate;
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
cyg_uint8 old_eth1_dhcpstate = eth1_dhcpstate;
#endif
 
// If there are no interfaces at all, init it every time, doesn't
// matter. In case we are called from elsewhere...
if ( 1
#ifdef CYGHWR_NET_DRIVER_ETH0
&& eth0_dhcpstate == 0
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
&& eth1_dhcpstate == 0
#endif
)
cyg_semaphore_init( &dhcp_needs_attention, 0 );
 
// Run the state machine...
#ifdef CYGHWR_NET_DRIVER_ETH0
if (eth0_up
&& DHCPSTATE_FAILED != eth0_dhcpstate )
eth0_up = do_dhcp(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease);
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
if (eth1_up
&& DHCPSTATE_FAILED != eth1_dhcpstate )
eth1_up = do_dhcp(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease);
#endif
 
// If the interface newly came up, initialize it:
// (this duplicates the code in init_all_network_interfaces() really).
#ifdef CYGHWR_NET_DRIVER_ETH0
if ( eth0_up
&& eth0_dhcpstate == DHCPSTATE_BOUND
&& old_eth0_dhcpstate != eth0_dhcpstate ) {
if (!init_net(eth0_name, &eth0_bootp_data)) {
eth0_up = false;
}
}
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
if ( eth1_up
&& eth1_dhcpstate == DHCPSTATE_BOUND
&& old_eth1_dhcpstate != eth1_dhcpstate ) {
if (!init_net(eth1_name, &eth1_bootp_data)) {
eth1_up = false;
}
}
#endif
 
#ifdef CYGHWR_NET_DRIVER_ETH0
if ( old_eth0_dhcpstate == DHCPSTATE_BOUND &&
eth0_dhcpstate == DHCPSTATE_NOTBOUND )
return 0; // a lease timed out; we became unbound
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
if ( old_eth1_dhcpstate == DHCPSTATE_BOUND &&
eth1_dhcpstate == DHCPSTATE_NOTBOUND )
return 0; // a lease timed out; we became unbound
#endif
return 1; // all is well
}
 
 
// Shutdown any interface whose state is DHCPSTATE_NOTBOUND.
int dhcp_halt( void )
{
#ifdef CYGHWR_NET_DRIVER_ETH0
if ( eth0_up
&& eth0_dhcpstate != DHCPSTATE_FAILED ) {
do_dhcp_down_net(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease);
}
eth0_up = false;
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
if ( eth1_up
&& eth1_dhcpstate != DHCPSTATE_FAILED ) {
do_dhcp_down_net(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease);
}
eth1_up = false;
#endif
return 1;
}
 
 
// Release (and set state to DHCPSTATE_NOTBOUND) all interfaces - we are
// closing down. (unlikely but maybe useful for testing)
int dhcp_release( void )
{
#ifdef CYGHWR_NET_DRIVER_ETH0
if (eth0_up)
do_dhcp_release(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease);
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
if (eth1_up)
do_dhcp_release(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease);
#endif
return 1;
}
 
 
// ------------------------------------------------------------------------
// The management thread function
void dhcp_mgt_entry( cyg_addrword_t loop_on_failure )
{
int j;
while ( 1 ) {
while ( 1 ) {
cyg_semaphore_wait( &dhcp_needs_attention );
if ( ! dhcp_bind() ) // a lease expired
break; // If we need to re-bind
}
dhcp_halt(); // tear everything down
if ( !loop_on_failure )
return; // exit the thread/return
init_all_network_interfaces(); // re-initialize
for ( j = 0; j < CYGPKG_NET_NLOOP; j++ )
init_loopback_interface( j );
#ifdef CYGPKG_SNMPAGENT
SnmpdShutDown(0); // Cycle the snmpd state
#endif
}
}
 
#ifdef CYGOPT_NET_DHCP_DHCP_THREAD
// Then we provide such a thread...
cyg_handle_t dhcp_mgt_thread_h = 0;
cyg_thread dhcp_mgt_thread;
 
#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + sizeof(struct bootp))
static cyg_uint8 dhcp_mgt_stack[ STACK_SIZE ];
 
void dhcp_start_dhcp_mgt_thread( void )
{
if ( ! dhcp_mgt_thread_h ) {
cyg_semaphore_init( &dhcp_needs_attention, 0 );
cyg_thread_create(
CYGPKG_NET_DHCP_THREAD_PRIORITY, /* scheduling info (eg pri) */
dhcp_mgt_entry, /* entry point function */
CYGOPT_NET_DHCP_DHCP_THREAD_PARAM, /* entry data */
"DHCP lease mgt", /* optional thread name */
dhcp_mgt_stack, /* stack base, NULL = alloc */
STACK_SIZE, /* stack size, 0 = default */
&dhcp_mgt_thread_h, /* returned thread handle */
&dhcp_mgt_thread /* put thread here */
);
 
cyg_thread_resume(dhcp_mgt_thread_h);
}
}
 
 
#endif // CYGOPT_NET_DHCP_DHCP_THREAD
 
#endif // CYGPKG_NET_DHCP
 
// EOF dhcp_support.c
/tftp_client.c
0,0 → 1,425
//==========================================================================
//
// lib/tftp_client.c
//
// TFTP client support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-04-06
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
// TFTP client support
 
#include <network.h>
#include <arpa/tftp.h>
#include <tftp_support.h>
 
#define min(x,y) (x<y ? x : y)
 
//
// Read a file from a host into a local buffer. Returns the
// number of bytes actually read, or (-1) if an error occurs.
// On error, *err will hold the reason.
//
int
tftp_get(char *filename,
struct sockaddr_in *server,
char *buf,
int len,
int mode,
int *err)
{
int res = 0;
int s, actual_len, data_len, recv_len, from_len;
static int get_port = 7700;
struct sockaddr_in local_addr, server_addr, from_addr;
char data[SEGSIZE+sizeof(struct tftphdr)];
struct tftphdr *hdr = (struct tftphdr *)data;
char *cp, *fp;
struct timeval timeout;
unsigned short last_good_block = 0;
struct servent *server_info;
fd_set fds;
int total_timeouts = 0;
 
*err = 0; // Just in case
 
// Create initial request
hdr->th_opcode = htons(RRQ); // Read file
cp = (char *)&hdr->th_stuff;
fp = filename;
while (*fp) *cp++ = *fp++;
*cp++ = '\0';
if (mode == TFTP_NETASCII) {
fp = "NETASCII";
} else if (mode == TFTP_OCTET) {
fp = "OCTET";
} else {
*err = TFTP_INVALID;
return -1;
}
while (*fp) *cp++ = *fp++;
*cp++ = '\0';
server_info = getservbyname("tftp", "udp");
if (server_info == (struct servent *)0) {
*err = TFTP_NETERR;
return -1;
}
 
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
// Couldn't open a communications channel
*err = TFTP_NETERR;
return -1;
}
memset((char *)&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_len = sizeof(local_addr);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(get_port++);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
// Problem setting up my end
*err = TFTP_NETERR;
close(s);
return -1;
}
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 = server->sin_addr;
if (server->sin_port == 0) {
server_addr.sin_port = server_info->s_port; // Network order already
} else {
server_addr.sin_port = server->sin_port;
}
 
// Send request
if (sendto(s, data, sizeof(data), 0,
(struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
// Problem sending request
*err = TFTP_NETERR;
close(s);
return -1;
}
 
// Read data
fp = buf;
while (true) {
timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
if ((++total_timeouts > TFTP_TIMEOUT_MAX) || (last_good_block == 0)) {
// Timeout - no data received
*err = TFTP_TIMEOUT;
close(s);
return -1;
}
// Try resending last ACK
hdr->th_opcode = htons(ACK);
hdr->th_block = htons(last_good_block);
if (sendto(s, data, 4 /* FIXME */, 0,
(struct sockaddr *)&from_addr, from_len) < 0) {
// Problem sending request
*err = TFTP_NETERR;
close(s);
return -1;
}
} else {
recv_len = sizeof(data);
from_len = sizeof(from_addr);
if ((data_len = recvfrom(s, &data, recv_len, 0,
(struct sockaddr *)&from_addr, &from_len)) < 0) {
// What happened?
*err = TFTP_NETERR;
close(s);
return -1;
}
if (ntohs(hdr->th_opcode) == DATA) {
actual_len = 0;
if (ntohs(hdr->th_block) == (last_good_block+1)) {
// Consume this data
cp = hdr->th_data;
data_len -= 4; /* Sizeof TFTP header */
actual_len = data_len;
res += actual_len;
while (data_len-- > 0) {
if (len-- > 0) {
*fp++ = *cp++;
} else {
// Buffer overflow
*err = TFTP_TOOLARGE;
close(s);
return -1;
}
}
last_good_block++;
}
// Send out the ACK
hdr->th_opcode = htons(ACK);
hdr->th_block = htons(last_good_block);
if (sendto(s, data, 4 /* FIXME */, 0,
(struct sockaddr *)&from_addr, from_len) < 0) {
// Problem sending request
*err = TFTP_NETERR;
close(s);
return -1;
}
if ((actual_len >= 0) && (actual_len < SEGSIZE)) {
// End of data
close(s);
return res;
}
} else
if (ntohs(hdr->th_opcode) == ERROR) {
*err = ntohs(hdr->th_code);
close(s);
return -1;
} else {
// What kind of packet is this?
*err = TFTP_PROTOCOL;
close(s);
return -1;
}
}
}
}
 
//
// Send data to a file on a server via TFTP.
//
int
tftp_put(char *filename,
struct sockaddr_in *server,
char *buf,
int len,
int mode,
int *err)
{
int res = 0;
int s, actual_len, data_len, recv_len, from_len;
static int put_port = 7800;
struct sockaddr_in local_addr, server_addr, from_addr;
char data[SEGSIZE+sizeof(struct tftphdr)];
struct tftphdr *hdr = (struct tftphdr *)data;
char *cp, *fp, *sfp;
struct timeval timeout;
unsigned short last_good_block = 0;
struct servent *server_info;
fd_set fds;
int total_timeouts = 0;
 
*err = 0; // Just in case
 
server_info = getservbyname("tftp", "udp");
if (server_info == (struct servent *)0) {
*err = TFTP_NETERR;
return -1;
}
 
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
// Couldn't open a communications channel
*err = TFTP_NETERR;
return -1;
}
memset((char *)&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_len = sizeof(local_addr);
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(put_port++);
if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
// Problem setting up my end
*err = TFTP_NETERR;
close(s);
return -1;
}
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 = server->sin_addr;
if (server->sin_port == 0) {
server_addr.sin_port = server_info->s_port; // Network order already
} else {
server_addr.sin_port = server->sin_port;
}
 
while (1) {
// Create initial request
hdr->th_opcode = htons(WRQ); // Create/write file
cp = (char *)&hdr->th_stuff;
fp = filename;
while (*fp) *cp++ = *fp++;
*cp++ = '\0';
if (mode == TFTP_NETASCII) {
fp = "NETASCII";
} else if (mode == TFTP_OCTET) {
fp = "OCTET";
} else {
*err = TFTP_INVALID;
return -1;
}
while (*fp) *cp++ = *fp++;
*cp++ = '\0';
// Send request
if (sendto(s, data, sizeof(data), 0,
(struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
// Problem sending request
*err = TFTP_NETERR;
close(s);
return -1;
}
// Wait for ACK
timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
if (++total_timeouts > TFTP_TIMEOUT_MAX) {
// Timeout - no ACK received
*err = TFTP_TIMEOUT;
close(s);
return -1;
}
} else {
recv_len = sizeof(data);
from_len = sizeof(from_addr);
if ((data_len = recvfrom(s, &data, recv_len, 0,
(struct sockaddr *)&from_addr, &from_len)) < 0) {
// What happened?
*err = TFTP_NETERR;
close(s);
return -1;
}
if (ntohs(hdr->th_opcode) == ACK) {
// Write request accepted - start sending data
break;
} else
if (ntohs(hdr->th_opcode) == ERROR) {
*err = ntohs(hdr->th_code);
close(s);
return -1;
} else {
// What kind of packet is this?
*err = TFTP_PROTOCOL;
close(s);
return -1;
}
}
}
 
// Send data
sfp = buf;
last_good_block = 1;
while (res < len) {
// Build packet of data to send
data_len = min(SEGSIZE, len-res);
hdr->th_opcode = htons(DATA);
hdr->th_block = htons(last_good_block);
cp = hdr->th_data;
fp = sfp;
actual_len = data_len + 4;
// FIXME - what about "netascii" data?
while (data_len-- > 0) *cp++ = *fp++;
// Send data packet
if (sendto(s, data, actual_len, 0,
(struct sockaddr *)&from_addr, from_len) < 0) {
// Problem sending request
*err = TFTP_NETERR;
close(s);
return -1;
}
// Wait for ACK
timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
if (++total_timeouts > TFTP_TIMEOUT_MAX) {
// Timeout - no data received
*err = TFTP_TIMEOUT;
close(s);
return -1;
}
} else {
recv_len = sizeof(data);
from_len = sizeof(from_addr);
if ((data_len = recvfrom(s, &data, recv_len, 0,
(struct sockaddr *)&from_addr, &from_len)) < 0) {
// What happened?
*err = TFTP_NETERR;
close(s);
return -1;
}
if (ntohs(hdr->th_opcode) == ACK) {
if (ntohs(hdr->th_block) == last_good_block) {
// Advance pointers, etc
sfp = fp;
res += (actual_len - 4);
last_good_block++;
} else {
diag_printf("Send block #%d, got ACK for #%d\n",
last_good_block, ntohs(hdr->th_block));
}
} else
if (ntohs(hdr->th_opcode) == ERROR) {
*err = ntohs(hdr->th_code);
close(s);
return -1;
} else {
// What kind of packet is this?
*err = TFTP_PROTOCOL;
close(s);
return -1;
}
}
}
close(s);
return res;
}
 
// EOF tftp_client.c
/ifaddrs.c
0,0 → 1,318
//==========================================================================
//
// src/ifaddrs.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
 
//
// Adapted from KAME getifaddrs.c, if_nametoindex.c, if_indextoname.c
//
 
/* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */
/* $KAME: if_nametoindex.c,v 1.6 2000/11/24 08:18:54 itojun Exp $ */
/* $KAME: if_indextoname.c,v 1.7 2000/11/08 03:09:30 itojun Exp $ */
 
/*
* Copyright (c) 1995, 1999
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
*/
 
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
 
#undef _KERNEL
#undef __INSIDE_NET
#include <sys/param.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <errno.h>
#include <netinet/in.h>
#include <net/netdb.h>
#include <ifaddrs.h>
 
#if !defined(AF_LINK)
#define SA_LEN(sa) sizeof(struct sockaddr)
#endif
 
#if !defined(SA_LEN)
#define SA_LEN(sa) (sa)->sa_len
#endif
 
#define SALIGN (sizeof(long) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
 
#ifndef ALIGNBYTES
/*
* On systems with a routing socket, ALIGNBYTES should match the value
* that the kernel uses when building the messages.
*/
#define ALIGNBYTES XXX
#endif
#ifndef ALIGN
#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
#endif
 
int
getifaddrs(struct ifaddrs **pif)
{
int icnt = 1; // Interface count
int dcnt = 0; // Data [length] count
int ncnt = 0; // Length of interface names
char buf[1024];
int i, sock;
struct ifconf ifc;
struct ifreq *ifr, *lifr;
char *data, *names;
struct ifaddrs *ifa, *ift;
 
ifc.ifc_buf = buf;
ifc.ifc_len = sizeof(buf);
 
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return (-1);
i = ioctl(sock, SIOCGIFCONF, (char *)&ifc);
close(sock);
if (i < 0)
return (-1);
 
ifr = ifc.ifc_req;
lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
 
while (ifr < lifr) {
struct sockaddr *sa;
 
sa = &ifr->ifr_addr;
++icnt;
dcnt += SA_RLEN(sa);
ncnt += sizeof(ifr->ifr_name) + 1;
if (SA_LEN(sa) < sizeof(*sa))
ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
else
ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
}
 
if (icnt + dcnt + ncnt == 1) {
// Nothing found
*pif = NULL;
free(buf);
return (0);
}
data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
if (data == NULL) {
free(buf);
return(-1);
}
 
ifa = (struct ifaddrs *)(void *)data;
data += sizeof(struct ifaddrs) * icnt;
names = data + dcnt;
 
memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
ift = ifa;
 
ifr = ifc.ifc_req;
lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
 
while (ifr < lifr) {
struct sockaddr *sa;
 
ift->ifa_name = names;
names[sizeof(ifr->ifr_name)] = 0;
strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
while (*names++) ;
 
ift->ifa_addr = (struct sockaddr *)data;
sa = &ifr->ifr_addr;
memcpy(data, sa, SA_LEN(sa));
data += SA_RLEN(sa);
if (SA_LEN(sa) < sizeof(*sa))
ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
else
ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
ift = (ift->ifa_next = ift + 1);
}
 
if (--ift >= ifa) {
ift->ifa_next = NULL;
*pif = ifa;
} else {
*pif = NULL;
free(ifa);
}
return (0);
}
 
void
freeifaddrs(struct ifaddrs *ifp)
{
free(ifp);
}
 
void
_show_all_interfaces(void)
{
struct ifaddrs *iflist, *ifp;
char addr[64];
int indx;
 
if (getifaddrs(&iflist) < 0) {
diag_printf("Can't get interface information!!\n");
return;
}
ifp = iflist;
while (ifp != (struct ifaddrs *)NULL) {
if (ifp->ifa_addr->sa_family != AF_LINK) {
getnameinfo (ifp->ifa_addr, ifp->ifa_addr->sa_len, addr, sizeof(addr), 0, 0, 0);
diag_printf("%p - %s - %s\n", ifp, ifp->ifa_name, addr);
}
ifp = ifp->ifa_next;
}
indx = if_nametoindex(iflist->ifa_name);
diag_printf("indx(%s) = %d\n", iflist->ifa_name, indx);
if (indx > 0) {
if (if_indextoname(indx, addr)) {
diag_printf("index(%s) = %d/%s\n", iflist->ifa_name, indx, addr);
} else {
diag_printf("index(%s) = %d: %s\n", iflist->ifa_name, indx, strerror(errno));
}
} else {
diag_printf("index(%s): %s\n", iflist->ifa_name, strerror(errno));
}
freeifaddrs(iflist);
}
 
/*
* From RFC 2553:
*
* 4.1 Name-to-Index
*
*
* The first function maps an interface name into its corresponding
* index.
*
* #include <net/if.h>
*
* unsigned int if_nametoindex(const char *ifname);
*
* If the specified interface name does not exist, the return value is
* 0, and errno is set to ENXIO. If there was a system error (such as
* running out of memory), the return value is 0 and errno is set to the
* proper value (e.g., ENOMEM).
*/
 
unsigned int
if_nametoindex(const char *ifname)
{
struct ifaddrs *ifaddrs, *ifa;
unsigned int ni;
 
if (getifaddrs(&ifaddrs) < 0)
return(0);
 
ni = 0;
 
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK &&
strcmp(ifa->ifa_name, ifname) == 0) {
ni = ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index;
break;
}
}
 
freeifaddrs(ifaddrs);
if (!ni)
errno = ENXIO;
return(ni);
}
 
/*
* From RFC 2533:
*
* The second function maps an interface index into its corresponding
* name.
*
* #include <net/if.h>
*
* char *if_indextoname(unsigned int ifindex, char *ifname);
*
* The ifname argument must point to a buffer of at least IF_NAMESIZE
* bytes into which the interface name corresponding to the specified
* index is returned. (IF_NAMESIZE is also defined in <net/if.h> and
* its value includes a terminating null byte at the end of the
* interface name.) This pointer is also the return value of the
* function. If there is no interface corresponding to the specified
* index, NULL is returned, and errno is set to ENXIO, if there was a
* system error (such as running out of memory), if_indextoname returns
* NULL and errno would be set to the proper value (e.g., ENOMEM).
*/
 
char *
if_indextoname(unsigned int ifindex, char *ifname)
{
struct ifaddrs *ifaddrs, *ifa;
int error = 0;
 
if (getifaddrs(&ifaddrs) < 0)
return(NULL); /* getifaddrs properly set errno */
 
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK &&
ifindex == ((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index)
break;
}
 
if (ifa == NULL) {
error = ENXIO;
ifname = NULL;
}
else
strncpy(ifname, ifa->ifa_name, IFNAMSIZ);
 
freeifaddrs(ifaddrs);
 
errno = error;
return(ifname);
}
/bootp_support.c
0,0 → 1,580
//==========================================================================
//
// lib/bootp_support.c
//
// Minimal BOOTP functions
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-01-10
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
// BOOTP support (and a little DHCP support also)
 
#include <pkgconf/system.h>
#include <pkgconf/net.h>
#include <pkgconf/isoinfra.h>
 
#include <network.h>
#include <errno.h>
#ifdef CYGPKG_NET_FREEBSD_STACK // New layout
#include <net/if_var.h>
#include <netinet/in_var.h>
#include <netinet6/nd6.h>
#endif
 
#ifdef CYGINT_ISO_DNS
#include <netdb.h>
#endif
 
#ifndef CYGPKG_LIBC_STDIO
#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
#endif
 
// 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;
cyg_bool_t retcode = true;
 
// Ensure clean slate
cyg_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 = HTYPE_ETHERNET;
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) {
// This is an "acceptable" error, it means there is no server for
// us: do not initialize the interface.
retcode = false;
}
 
// Shut things down regardless of success of rx, otherwise other
// interfaces cannot be initialised!
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 retcode;
}
 
static char *_bootp_op[] = {"", "REQUEST", "REPLY"};
static char *_bootp_hw_type[] = {"", "Ethernet", "Exp Ethernet", "AX25",
"Pronet", "Chaos", "IEEE802", "Arcnet"};
 
static char *_dhcpmsgs[] = {"","DISCOVER", "OFFER", "REQUEST", "DECLINE",
"ACK", "NAK", "RELEASE" };
 
void
show_bootp(const char *intf, struct bootp *bp)
{
int i, len;
unsigned char *op, *ap = 0, optover;
unsigned char name[128];
struct in_addr addr[32];
unsigned int length;
diag_printf("BOOTP[%s] op: %s\n", intf, _bootp_op[bp->bp_op]);
diag_printf(" htype: %s\n", _bootp_hw_type[bp->bp_htype]);
diag_printf(" hlen: %d\n", bp->bp_hlen );
diag_printf(" hops: %d\n", bp->bp_hops );
diag_printf(" xid: 0x%x\n", bp->bp_xid );
diag_printf(" secs: %d\n", bp->bp_secs );
diag_printf(" flags: 0x%x\n", bp->bp_flags );
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));
 
optover = 0; // See whether sname and file are overridden for options
length = sizeof(optover);
(void)get_bootp_option( bp, TAG_DHCP_OPTOVER, &optover, &length );
if ( !(1 & optover) && bp->bp_sname[0] )
diag_printf(" server: %s\n", bp->bp_sname);
if ( ! (2 & optover) && 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;
case TAG_DHCP_MESS_TYPE:
diag_printf(" DHCP message: %d %s\n",
op[2], _dhcpmsgs[op[2]] );
break;
case TAG_DHCP_REQ_IP:
diag_printf(" DHCP requested ip: %d.%d.%d.%d\n",
op[2], op[3], op[4], op[5] );
break;
case TAG_DHCP_LEASE_TIME :
case TAG_DHCP_RENEWAL_TIME :
case TAG_DHCP_REBIND_TIME :
diag_printf(" DHCP time %d: %d\n",
*op, ((((((op[2]<<8)+op[3])<<8)+op[4])<<8)+op[5]) );
 
break;
case TAG_DHCP_SERVER_ID :
diag_printf(" DHCP server id: %d.%d.%d.%d\n",
op[2], op[3], op[4], op[5] );
break;
 
case TAG_DHCP_OPTOVER :
case TAG_DHCP_PARM_REQ_LIST:
case TAG_DHCP_TEXT_MESSAGE :
case TAG_DHCP_MAX_MSGSZ :
case TAG_DHCP_CLASSID :
case TAG_DHCP_CLIENTID :
diag_printf(" DHCP option: %x/%d.%d:", *op, *op, *(op+1));
if ( 1 == op[1] )
diag_printf( " %d", op[2] );
else if ( 2 == op[1] )
diag_printf( " %d", (op[2]<<8)+op[3] );
else if ( 4 == op[1] )
diag_printf( " %d", ((((((op[2]<<8)+op[3])<<8)+op[4])<<8)+op[5]) );
else
for ( i = 2; i < 2 + op[1]; i++ )
diag_printf(" %d",op[i]);
diag_printf("\n");
break;
 
default:
diag_printf("Unknown option: %x/%d.%d:", *op, *op, *(op+1));
for ( i = 2; i < 2 + op[1]; i++ )
diag_printf(" %d",op[i]);
diag_printf("\n");
break;
}
op += *(op+1)+2;
}
}
}
 
cyg_bool_t
get_bootp_option(struct bootp *bp, unsigned char tag, void *opt,
unsigned int *length)
{
unsigned char *val = (unsigned char *)opt;
int i;
cyg_uint8 optover;
#define SCANTAG( ptr ) CYG_MACRO_START \
unsigned int max; \
unsigned char *op = (ptr); \
while (*op != TAG_END) { \
if (*op == tag) { \
max=(*(op+1)>*length ? *length : *(op+1)); \
for (i = 0; i < max; i++) { \
*val++ = *(op+i+2); \
} \
*length=max; \
return true; \
} \
op += *(op+1)+2; \
} \
CYG_MACRO_END
 
SCANTAG( &bp->bp_vend[4] );
 
if ( TAG_DHCP_OPTOVER == tag ) // prevent recursion > once
return false;
// else, look for that tag to see if there's more...
optover = 0;
if ( ! get_bootp_option( bp, TAG_DHCP_OPTOVER, &optover, length) )
return false;
 
if ( 1 & optover ) // then the file field also holds options
SCANTAG( &bp->bp_file[0] );
 
if ( 2 & optover ) // then the sname field also holds options
SCANTAG( &bp->bp_sname[0] );
 
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;
unsigned int length;
 
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
 
// Must do this temporarily with default route and netmask so that
// [sub]netmask can be set.
strcpy(ifr.ifr_name, intf);
if (ioctl(s, SIOCSIFADDR, &ifr)) {
perror("SIOCIFADDR");
return false;
}
 
length = sizeof(addrp->sin_addr);
if (get_bootp_option(bp, TAG_SUBNET_MASK, &addrp->sin_addr,&length)) {
netmask = addrp->sin_addr;
if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
perror("SIOCSIFNETMASK");
return false;
}
// Must do this again so that [sub]netmask (and so default route)
// is taken notice of.
addrp->sin_addr = bp->bp_yiaddr; // The address BOOTP gave us
if (ioctl(s, SIOCSIFADDR, &ifr)) {
perror("SIOCIFADDR 2");
return false;
}
}
 
length = sizeof(addrp->sin_addr);
if (get_bootp_option(bp, TAG_IP_BROADCAST, &addrp->sin_addr,&length)) {
if (ioctl(s, SIOCSIFBRDADDR, &ifr)) {
perror("SIOCSIFBRDADDR");
return false;
}
// Do not re-set the IFADDR after this; doing *that* resets the
// BRDADDR to the default!
}
 
ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
perror("SIOCSIFFLAGS");
return false;
}
 
// Set up routing
length = sizeof(addrp->sin_addr);
if (get_bootp_option(bp, TAG_GATEWAY, &gateway,&length)) {
// ...and it's a nonzero address...
if ( 0 != gateway.s_addr ) {
memset(&route, 0, sizeof(route));
addrp->sin_family = AF_INET;
addrp->sin_port = 0;
addrp->sin_len = sizeof(*addrp);
addrp->sin_addr.s_addr = 0; // Use 0,0,GATEWAY for the default route
memcpy(&route.rt_dst, addrp, sizeof(*addrp));
addrp->sin_addr.s_addr = 0;
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);
#ifdef CYGINT_ISO_DNS
{
#define MAX_IP_ADDR_LEN 16
char buf[BP_MAX_OPTION_LEN+1];
memset(buf,0,sizeof(buf));
length = sizeof(buf);
if (get_bootp_option(bp, TAG_DOMAIN_NAME, buf, &length)) {
setdomainname(buf, length);
}
length = sizeof(buf);
if (get_bootp_option(bp, TAG_DOMAIN_SERVER, buf, &length)) {
cyg_dns_res_init((struct in_addr *)buf);
}
}
#endif
return true;
}
 
#ifdef INET6
extern const struct in6_addr in6mask128;
cyg_bool_t
init_net_IPv6(const char *intf, struct bootp *bp, char *prefix)
{
int s;
struct in6_aliasreq in6_addr;
char in6_ip[128];
 
// Set up non link-layer address
s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s < 0) {
perror("socket IPv6");
return false;
}
bzero(&in6_addr, sizeof(in6_addr));
diag_sprintf(in6_ip, "%s::%s", prefix, inet_ntoa(bp->bp_yiaddr));
in6_addr.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
in6_addr.ifra_addr.sin6_family = AF_INET6;
if (!inet_pton(AF_INET6, in6_ip, (char *)&in6_addr.ifra_addr.sin6_addr)) {
diag_printf("Can't set IPv6 address: %s\n", in6_ip);
return false;
}
in6_addr.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
in6_addr.ifra_prefixmask.sin6_family = AF_INET6;
in6_addr.ifra_prefixmask.sin6_addr = in6mask128;
strcpy(in6_addr.ifra_name, intf);
in6_addr.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
in6_addr.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
if (ioctl(s, SIOCAIFADDR_IN6, &in6_addr)) {
perror("SIOCAIFADDR_IN6");
return false;
}
close(s);
return true;
}
#endif
 
// EOF bootp_support.c
/getserv.c
0,0 → 1,99
//==========================================================================
//
// lib/getserv.c
//
// getservbyname(), getservbyport()
//
//==========================================================================
//####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####
//
//==========================================================================
 
 
#include <sys/param.h>
#include <netdb.h>
#include <errno.h>
 
// These must return the port in network byte order.
//
// This means treated as a short, because it's a port, despite the types in
// the API and the struct being ints.
//
// The argument to getservbyport() is also network byte order, so that code
// must change to flip before comparing.
 
static struct servent services[] = {
{ "ftp", 0, 21 , "tcp" },
{ "ftp-data", 0, 20 , "tcp" },
{ "domain", 0, 53 , "udp" },
{ "tftp", 0, 69 , "udp" },
{ "snmp", 0, 161 , "udp" },
 
{ NULL, 0, 0 , NULL }
};
 
// Note that this contains no interlocking between clients of the
// interface; but this is completely typical of such APIs.
 
static struct servent *
setreturned( struct servent *p )
{
static struct servent returned;
 
returned.s_name = p->s_name;
returned.s_aliases = p->s_aliases;
returned.s_port = htons(p->s_port); // return in net order
returned.s_proto = p->s_proto;
return &returned;
}
 
struct servent *
getservbyname(const char *name, const char *proto)
{
struct servent *p = services;
while (p->s_name) {
if ((strcmp(name, p->s_name) == 0) &&
(strcmp(proto, p->s_proto) == 0)) {
return setreturned(p);
}
p++;
}
errno = ENOENT;
return (struct servent *)0;
}
 
struct servent *
getservbyport(const int num, const char *proto)
{
struct servent *p = services;
int port = ntohs(num);
while (p->s_name) {
if ((p->s_port == port) &&
(strcmp(proto, p->s_proto) == 0)) {
return setreturned(p);
}
p++;
}
errno = ENOENT;
return (struct servent *)0;
}
/inet_ntoa.c
0,0 → 1,70
//==========================================================================
//
// src/inet_ntoa.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
 
 
/*
* Copyright 1994, 1995 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/libkern/inet_ntoa.c,v 1.2.16.1 2000/08/03 01:03:45 peter Exp $
*/
 
#include <sys/param.h>
#include <netinet/in.h>
 
char *
inet_ntoa(struct in_addr ina)
{
static char buf[4*sizeof "123"];
unsigned char *ucp = (unsigned char *)&ina;
 
diag_sprintf(buf, "%d.%d.%d.%d",
ucp[0] & 0xff,
ucp[1] & 0xff,
ucp[2] & 0xff,
ucp[3] & 0xff);
return buf;
}
 
/dhcp_prot.c
0,0 → 1,1366
/*==========================================================================
//
// dhcp_prot.c
//
// DHCP protocol implementation for DHCP client
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): hmt
// Contributors: gthomas
// Date: 2000-07-01
// Purpose: DHCP support
// Description:
//
//####DESCRIPTIONEND####
//
//========================================================================*/
 
#include <pkgconf/system.h>
#include <pkgconf/net.h>
 
#ifdef CYGPKG_NET_DHCP
 
#if 0
#define perror( txt ) // nothing
#endif
 
#include <network.h>
#include <dhcp.h>
#include <errno.h>
 
#include <cyg/infra/cyg_ass.h>
 
#ifdef INET6
#include <net/if_var.h>
#include <netinet6/in6_var.h>
#endif
 
// ------------------------------------------------------------------------
// Returns a pointer to the end of dhcp message (or NULL if invalid)
// meaning the address of the byte *after* the TAG_END token in the vendor
// data.
 
static unsigned char *
scan_dhcp_size( struct bootp *ppkt )
{
unsigned char *op;
op = &ppkt->bp_vend[0];
// First check for the cookie!
if ( op[0] != 99 ||
op[1] != 130 ||
op[2] != 83 ||
op[3] != 99 ) {
CYG_FAIL( "Bad DHCP cookie" );
return NULL;
}
op += 4;
while (*op != TAG_END) {
op += *(op+1)+2;
if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
CYG_FAIL( "Oversize DHCP packet in dhcp_size" );
return NULL;
}
}
// Check op has not gone wild
CYG_ASSERT( op > (unsigned char *)(&ppkt[0]), "op pointer underflow!" );
// Compare op with non-existent "next" struct bootp in the array.
CYG_ASSERT( op < (unsigned char *)(&ppkt[1]), "op pointer overflow!" );
return op + 1; // Address of first invalid byte
}
 
// ------------------------------------------------------------------------
// Get the actual packet size of an initialized buffer
 
static int
dhcp_size( struct bootp *ppkt )
{
unsigned char *op;
 
op = scan_dhcp_size( ppkt );
if ( !op ) return 0;
return (op - (unsigned char *)ppkt);
}
 
 
// ------------------------------------------------------------------------
// Get the actual packet size of an initialized buffer
// This will also pad the packet with 0 if length is less
// than BP_STD_TX_MINPKTSZ.
 
static int
dhcp_size_for_send( struct bootp *ppkt )
{
unsigned char *op;
 
op = scan_dhcp_size( ppkt );
if ( !op ) return 0; // Better not scribble!
// Zero extra bytes until the packet is large enough.
for ( ; op < (((unsigned char *)ppkt) + BP_STD_TX_MINPKTSZ); op++ )
*op = 0;
return (op - (unsigned char *)ppkt);
}
 
// ------------------------------------------------------------------------
// Insert/set an option value in an initialized buffer
 
static int
set_fixed_tag( struct bootp *ppkt,
unsigned char tag,
cyg_uint32 value,
int len)
{
unsigned char *op;
 
// Initially this will only scan the options field.
op = &ppkt->bp_vend[4];
while (*op != TAG_END) {
if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
CYG_FAIL( "Oversize DHCP packet in set_fixed_tag" );
return false;
}
if (*op == tag) // Found it...
break;
op += *(op+1)+2;
}
if (*op == tag) { // Found it...
if ( *(op+1) != len ) {
CYG_FAIL( "Wrong size in set_fixed_tag" );
return false; // wrong size
}
}
else { // overwrite the end tag and install a new one
if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
CYG_FAIL( "Oversize DHCP packet in set_fixed_tag append" );
return false;
}
*op = tag;
*(op+1) = len;
*(op + len + 2) = TAG_END;
}
// and insert the value. Net order is BE.
op += len + 2 - 1; // point to end of value
while ( len-- > 0 ) {
*op-- = (unsigned char)(value & 255);
value >>= 8;
}
return true;
}
 
// Note that this does not permit changing the size of an extant tag.
static int
set_variable_tag( struct bootp *ppkt,
unsigned char tag,
cyg_uint8 *pvalue,
int len)
{
unsigned char *op;
 
// Initially this will only scan the options field.
op = &ppkt->bp_vend[4];
while (*op != TAG_END) {
if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
CYG_FAIL( "Oversize DHCP packet in set_variable_tag" );
return false;
}
if (*op == tag) // Found it...
break;
op += *(op+1)+2;
}
if (*op == tag) { // Found it...
if ( *(op+1) != len ) {
CYG_FAIL( "Wrong size in set_variable_tag" );
return false; // wrong size
}
}
else { // overwrite the end tag and install a new one
if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
CYG_FAIL( "Oversize DHCP packet in set_variable_tag append" );
return false;
}
*op = tag;
*(op+1) = len;
*(op + len + 2) = TAG_END;
}
// and insert the value. No order is implied.
op += 2; // point to start of value
while ( len-- > 0 ) {
*op++ = *pvalue++;
}
return true;
}
 
static int
unset_tag( struct bootp *ppkt,
unsigned char tag )
{
unsigned char *op, *nextp = 0, *killp = 0;
 
// Initially this will only scan the options field.
op = &ppkt->bp_vend[4];
while (*op != TAG_END) {
if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
CYG_FAIL( "Oversize DHCP packet in unset_tag" );
return false;
}
if (*op == tag) { // Found it...
killp = op; // item to kill
nextp = op + *(op+1)+2; // next item address
}
op += *(op+1)+2; // scan to the end
}
 
if ( !killp )
return false;
 
// Obliterate the found op by copying down: *op is the end.
while( nextp <= op ) // <= to copy the TAG_END too.
*killp++ = *nextp++;
return true;
}
 
// ------------------------------------------------------------------------
// Bring up an interface enough to broadcast, before we know who we are
 
static int
bring_half_up(const char *intf, struct ifreq *ifrp )
{
int s;
int one = 1;
 
struct sockaddr_in *addrp;
struct ecos_rtentry route;
 
// Ensure clean slate
cyg_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 *) &ifrp->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(ifrp->ifr_name, intf);
if (ioctl(s, SIOCSIFADDR, ifrp)) { /* set ifnet address */
perror("SIOCSIFADDR");
return false;
}
 
if (ioctl(s, SIOCSIFNETMASK, ifrp)) { /* set net addr mask */
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, ifrp)) { /* set broadcast addr */
perror("SIOCSIFBRDADDR");
return false;
}
 
ifrp->ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
if (ioctl(s, SIOCSIFFLAGS, ifrp)) { /* set ifnet flags */
perror("SIOCSIFFLAGS up");
return false;
}
 
if (ioctl(s, SIOCGIFHWADDR, ifrp) < 0) { /* get MAC address */
perror("SIOCGIFHWADDR 1");
return false;
}
 
// Set up routing
addrp->sin_family = AF_INET;
addrp->sin_port = 0;
addrp->sin_len = sizeof(*addrp); // Size of address
 
/* 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_addr.s_addr = INADDR_ANY;
memcpy(&route.rt_dst, addrp, sizeof(*addrp));
memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
 
route.rt_dev = ifrp->ifr_name;
route.rt_flags = RTF_UP|RTF_GATEWAY;
route.rt_metric = 0;
 
if (ioctl(s, SIOCADDRT, &route)) { /* add route */
if (errno != EEXIST) {
perror("SIOCADDRT 3");
return false;
}
}
 
close(s);
 
return true;
}
 
 
// ------------------------------------------------------------------------
// DHCP retransmission timeouts and number of tries
//
// To work better with simulated failures (or real ones!) so that the rest
// of the system is tested, rather than DHCP renewal failures pulling
// everything down, we try a little more zealously than the RFC suggests.
 
static unsigned char timeout_random = 0;
 
struct timeout_state {
unsigned int secs;
int countdown;
};
 
static inline void reset_timeout( struct timeval *ptv, struct timeout_state *pstate )
{
timeout_random++;
pstate->countdown = 4; // initial fast retries
pstate->secs = 3 + (timeout_random & 3);
ptv->tv_sec = 0;
ptv->tv_usec = 65536 * (2 + (timeout_random & 3)); // 0.1 - 0.3S, about
}
 
static inline int next_timeout( struct timeval *ptv, struct timeout_state *pstate )
{
if ( 0 < pstate->countdown-- )
return true;
if ( 0 == ptv->tv_sec )
ptv->tv_sec = pstate->secs;
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 < 100; // If longer, too many tries...
}
 
// ------------------------------------------------------------------------
// Lease expiry and alarms to notify it
 
static 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;
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;
// 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 ,&length))
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, &length ))
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, &length ))
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.
set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
}
 
// ------------------------------------------------------------------------
// the DHCP state machine - this does all the work
 
int
do_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;
int one = 1;
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.
if ( DHCPSTATE_INIT == oldstate
|| DHCPSTATE_FAILED == oldstate
|| 0 == oldstate ) {
// either explicit init state or the beginning of time or retry
if ( ! bring_half_up( intf, &ifr ) )
return false;
 
*pstate = DHCPSTATE_INIT;
}
 
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;
}
 
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");
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;
}
// 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 );
 
// Choose a new XID: first get the ESA as a basis:
strcpy(&ifr.ifr_name[0], intf);
if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
perror("SIOCGIFHWADDR 2");
return false;
}
 
// Choose from scratch depending on ifr_hwaddr...[]
xid = ifr.ifr_hwaddr.sa_data[5];
xid |= (ifr.ifr_hwaddr.sa_data[4]) << 8;
xid |= (ifr.ifr_hwaddr.sa_data[3]) << 16;
xid |= (ifr.ifr_hwaddr.sa_data[2]) << 24;
xid ^= (cyg_arc4random() & 0xffff0000);
 
// Avoid adjacent ESAs colliding by increment
#define NEW_XID(_xid) CYG_MACRO_START (_xid)+= 0x10000; CYG_MACRO_END
 
while ( 1 ) {
 
// If we are active rather than in the process of shutting down,
// check for any lease expiry every time round, so that alarms
// *can* change the course of events even when already renewing,
// for example.
if ( DHCPSTATE_DO_RELEASE != *pstate
&& DHCPSTATE_NOTBOUND != *pstate
&& DHCPSTATE_FAILED != *pstate ) {
cyg_uint8 lease_state;
 
cyg_scheduler_lock();
lease_state = lease->which;
lease->which = 0; // flag that we have noticed it
cyg_scheduler_unlock();
 
if ( lease_state & DHCP_LEASE_EX ) {
// then the lease has expired completely!
*pstate = DHCPSTATE_NOTBOUND;
}
else if ( lease_state & DHCP_LEASE_T2 ) {
// Time to renew
reset_timeout( &tv, &timeout_scratch ); // next conversation
*pstate = DHCPSTATE_REBINDING;
}
else if ( lease_state & DHCP_LEASE_T1 ) {
// Time to renew
reset_timeout( &tv, &timeout_scratch ); // next conversation
*pstate = DHCPSTATE_RENEWING;
}
}
 
switch ( *pstate ) {
 
case DHCPSTATE_INIT:
 
// Send the DHCPDISCOVER packet
 
// Fill in the BOOTP request - DHCPDISCOVER packet
bzero(xmit, sizeof(*xmit));
xmit->bp_op = BOOTREQUEST;
xmit->bp_htype = HTYPE_ETHERNET;
xmit->bp_hlen = IFHWADDRLEN;
xmit->bp_xid = xid;
xmit->bp_secs = 0;
xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
bcopy(ifr.ifr_hwaddr.sa_data, &xmit->bp_chaddr, xmit->bp_hlen);
bcopy(mincookie, xmit->bp_vend, sizeof(mincookie));
 
// remove the next line to test ability to handle bootp packets.
set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPDISCOVER, 1 );
// 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_INIT sending:\n" );
show_bootp( intf, xmit );
#endif
if(sendto(s, xmit, dhcp_size_for_send(xmit), 0,
(struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
*pstate = DHCPSTATE_FAILED;
break;
}
 
seen_bootp_reply = 0;
*pstate = DHCPSTATE_SELECTING;
break;
 
case DHCPSTATE_SELECTING:
// This is a separate state so that we can listen again
// *without* retransmitting.
// listen for the DHCPOFFER reply
 
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 (this time)
if ( seen_bootp_reply ) { // then already have a bootp reply
// Save the good packet in *xmit
bcopy( received, xmit, dhcp_size(received) );
*pstate = DHCPSTATE_BOOTP_FALLBACK;
NEW_XID( xid ); // Happy to advance, so new XID
reset_timeout( &tv, &timeout_scratch );
break;
}
// go to the next larger timeout and re-send:
if ( ! next_timeout( &tv, &timeout_scratch ) ) {
*pstate = DHCPSTATE_FAILED;
break;
}
*pstate = DHCPSTATE_INIT; // to retransmit
break;
}
// Check for well-formed packet with correct termination (not truncated)
length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_SELECTING 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() ) // XID and ESA matches?
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,
&length);
}
 
// see if it was a DHCP reply or a bootp reply; it could be
// either.
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
&length) ) {
if ( DHCPOFFER == msgtype ) { // all is well
// Save the good packet in *xmit
bcopy( received, xmit, dhcp_size(received) );
// we like the packet, so reset the timeout for next time
reset_timeout( &tv, &timeout_scratch );
*pstate = DHCPSTATE_REQUESTING;
NEW_XID( xid ); // Happy to advance, so new XID
}
}
else // No TAG_DHCP_MESS_TYPE entry so it's a bootp reply
seen_bootp_reply = 1; // (keep the bootp packet in received)
// If none of the above state changes occurred, we got a packet
// that "should not happen", OR we have a bootp reply in our
// hand; so listen again with the same timeout, without
// retrying the send, in the hope of getting a DHCP reply.
break;
 
case DHCPSTATE_REQUESTING:
// Just send what you got with a DHCPREQUEST in the message type.
// then wait for an ACK in DHCPSTATE_REQUEST_RECV.
 
// Fill in the BOOTP request - DHCPREQUEST packet
xmit->bp_xid = xid;
xmit->bp_op = BOOTREQUEST;
xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
 
set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
// Set all the tags we want to use when sending a packet
set_default_dhcp_tags( xmit );
// And this will be a new one:
set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_REQUESTING 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;
if(sendto(s, &xmit2, xlen, 0,
(struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
*pstate = DHCPSTATE_FAILED;
break;
}
 
*pstate = DHCPSTATE_REQUEST_RECV;
break;
 
case DHCPSTATE_REQUEST_RECV:
// wait for an ACK or a NACK - retry by going back to
// DHCPSTATE_REQUESTING; NACK means go back to INIT.
 
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 ) ) {
*pstate = DHCPSTATE_FAILED;
break;
}
*pstate = DHCPSTATE_REQUESTING;
break;
}
// Check for well-formed packet with correct termination (not truncated)
length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_REQUEST_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,
&length);
}
 
// check it was a DHCP reply
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
&length) ) {
if ( DHCPACK == msgtype // Same offer & server?
&& received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr
&& received->bp_siaddr.s_addr == xmit->bp_siaddr.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 // Same server?
&& received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr) {
// we're bounced!
*pstate = DHCPSTATE_INIT; // So back the start of the rigmarole.
NEW_XID( xid ); // Unhappy to advance, so new XID
reset_timeout( &tv, &timeout_scratch );
break;
}
// otherwise it's something else, maybe another offer, or a bogus
// NAK from someone we are not asking!
// Just listen again, which implicitly discards it.
}
break;
 
case DHCPSTATE_BOUND:
 
// We are happy now, we have our address.
 
// All done with socket
close(s);
 
// Re-initialize the interface with the new state
if ( DHCPSTATE_BOUND != 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_RENEWING:
// Just send what you got with a DHCPREQUEST in the message
// type UNICAST straight to the server. Then wait for an ACK.
 
// 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 );
// Set unicast address to *server*
server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
 
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_RENEWING 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_RENEW_RECV;
break;
 
case DHCPSTATE_RENEW_RECV:
// wait for an ACK or a NACK - retry by going back to
// DHCPSTATE_RENEWING; NACK means go to NOTBOUND.
// No answer means just wait for T2, to broadcast.
 
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 T2
// expires - retain the lease meanwhile. The normal
// lease mechanism will invoke REBINDING as and when
// necessary.
*pstate = DHCPSTATE_BOUND;
break;
}
*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,
&length);
}
 
// check it was a DHCP reply
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
&length) ) {
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;
if(sendto(s, &xmit2, xlen, 0,
(struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
*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,
&length);
}
 
// check it was a DHCP reply
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
&length) ) {
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 reinitialization
 
int
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;
 
// Ensure clean slate
cyg_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");
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");
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)
{
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
/ipv6_routing_thread.c
0,0 → 1,343
//==========================================================================
//
// ipv6_routing_thread.c
//
// IPv6 routing support
//
//==========================================================================
//####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, lhamilton
// Date: 2002-04-16
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
// IPv6 routing support
 
#include <pkgconf/net.h>
#undef _KERNEL
#include <sys/param.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <errno.h>
 
#include <cyg/kernel/kapi.h>
 
#include <net/if.h>
#include <ifaddrs.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netdb.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
 
void _show_all_interfaces(void);
 
#define DBG_PRINT 1
#define ALLROUTER "ff02::2"
 
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL+2048
#define _1_MILLION 1000000
#define STATE_DELAY 0
#define STATE_PROBE 1
#define STATE_IDLE 2
 
#define MAX_RTR_SOLICITATIONS 3
#define SEL_TIMEOUT_IDLE 145
#define SECONDS_TILL_RS_SEND (12*60*60)
 
static char rs_stack[STACK_SIZE];
static cyg_thread rs_thread_data;
static cyg_handle_t rs_thread_handle;
static int s;
static int probe=0;
static int racount=0;
static int state;
static int badra;
static int cc = sizeof(struct icmp6_hdr);
static u_char outpack[sizeof(struct icmp6_hdr)];
struct sockaddr_in6 to;
static struct timeval select_timeout;
static struct timeval last_ra_time;
static struct timeval idle_expire;
static struct icmp6stat *istat;
extern struct icmp6stat cyg_icmp6stat;
 
static void
cyg_rs_exit(void)
{
diag_printf("<%s>\n", __FUNCTION__);
cyg_thread_exit();
}
 
static void
dprnt(const char *msg, ...)
{
#ifdef DBG_PRINT
va_list ap;
 
va_start(ap, msg);
(void) vfprintf(stdout, msg, ap);
(void) fprintf(stdout, "\n");
va_end(ap);
#endif
}
 
#ifdef DBG_PRINT
void
sleep_msg(char *str, int total)
{
int hours, minutes;
 
hours = total / 3600;
total -= hours * 3600;
minutes = total / 60;
total -= minutes * 60;
 
if (hours > 0)
dprnt("%s: %d hr, %d min", str, hours, minutes);
else if (minutes > 0)
dprnt("%s: %d min, %d sec", str, minutes, total);
else
dprnt("%s: %d sec", str, total);
}
#endif
 
void
get_realtime(struct timeval *now)
{
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
now->tv_sec = tp.tv_sec;
now->tv_usec = 0;
}
 
void
send_rs_packet(void)
{
probe++;
 
dprnt("%s: probe=%d", __FUNCTION__, probe);
 
if (sendto(s, outpack, cc, 0, (struct sockaddr *)&to, to.sin6_len) < 0) {
dprnt("%s: can't send RS: %s", __FUNCTION__, strerror(errno));
}
}
 
void
receive_ra_packet(void)
{
int len;
char msg[1024];
 
dprnt("%s", __FUNCTION__);
 
len = read(s, msg, sizeof(msg));
if (len < 0) {
dprnt(" Can't read RA data: %s", strerror(errno));
return;
}
dprnt("packet data (buf len=%d) :", len);
diag_dump_buf(msg, len);
 
racount++;
get_realtime(&last_ra_time);
dprnt("racount=%d, timestamp=%d sec",
racount, last_ra_time.tv_sec);
 
if (badra != istat->icp6s_badra) {
/* BAD RA received by ipv6 stack (nd6_ra_input).
Resend RS packet. */
badra = istat->icp6s_badra;
dprnt("<Bad RA (Router Advertisement)>");
return;
}
/* Check the ICMPv6 RA Code */
if (msg[1] != 0) {
len = (int)msg[1];
dprnt("<Bad ICMPv6 Code: %d>", len);
return;
}
 
/* RA received, go idle for SECONDS_TILL_RS_SEND */
idle_expire.tv_sec = last_ra_time.tv_sec +
SECONDS_TILL_RS_SEND;
probe = 0;
select_timeout.tv_sec = SEL_TIMEOUT_IDLE;
if (state != STATE_IDLE)
dprnt("Going IDLE, thread listening");
state = STATE_IDLE;
}
 
void
check_timer(void)
{
struct timeval now;
 
if (state == STATE_DELAY) {
probe = 0;
select_timeout.tv_sec = RTR_SOLICITATION_INTERVAL;
state = STATE_PROBE;
send_rs_packet();
} else if (state == STATE_PROBE) {
dprnt("%s: state: PROBE", __FUNCTION__);
if (probe < MAX_RTR_SOLICITATIONS) {
send_rs_packet();
} else {
dprnt("Maximum %d rtr solicitations sent out",
MAX_RTR_SOLICITATIONS);
get_realtime(&now);
probe = 0;
idle_expire.tv_sec = now.tv_sec +
SECONDS_TILL_RS_SEND;
dprnt("Going IDLE");
select_timeout.tv_sec = SEL_TIMEOUT_IDLE;
state = STATE_IDLE;
#ifdef DBG_PRINT
sleep_msg("Thread listening (state=IDLE)",
SECONDS_TILL_RS_SEND);
#endif
}
} else {
/* STATE_IDLE */
get_realtime(&now);
if (now.tv_sec >= idle_expire.tv_sec) {
dprnt("<Leaving IDLE; Woke up to retry RS send>");
select_timeout.tv_sec = 1;
state = STATE_DELAY;
}
#ifdef DBG_PRINT
else if ((idle_expire.tv_sec - now.tv_sec) < (5 * 60)) {
sleep_msg("Coming out of IDLE in",
idle_expire.tv_sec - now.tv_sec);
}
#endif
}
}
 
static void
cyg_rs(cyg_addrword_t param)
{
struct addrinfo hints, *res;
struct icmp6_hdr *icp;
struct icmp6_filter filt;
struct timeval loop_delay;
int err, status;
u_int hlim = 255;
fd_set fdset;
 
_show_all_interfaces();
 
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
err = getaddrinfo(ALLROUTER, NULL, &hints, &res);
if (err) {
dprnt("%s - failed to get ALL ROUTER: %s",
__FUNCTION__, gai_strerror(err));
cyg_rs_exit();
}
memcpy(&to, res->ai_addr, res->ai_addrlen);
*(u_int16_t *)&to.sin6_addr.s6_addr[2] = htons(1);
 
if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
dprnt("%s - can't open socket: %s",
__FUNCTION__, strerror(errno));
cyg_rs_exit();
}
if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&hlim, sizeof(hlim)) < 0) {
dprnt("%s - can't set IPV6 MULTICAST HOPS: %s",
__FUNCTION__, strerror(errno));
cyg_rs_exit();
}
 
/* Specify to accept only router advertisements on the socket */
ICMP6_FILTER_SETBLOCKALL(&filt);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
&filt, sizeof(filt)) < 0) {
dprnt("%s - can't set ICMP6 filter: %s",
__FUNCTION__, strerror(errno));
cyg_rs_exit();
}
 
idle_expire.tv_usec = 0;
select_timeout.tv_usec = 0;
last_ra_time.tv_usec = 0;
last_ra_time.tv_sec = 10;
select(0, 0, 0, 0, &last_ra_time);
 
racount = 0;
istat = &(cyg_icmp6stat);
badra = istat->icp6s_badra;
 
icp = (struct icmp6_hdr *)outpack;
icp->icmp6_type = ND_ROUTER_SOLICIT;
icp->icmp6_code = 0;
icp->icmp6_cksum = 0;
icp->icmp6_data32[0] = 0; /* RS reserved field */
state = STATE_DELAY;
 
while (true) {
FD_ZERO(&fdset);
FD_SET(s, &fdset);
 
check_timer();
 
status = select(s + 1, &fdset, NULL, NULL, &select_timeout);
if (status < 0) {
dprnt("%s - select: %s", strerror(errno));
continue;
}
if (status == 1)
receive_ra_packet();
 
loop_delay.tv_sec = 2;
loop_delay.tv_usec = 0;
select(0, 0, 0, 0, &loop_delay);
}
/* NOTREACHED */
}
 
void
ipv6_start_routing_thread(void)
{
cyg_thread_create(
CYGINT_NET_IPV6_ROUTING_THREAD_PRIORITY, // Priority
cyg_rs, // entry
0, // parameter
"IPv6 routing", // Name
&rs_stack[0], // Stack
STACK_SIZE, // Size
&rs_thread_handle, // Handle
&rs_thread_data // Thread data structure
);
cyg_thread_resume(rs_thread_handle); // Start it
diag_printf("IPv6 routing thread started\n");
}
 
/network_support.c
0,0 → 1,485
//==========================================================================
//
// network_support.c
//
// Misc network support functions
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Andrew Lunn <andrew.lunn@ascom.ch>
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas, sorin@netappi.com ("Sorin Babeanu"), hmt, jlarmour,
// andrew.lunn@ascom.ch
// Date: 2000-01-10
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
// BOOTP support
 
#include <pkgconf/net.h>
#undef _KERNEL
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
 
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <net/route.h>
 
#include <cyg/infra/diag.h>
#include <cyg/kernel/kapi.h>
 
#include <stdio.h> // for 'sprintf()'
 
#include <bootp.h>
#include <network.h>
#include <arpa/inet.h>
 
#ifdef CYGPKG_IO_PCMCIA
#include <cyg/io/eth/netdev.h>
#endif
 
#ifdef CYGPKG_NET_DHCP
#include <dhcp.h>
#endif
 
#ifdef CYGPKG_NS_DNS
#include <pkgconf/ns_dns.h>
#endif
 
#ifdef CYGHWR_NET_DRIVER_ETH0
struct bootp eth0_bootp_data;
cyg_bool_t eth0_up = false;
const char *eth0_name = "eth0";
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
struct bootp eth1_bootp_data;
cyg_bool_t eth1_up = false;
const char *eth1_name = "eth1";
#endif
 
#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");
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.<lo>.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");
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");
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");
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;
}
 
void
build_bootp_record(struct bootp *bp,
const char *if_name,
const char *addrs_ip,
const char *addrs_netmask,
const char *addrs_broadcast,
const char *addrs_gateway,
const char *addrs_server)
{
int i, s;
in_addr_t addr;
unsigned char *vp;
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
bp->bp_ciaddr.s_addr = inet_addr(addrs_ip);
bp->bp_yiaddr.s_addr = inet_addr(addrs_ip);
bp->bp_siaddr.s_addr = inet_addr(addrs_server);
bp->bp_giaddr.s_addr = inet_addr(addrs_gateway);
vp = &bp->bp_vend[0];
bcopy(&cookie, vp, sizeof(cookie));
vp += sizeof(cookie);
addr = inet_addr(addrs_netmask);
vp = add_tag(vp, TAG_SUBNET_MASK, &addr, sizeof(in_addr_t));
addr = inet_addr(addrs_broadcast);
vp = add_tag(vp, TAG_IP_BROADCAST, &addr, sizeof(in_addr_t));
addr = inet_addr(addrs_gateway);
vp = add_tag(vp, TAG_GATEWAY, &addr, sizeof(in_addr_t));
*vp = TAG_END;
}
 
 
//
// Initialize network interface[s] using BOOTP/DHCP
//
void
init_all_network_interfaces(void)
{
static volatile int in_init_all_network_interfaces = 0;
#ifdef CYGPKG_IO_PCMCIA
cyg_netdevtab_entry_t *t;
#endif // CYGPKG_IO_PCMCIA
 
cyg_scheduler_lock();
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();
 
#ifdef CYGHWR_NET_DRIVER_ETH0
if ( ! eth0_up ) { // Make this call idempotent
#ifdef CYGPKG_IO_PCMCIA
if ((t = eth_drv_netdev("eth0")) != (cyg_netdevtab_entry_t *)NULL) {
int tries = 0;
while (t->status != CYG_NETDEVTAB_STATUS_AVAIL) {
if (tries == 0) {
diag_printf("... Waiting for PCMCIA device 'eth0'\n");
}
if (++tries == 5) {
diag_printf("... Giving up on PCMCIA device 'eth0'\n");
goto bail_eth0;
}
cyg_thread_delay(100);
}
}
#endif // CYGPKG_IO_PCMCIA
#ifdef CYGHWR_NET_DRIVER_ETH0_BOOTP
// Perform a complete initialization, using BOOTP/DHCP
eth0_up = true;
#ifdef CYGHWR_NET_DRIVER_ETH0_DHCP
eth0_dhcpstate = 0; // Says that initialization is external to dhcp
if (do_dhcp(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease))
#else
#ifdef CYGPKG_NET_DHCP
eth0_dhcpstate = DHCPSTATE_BOOTP_FALLBACK;
// so the dhcp machine does no harm if called
#endif
if (do_bootp(eth0_name, &eth0_bootp_data))
#endif
{
#ifdef CYGHWR_NET_DRIVER_ETH0_BOOTP_SHOW
show_bootp(eth0_name, &eth0_bootp_data);
#endif
} else {
diag_printf("BOOTP/DHCP failed on eth0\n");
eth0_up = false;
}
#elif defined(CYGHWR_NET_DRIVER_ETH0_ADDRS_IP)
eth0_up = true;
build_bootp_record(&eth0_bootp_data,
eth0_name,
string(CYGHWR_NET_DRIVER_ETH0_ADDRS_IP),
string(CYGHWR_NET_DRIVER_ETH0_ADDRS_NETMASK),
string(CYGHWR_NET_DRIVER_ETH0_ADDRS_BROADCAST),
string(CYGHWR_NET_DRIVER_ETH0_ADDRS_GATEWAY),
string(CYGHWR_NET_DRIVER_ETH0_ADDRS_SERVER));
show_bootp(eth0_name, &eth0_bootp_data);
#endif
#ifdef CYGPKG_IO_PCMCIA
bail_eth0:
#endif
}
#endif // CYGHWR_NET_DRIVER_ETH0
#ifdef CYGHWR_NET_DRIVER_ETH1
if ( ! eth1_up ) { // Make this call idempotent
#ifdef CYGPKG_IO_PCMCIA
if ((t = eth_drv_netdev("eth1")) != (cyg_netdevtab_entry_t *)NULL) {
int tries = 0;
while (t->status != CYG_NETDEVTAB_STATUS_AVAIL) {
if (tries == 0) {
diag_printf("... Waiting for PCMCIA device 'eth1'\n");
}
if (++tries == 5) {
diag_printf("... Giving up on PCMCIA device 'eth1'\n");
goto bail_eth1;
}
cyg_thread_delay(100);
}
}
#endif // CYGPKG_IO_PCMCIA
#ifdef CYGHWR_NET_DRIVER_ETH1_BOOTP
// Perform a complete initialization, using BOOTP/DHCP
eth1_up = true;
#ifdef CYGHWR_NET_DRIVER_ETH1_DHCP
eth1_dhcpstate = 0; // Says that initialization is external to dhcp
if (do_dhcp(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease))
#else
#ifdef CYGPKG_NET_DHCP
eth1_dhcpstate = DHCPSTATE_BOOTP_FALLBACK;
// so the dhcp machine does no harm if called
#endif
if (do_bootp(eth1_name, &eth1_bootp_data))
#endif
{
#ifdef CYGHWR_NET_DRIVER_ETH1_BOOTP_SHOW
show_bootp(eth1_name, &eth1_bootp_data);
#endif
} else {
diag_printf("BOOTP/DHCP failed on eth1\n");
eth1_up = false;
}
#elif defined(CYGHWR_NET_DRIVER_ETH1_ADDRS_IP)
eth1_up = true;
build_bootp_record(&eth1_bootp_data,
eth1_name,
string(CYGHWR_NET_DRIVER_ETH1_ADDRS_IP),
string(CYGHWR_NET_DRIVER_ETH1_ADDRS_NETMASK),
string(CYGHWR_NET_DRIVER_ETH1_ADDRS_BROADCAST),
string(CYGHWR_NET_DRIVER_ETH1_ADDRS_GATEWAY),
string(CYGHWR_NET_DRIVER_ETH1_ADDRS_SERVER));
show_bootp(eth1_name, &eth1_bootp_data);
#endif
#ifdef CYGPKG_IO_PCMCIA
bail_eth1:
#endif
}
#endif // CYGHWR_NET_DRIVER_ETH1
#ifdef CYGHWR_NET_DRIVER_ETH0
#ifndef CYGHWR_NET_DRIVER_ETH0_MANUAL
if (eth0_up) {
if (!init_net(eth0_name, &eth0_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, &eth0_bootp_data,
string(CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX))) {
diag_printf("Static IPv6 network initialization failed for eth0\n");
eth0_up = false; // ???
}
#endif
}
#endif
#endif
#ifdef CYGHWR_NET_DRIVER_ETH1
#ifndef CYGHWR_NET_DRIVER_ETH1_MANUAL
if (eth1_up) {
if (!init_net(eth1_name, &eth1_bootp_data)) {
diag_printf("Network initialization failed for eth1\n");
eth1_up = false;
}
#ifdef CYGHWR_NET_DRIVER_ETH1_IPV6_PREFIX
if (!init_net_IPv6(eth1_name, &eth1_bootp_data,
string(CYGHWR_NET_DRIVER_ETH1_IPV6_PREFIX))) {
diag_printf("Static IPv6 network initialization failed for eth1\n");
eth1_up = false; // ???
}
#endif
}
#endif
#endif
 
#ifdef CYGPKG_NET_NLOOP
#if 0 < CYGPKG_NET_NLOOP
{
static int loop_init = 0;
int i;
if ( 0 == loop_init++ )
for ( i = 0; i < CYGPKG_NET_NLOOP; i++ )
init_loopback_interface( i );
}
#endif
#endif
 
#ifdef CYGOPT_NET_DHCP_DHCP_THREAD
dhcp_start_dhcp_mgt_thread();
#endif
 
#ifdef CYGOPT_NET_IPV6_ROUTING_THREAD
ipv6_start_routing_thread();
#endif
 
#ifdef CYGDAT_NS_DNS_DEFAULT_SERVER
#define _SERVER string(CYGDAT_NS_DNS_DEFAULT_SERVER)
 
{
struct in_addr server;
inet_aton(_SERVER, &server);
cyg_dns_res_init(&server);
}
#endif
 
#ifdef CYGDAT_NS_DNS_DOMAINNAME_NAME
#define _NAME string(CYGDAT_NS_DNS_DOMAINNAME_NAME)
{
const char buf[] = _NAME;
int len = strlen(_NAME);
setdomainname(buf,len);
}
#endif
// Open the monitor to other threads.
in_init_all_network_interfaces = 0;
 
}
 
// EOF network_support.c
/getaddrinfo.c
0,0 → 1,357
//==========================================================================
//
// lib/getaddrinfo.c
//
// getaddrinfo(), freeaddrinfo(), gai_strerror(), getnameinfo()
//
//==========================================================================
//####ECOSPDCOPYRIGHTBEGIN####
//
// Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
// All Rights Reserved.
//
// Permission is granted to use, copy, modify and redistribute this
// file.
//
//####ECOSPDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2002-03-05
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <sys/param.h>
#include <sys/socket.h> // PF_xxx
#include <netinet/in.h> // IPPROTO_xx
#include <net/netdb.h>
#include <errno.h>
#include <cyg/infra/cyg_ass.h>
 
extern int sprintf(char *, const char *, ...);
extern long strtol(const char *, char **, int);
extern void *malloc(size_t);
extern void *calloc(int, size_t);
extern void free(void *);
 
// This routine is the real meat of the host->address translation
static int
_getaddr(struct addrinfo *ai, const char *node,
const struct addrinfo *hints, int family, int port)
{
switch (family) {
case AF_INET:
{
struct sockaddr_in *sa;
sa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
ai->ai_addr = (struct sockaddr *)sa;
ai->ai_addrlen = sizeof(*sa);
if (ai->ai_addr == (struct sockaddr *)NULL) {
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_MEMORY;
}
sa->sin_family = AF_INET;
sa->sin_len = sizeof(*sa);
sa->sin_port = htons(port);
if (node == (char *)NULL) {
if (hints->ai_flags & AI_PASSIVE) {
sa->sin_addr.s_addr = htonl(INADDR_ANY);
} else {
sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
} else {
// For now, only numeric "presentation" addresses supported
if (!inet_pton(AF_INET, (char *)node, (char *)&sa->sin_addr.s_addr)) {
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_FAIL; // Couldn't resolve name
}
}
}
break;
#ifdef CYGPKG_NET_INET6
case AF_INET6:
{
struct sockaddr_in6 *sa;
sa = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
ai->ai_addr = (struct sockaddr *)sa;
ai->ai_addrlen = sizeof(*sa);
if (ai->ai_addr == (struct sockaddr *)NULL) {
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_MEMORY;
}
sa->sin6_family = AF_INET6;
sa->sin6_len = sizeof(*sa);
sa->sin6_port = htons(port);
if (node == (char *)NULL) {
if (hints->ai_flags & AI_PASSIVE) {
sa->sin6_addr = in6addr_any;
} else {
sa->sin6_addr = in6addr_loopback;
}
} else {
// For now, only numeric "presentation" addresses supported
if (!inet_pton(AF_INET6, (char *)node, (char *)&sa->sin6_addr)) {
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_FAIL; // Couldn't resolve name
}
}
}
break;
#endif
}
return EAI_NONE;
}
 
int
getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct addrinfo dflt_hints;
struct protoent *proto = (struct protoent *)NULL;
struct addrinfo *ai;
char *protoname;
int port = 0;
int family;
int err;
 
if (hints == (struct addrinfo *)NULL) {
dflt_hints.ai_flags = 0; // No special flags
dflt_hints.ai_family = PF_UNSPEC;
dflt_hints.ai_socktype = 0;
dflt_hints.ai_protocol = 0;
hints = &dflt_hints;
}
// Prevalidate parameters
if ((nodename == (char *)NULL) && (servname == (char *)NULL)) {
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_NONAME;
}
switch (hints->ai_family) {
case PF_UNSPEC:
case PF_INET:
family = AF_INET;
break;
#ifdef CYGPKG_NET_INET6
case PF_INET6:
family = AF_INET6;
break;
#endif
default:
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_FAMILY;
}
// Allocate the first/primary result
*res = ai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
if (ai == (struct addrinfo *)NULL) {
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_MEMORY;
}
// Handle request
if (hints->ai_protocol != 0) {
proto = getprotobynumber(hints->ai_protocol);
}
ai->ai_family = family;
if (servname != (char *)NULL) {
switch (hints->ai_socktype) {
case 0:
case SOCK_STREAM:
protoname = "tcp";
ai->ai_socktype = SOCK_STREAM;
break;
case SOCK_DGRAM:
protoname = "udp";
ai->ai_socktype = SOCK_DGRAM;
break;
default:
freeaddrinfo(ai);
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_SOCKTYPE;
}
// See if this is just a port #
if ((port = strtol(servname, 0, 0)) > 0) {
ai->ai_socktype = hints->ai_socktype;
if (hints->ai_socktype == 0) {
// Need to have complete binding type/port
freeaddrinfo(ai);
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_SERVICE;
}
} else {
struct servent *serv = (struct servent *)NULL;
 
serv = getservbyname(servname, protoname);
if (serv == (struct servent *)NULL) {
if (hints->ai_socktype == 0) {
protoname = "udp";
serv = getservbyname(servname, protoname);
}
}
if (serv == (struct servent *)NULL) {
freeaddrinfo(ai);
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_SERVICE;
}
port = ntohs(serv->s_port);
}
proto = getprotobyname(protoname);
if (hints->ai_protocol && (hints->ai_protocol != proto->p_proto)) {
freeaddrinfo(ai);
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_SOCKTYPE;
}
ai->ai_protocol = proto->p_proto;
}
// Iterate through address types and create addresses
// Note: this does not handle the case where a given service can be
// handled via multiple protocols, e.g. http/tcp & http/udp
err = _getaddr(ai, nodename, hints, family, port);
if (err != EAI_NONE) {
freeaddrinfo(ai);
return err;
}
#ifdef CYGPKG_NET_INET6
if (hints->ai_family == PF_UNSPEC) {
// Add IPv6 address as well
struct addrinfo *nai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
if (nai == (struct addrinfo *)NULL) {
freeaddrinfo(ai);
diag_printf("Error at %s.%d\n", __FUNCTION__, __LINE__);
return EAI_MEMORY;
}
ai->ai_next = nai;
nai->ai_family = PF_INET6;
nai->ai_socktype = ai->ai_socktype;
nai->ai_protocol = ai->ai_protocol;
err = _getaddr(nai, nodename, hints, AF_INET6, port);
if (err != EAI_NONE) {
freeaddrinfo(*res);
return err;
}
}
#endif
// Note: null nodename is the same as 'localhost'
if (nodename == (char *)NULL) {
nodename = (const char *)"localhost";
}
if (hints->ai_flags & AI_CANONNAME) {
// Hack - until host name handling is more complete
ai = *res; // Canonical name is only in primary record
ai->ai_canonname = malloc(strlen(nodename)+1);
if (ai->ai_canonname) {
strcpy(ai->ai_canonname, nodename);
}
}
if (hints->ai_flags & AI_PASSIVE) {
// Incomplete addressing - used for bind/listen
} else {
// Complete addressing - used for connect/send/...
}
return EAI_NONE; // No errors
}
 
void
freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next = ai;
 
while ((ai = next) != (struct addrinfo *)NULL) {
if (ai->ai_canonname) free(ai->ai_canonname);
if (ai->ai_addr) free(ai->ai_addr);
next = ai->ai_next;
free(ai);
}
}
 
char
*gai_strerror(int err)
{
switch (err) {
case EAI_NONE:
return "EAI - no error";
case EAI_AGAIN:
return "EAI - temporary failure in name resolution";
case EAI_BADFLAGS:
return "EAI - invalid flags";
case EAI_FAIL:
return "EAI - non-recoverable failure in name resolution";
case EAI_FAMILY:
return "EAI - family not supported";
case EAI_MEMORY:
return "EAI - memory allocation failure";
case EAI_NONAME:
return "EAI - hostname nor servname provided, or not known";
case EAI_SERVICE:
return "EAI - servname not supported for socket type";
case EAI_SOCKTYPE:
return "EAI - socket type not supported";
case EAI_SYSTEM:
return "EAI - system error";
case EAI_BADHINTS:
return "EAI - inconsistent hints";
case EAI_PROTOCOL:
return "EAI - bad protocol";
default:
return "EAI - unknown error";
}
}
 
// Set of flags implemented
#define NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM)
 
int
getnameinfo (const struct sockaddr *sa, socklen_t salen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen,
unsigned int flags)
{
int port;
char *s;
struct servent *se;
 
if ((flags & ~NI_MASK) != 0) {
return EAI_BADFLAGS;
}
switch (sa->sa_family) {
case PF_INET:
#ifdef CYGPKG_NET_INET6
case PF_INET6:
#endif
if (host != (char *)NULL) {
s = _inet_ntop((struct sockaddr *)sa, host, hostlen);
if (!s) {
return EAI_FAIL;
}
}
if (serv != (char *)NULL) {
port = _inet_port((struct sockaddr *)sa);
if (!port) {
return EAI_FAIL;
}
se = (struct servent *)NULL;
if ((flags & NI_NUMERICSERV) == 0) {
if ((flags & NI_DGRAM) == 0) {
se = getservbyport(port, "tcp");
}
if (se == (struct servent *)NULL) {
se = getservbyport(port, "ucp");
}
}
if (se != (struct servent *)NULL) {
sprintf(serv, "%s/%s", se->s_name, se->s_proto);
} else {
sprintf(serv, "%d", port);
}
}
break;
default:
return EAI_FAMILY;
}
return EAI_NONE;
}
/tftp_dummy_file.c
0,0 → 1,220
//==========================================================================
//
// lib/tftp_dummy_file.c
//
// Dummy [in memory] file I/O functions
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-04-06
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
// TFTP file support - minimal "dummy" version
 
#include <network.h>
#include <tftp_support.h>
 
static int dummy_open(const char *, int);
static int dummy_close(int);
static int dummy_write(int, const void *, int);
static int dummy_read(int, void *, int);
 
struct tftpd_fileops dummy_fileops = {
dummy_open, dummy_close, dummy_write, dummy_read
};
 
struct _file_info;
struct _file {
unsigned char *pos, *eof;
int flags;
int mode;
struct _file_info *file;
};
#define FILE_OPEN 0x0001
 
#define NUM_FILES 8
static struct _file files[NUM_FILES];
 
struct _file_info {
char *name;
unsigned char *data;
int length, size;
};
 
// TEMP
static char _uu_data[] = "This is a test\n\
Four score and seven years ago,\n\
our forefathers brought forth a new nation,\n\
conceived in liberty and dedicated to the\n\
proposition that all men are created equal.\n\
Now we are engaged in a great civil war, testing\n\
whether that nation, or any nation so conceived\n\
and so dedicated, can long endure.\n\
1111111111111111111111111111111111\n\
2222222222222222222222222222222222\n\
3333333333333333333333333333333333\n\
4444444444444444444444444444444444\n\
5555555555555555555555555555555555\n\
6666666666666666666666666666666666\n\
";
 
static char _f0_data[1024*1024];
static char _f1_data[1024*1024];
static char _f2_data[1024*1024];
 
static char _name0[256] = "", _name1[256] = "", _name2[256] = "";
 
static struct _file_info file_list[] = {
{ "uu", _uu_data, sizeof(_uu_data)-1, sizeof(_uu_data)-1},
{ _name0, _f0_data, 0, sizeof(_f0_data)}, // Empty file
{ _name1, _f1_data, 0, sizeof(_f1_data)}, // Empty file
{ _name2, _f2_data, 0, sizeof(_f2_data)}, // Empty file
{ 0, 0, 0} // End of list
};
 
static inline struct _file *
dummy_fp(int fd)
{
struct _file *fp;
if ((fd < 0) || (fd >= NUM_FILES)) return (struct _file *)0;
fp = &files[fd];
if (!(fp->flags & FILE_OPEN)) return (struct _file *)0;
return fp;
}
 
static int
dummy_open(const char *fn, int flags)
{
int res = -1;
int fd;
struct _file *fp;
struct _file_info *fi;
 
fp = files;
for (fd = 0; fd < NUM_FILES; fd++, fp++) {
if (!(fp->flags & FILE_OPEN)) break;
}
if (fd == NUM_FILES) {
return -1; // No free files
}
if (flags & O_RDONLY) {
// Search for an extant file
fi = file_list;
while (fi->name) {
if (strcmp(fi->name, fn) == 0) {
// Found it!
fp->pos = fi->data;
fp->eof = fi->data + fi->length;
fp->flags = FILE_OPEN;
fp->mode = flags;
return fd;
}
fi++;
}
} else {
// Search for a non-existant file
fi = file_list;
while (fi->name) {
if (fi->name[0] == '\0' || strcmp(fi->name, fn) == 0) {
if ( !fi->name[0] )
// Empty slot found
strcpy(fi->name, fn);
fp->pos = fi->data;
fp->eof = fi->data + fi->size;
fp->file = fi; // So we can update file info later
fp->mode = flags;
fp->flags = FILE_OPEN;
return fd;
}
fi++;
}
}
// No such file
return res;
}
 
static int
dummy_close(int fd)
{
struct _file *fp = dummy_fp(fd);
if (!fp) return -1;
if (fp->mode & O_WRONLY) {
// Clean up - update file info for later
fp->file->length = fp->pos - fp->file->data;
}
fp->flags = 0; // No longer open
return 0;
}
 
static int
dummy_write(int fd, const void *buf, int len)
{
struct _file *fp = dummy_fp(fd);
int res;
if (!fp) return -1;
res = fp->eof - fp->pos; // Space left in file
if (res <= 0) return 0; // End of file
if (res > len) res = len;
bcopy(buf, fp->pos, res);
fp->pos += res;
return res;
}
 
static int
dummy_read(int fd, void *buf, int len)
{
struct _file *fp = dummy_fp(fd);
int res;
if (!fp) return -1;
res = fp->eof - fp->pos; // Number of bytes left in "file"
if (res > len) res = len;
if (res <= 0) return 0; // End of file
bcopy(fp->pos, buf, res);
fp->pos += res;
return res;
}
 
 
// EOF tftp_dummy_file.c
/inet_addr.c
0,0 → 1,235
//==========================================================================
//
// src/inet_addr.c
//
// INET address parse functions
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-01-10
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
/* $OpenBSD: inet_addr.c,v 1.6 1999/05/03 22:31:14 yanick Exp $ */
 
/*
* ++Copyright++ 1983, 1990, 1993
* -
* Copyright (c) 1983, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
* -
* --Copyright--
*/
 
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
static char rcsid[] = "$From: inet_addr.c,v 8.5 1996/08/05 08:31:35 vixie Exp $";
#else
static char rcsid[] = "$OpenBSD: inet_addr.c,v 1.6 1999/05/03 22:31:14 yanick Exp $";
#endif
#endif /* LIBC_SCCS and not lint */
 
#ifdef __ECOS
#include <pkgconf/net.h>
#undef _KERNEL
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
 
#include <net/if.h>
#include <netinet/in.h>
#else
#include <sys/types.h>
#include <sys/param.h>
#include <netinet/in.h>
#endif
#include <arpa/inet.h>
#include <ctype.h>
 
#ifdef __ECOS
#define isascii(c) (((unsigned char)(c) >= 0x20) && ((unsigned char)(c) <= 0x7F))
#endif
 
/*
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
in_addr_t
inet_addr(const char *cp)
{
struct in_addr val;
 
if (inet_aton(cp, &val))
return (val.s_addr);
return (INADDR_NONE);
}
 
/*
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*/
int
inet_aton(const char *cp, struct in_addr *addr)
{
register in_addr_t val;
register int base, n;
register char c;
u_int parts[4];
register u_int *pp = parts;
 
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!isdigit(c))
return (0);
val = 0; base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X')
base = 16, c = *++cp;
else
base = 8;
}
for (;;) {
if (isascii(c) && isdigit(c)) {
val = (val * base) + (c - '0');
c = *++cp;
} else if (base == 16 && isascii(c) && isxdigit(c)) {
val = (val << 4) |
(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3)
return (0);
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isascii(c) || !isspace(c)))
return (0);
/*
* Concoct the address according to
* the number of parts specified.
*/
n = pp - parts + 1;
switch (n) {
 
case 0:
return (0); /* initial nondigit */
 
case 1: /* a -- 32 bits */
break;
 
case 2: /* a.b -- 8.24 bits */
if ((val > 0xffffff) || (parts[0] > 0xff))
return (0);
val |= parts[0] << 24;
break;
 
case 3: /* a.b.c -- 8.8.16 bits */
if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
return (0);
val |= (parts[0] << 24) | (parts[1] << 16);
break;
 
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
}
if (addr)
addr->s_addr = htonl(val);
return (1);
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.