LWIP - dhcpd --lwip

A sort of quick hack for dhcpd to work as a client with lwip server.

- The functionality is not changed unless --lwip switch is supplied.
  dhcpd does not use broadcast udp sockets but some sort of raw
  sockets and changes their behavior during their life by ioctls.

- I thought there is no need to polute lwip just to make dhcp client
  work. Instead I decided to twist the client a little bit.

- It is so far the only big collision I found between inet and lwip.
This commit is contained in:
Tomas Hruby 2011-04-07 07:44:17 +00:00
parent dca25a1b39
commit 8171eb0b3d
3 changed files with 76 additions and 7 deletions

View file

@ -16,6 +16,8 @@
#include <sys/asynchio.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <net/gen/ether.h>
#include <net/gen/eth_hdr.h>
#include <net/gen/eth_io.h>
@ -166,7 +168,10 @@ int opendev(network_t *np, fdtype_t fdtype, int compete)
/* Open the proper device in the proper mode. */
fdp= fdold;
fdp->n= np->n;
sprintf(fdp->device, "/dev/%s%d", devbytype[fdtype], np->n);
if (lwip && (fdtype == FT_ETHERNET || fdtype == FT_ICMP))
sprintf(fdp->device, "/dev/ip");
else
sprintf(fdp->device, "/dev/%s%d", devbytype[fdtype], np->n);
np->fdp= fdp;
if ((fdp->fd= open(fdp->device, O_RDWR)) < 0) {
@ -176,6 +181,38 @@ int opendev(network_t *np, fdtype_t fdtype, int compete)
switch (fdtype) {
case FT_ETHERNET:
if (lwip) {
nwio_ipopt_t ipopt;
int result;
char ethdev[64];
int efd;
sprintf(ethdev, "/dev/eth%d", np->n);
if ((efd = open(fdp->device, O_RDWR)) < 0) {
if (errno == ENOENT || errno == ENODEV ||
errno == ENXIO)
return 0;
fatal(ethdev);
}
if (ioctl(efd, NWIOGETHSTAT, &ethstat) < 0) {
/* Not an Ethernet. */
close(efd);
return 0;
}
close(efd);
np->eth= ethstat.nwes_addr;
ipopt.nwio_flags= NWIO_COPY | NWIO_PROTOSPEC;
ipopt.nwio_proto= 17; /* UDP */
result= ioctl (fdp->fd, NWIOSIPOPT, &ipopt);
if (result<0)
perror("ioctl (NWIOSIPOPT)"), exit(1);
break;
}
/* Cannot use NWIOGETHSTAT in non-blocking mode due to a race between
* the reply from the ethernet driver and the cancel message from VFS
* for reaching inet. Hence, a signal is used to interrupt NWIOGETHSTAT
@ -218,6 +255,26 @@ int opendev(network_t *np, fdtype_t fdtype, int compete)
break;
case FT_BOOTPC:
if (lwip) {
struct sockaddr_in si_me;
close(fdp->fd);
fdp->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fdp->fd < 0)
return 0;
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
si_me.sin_port = htons(port_client);
if (bind(fdp->fd, (struct sockaddr *) &si_me,
sizeof(si_me)) == -1) {
close(fdp->fd);
printf("DHCP : cannot bind client socket to port %d\n",
port_client);
return 0;
}
break;
}
udpopt.nwuo_flags= NWUO_COPY | NWUO_EN_LOC | NWUO_EN_BROAD
| NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL
| NWUO_DI_IPOPT | NWUO_LP_SET;

View file

@ -45,6 +45,8 @@ static int aflag, rflag; /* True if adding or deleting pool addresses. */
#define N_NETS 32
static unsigned n_nets; /* Actual number of networks. */
int lwip;
void report(const char *label)
{
static FILE *logfp;
@ -685,6 +687,11 @@ main:
char *opt= argv[i++]+1;
if (opt[0] == '-' && opt[1] == 0) break; /* -- */
if (strcmp(opt, "-lwip") == 0) {
lwip = 1;
continue;
}
while (*opt != 0) switch (*opt++) {
case 'f':
@ -776,7 +783,9 @@ main:
np->n= i;
/* Ethernet? */
if (opendev(np, FT_ETHERNET, 1)) {
if (lwip) {
np->type = NT_ETHERNET;
} else if (opendev(np, FT_ETHERNET, 1)) {
np->type= B(&np->eth)[0] != 'Z' ? NT_ETHERNET : NT_SINK;
if (debug >= 1) {
printf("%s: Ethernet address is %s%s\n",
@ -956,8 +965,8 @@ main:
if (!(np->flags & NF_BOUND)) {
/* Rebind over Ethernet. */
udp2ether(bp, np);
if (sendpacket(np, bp->eth,
sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
if (sendpacket(np, (lwip ? bp->ip : bp->eth),
(lwip ? 0 : sizeof(eth_hdr_t)) + sizeof(ip_hdr_t)
+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
if (debug >= 1) {
printf("%s: Broadcast DHCP %s\n",
@ -1007,8 +1016,9 @@ main:
if (!(np->flags & NF_BOUND)) {
if (!opendev(np, FT_ETHERNET, 0)) continue;
get_buf(&np->fdp->bp);
r= asyn_read(&asyn, np->fdp->fd, np->fdp->bp->eth,
BUF_ETH_SIZE);
r= asyn_read(&asyn, np->fdp->fd,
lwip ? np->fdp->bp->ip : np->fdp->bp->eth,
lwip ? BUF_IP_SIZE : BUF_ETH_SIZE);
} else {
if (!opendev(np, FT_BOOTPC, 0)) continue;
get_buf(&np->fdp->bp);
@ -1026,7 +1036,7 @@ main:
if (i < n_nets) {
give_buf(&bp, &np->fdp->bp);
if (((!(np->flags & NF_BOUND)
&& r >= (sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
&& r >= (lwip ? 0 : (sizeof(eth_hdr_t)) + sizeof(ip_hdr_t)
+ sizeof(udp_hdr_t) + offsetof(dhcp_t, options))
&& ether2udp(bp)
&& bp->udpio->uih_dst_port == port_client)

View file

@ -19,6 +19,8 @@
#define EXTERN extern
#endif
extern int lwip;
EXTERN char *program; /* This program's name. */
extern char *configfile; /* Configuration file. */
extern char *poolfile; /* Dynamic address pool. */