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, ð0_bootp_data, ð0_dhcpstate, ð0_lease); |
#endif |
#ifdef CYGHWR_NET_DRIVER_ETH1 |
if (eth1_up |
&& DHCPSTATE_FAILED != eth1_dhcpstate ) |
eth1_up = do_dhcp(eth1_name, ð1_bootp_data, ð1_dhcpstate, ð1_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, ð0_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, ð1_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, ð0_bootp_data, ð0_dhcpstate, ð0_lease); |
} |
eth0_up = false; |
#endif |
#ifdef CYGHWR_NET_DRIVER_ETH1 |
if ( eth1_up |
&& eth1_dhcpstate != DHCPSTATE_FAILED ) { |
do_dhcp_down_net(eth1_name, ð1_bootp_data, ð1_dhcpstate, ð1_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, ð0_bootp_data, ð0_dhcpstate, ð0_lease); |
#endif |
#ifdef CYGHWR_NET_DRIVER_ETH1 |
if (eth1_up) |
do_dhcp_release(eth1_name, ð1_bootp_data, ð1_dhcpstate, ð1_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, ð0_bootp_data, ð0_dhcpstate, ð0_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, ð0_bootp_data)) |
#endif |
{ |
#ifdef CYGHWR_NET_DRIVER_ETH0_BOOTP_SHOW |
show_bootp(eth0_name, ð0_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(ð0_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, ð0_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, ð1_bootp_data, ð1_dhcpstate, ð1_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, ð1_bootp_data)) |
#endif |
{ |
#ifdef CYGHWR_NET_DRIVER_ETH1_BOOTP_SHOW |
show_bootp(eth1_name, ð1_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(ð1_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, ð1_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, ð0_bootp_data)) { |
diag_printf("Network initialization failed for eth0\n"); |
eth0_up = false; |
} |
#ifdef CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX |
if (!init_net_IPv6(eth0_name, ð0_bootp_data, |
string(CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX))) { |
diag_printf("Static IPv6 network initialization failed for eth0\n"); |
eth0_up = false; // ??? |
} |
#endif |
} |
#endif |
#endif |
#ifdef CYGHWR_NET_DRIVER_ETH1 |
#ifndef CYGHWR_NET_DRIVER_ETH1_MANUAL |
if (eth1_up) { |
if (!init_net(eth1_name, ð1_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, ð1_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); |
} |