----- dhcp.c -------
Code: Alles auswählen
// DHCP Client for Small AVR Server
// (C) 2006 Andreas Böhme
//
#include "evalboard.h"
#include "dhcp.h"
#include "socket.h"
unsigned long transaction = 0xDE524160;
unsigned char new_ip[4] = {0, 0, 0, 0};
unsigned char dhcp_server[4];
void request_ip(void) {
cli(); dhcp_request(packet, 0, 1); sei();
}
void dhclient(char* buffer, int bufferlen) {
unsigned int udpdata;
unsigned int option_offset = 4;
unsigned char option_length;
unsigned char message_type = 0;
unsigned long lease_t = 0;
udpdata = ((buffer[IP_VERS_LEN] & 0x0F) << 2) + 14 + 8;
dhcp_t* dhcp_packet = (dhcp_t*) &buffer[udpdata];
// Hat die Antwort die richtige ID, sonst verwerfen!
if (dhcp_packet->bp_xid == transaction) {
// Options block parsen um die relevanten Datenteile zu ermitteln
while (dhcp_packet->options[option_offset] != 0xff) {
switch (dhcp_packet->options[option_offset]) {
// Option 51: Lease time
case 51: lease_t = dhcp_packet->options[option_offset + 2] * 0x1000000 + dhcp_packet->options[option_offset + 3] * 0x10000 + dhcp_packet->options[option_offset + 4] * 0x100 + dhcp_packet->options[option_offset + 5]; break;
// Option 53: DHCP Message Type
case 53: message_type = dhcp_packet->options[option_offset + 2]; break;
// Option 54: Adresse des Servers
case 54: for (unsigned char a = 0; a < 4; a++) dhcp_server[a] = dhcp_packet->options[option_offset + 2 + a];
default: ;
}
option_length = dhcp_packet->options[option_offset + 1];
printf ("Option %d: ",dhcp_packet->options[option_offset]);
for (unsigned char a = 2; a < option_length + 2; a++)
printf ("%x ", dhcp_packet->options[option_offset + a]);
printf("\n");
option_offset += (option_length + 2);
}
if (message_type == 2) {
printf ("Offered Address: %d.%d.%d.%d\n", dhcp_packet->bp_yiaddr[0], dhcp_packet->bp_yiaddr[1], dhcp_packet->bp_yiaddr[2], dhcp_packet->bp_yiaddr[3]);
for (unsigned char a = 0; a < 4; a++)
new_ip[a] = dhcp_packet->bp_yiaddr[a];
dhcp_request(buffer, bufferlen, 3);
}
else {
for (unsigned char a = 0; a < 4; a++)
new_ip[a] = 0;
}
if (message_type == 5) {
printf ("Assigned Address: %d.%d.%d.%d\n", dhcp_packet->bp_ciaddr[0], dhcp_packet->bp_ciaddr[1], dhcp_packet->bp_ciaddr[2], dhcp_packet->bp_ciaddr[3]);
for (unsigned char a = 0; a < 4; a++)
MYIP[a] = dhcp_packet->bp_ciaddr[a];
lease_time = lease_t;
}
}
}
void dhcp_request(char *buffer, int bufferlen, unsigned char mode) {
unsigned int udpdata;
struct Ethernet_Header *ethernet;
ethernet = (struct Ethernet_Header *)&buffer[ETHER_OFFSET];
struct IP_Header *ip;
ip = (struct IP_Header *)&buffer[IP_OFFSET];
struct TCP_Header *tcp;
tcp = (struct TCP_Header *)&buffer[TCP_OFFSET];
unsigned int result16;
ethernet->EnetPacketType = 0x0008;
// Broadcast an 255.255.255.255
ip->IP_Srcaddr = 0;
ip->IP_Destaddr = 0xffffffff;
for (unsigned char a = 0; a < 6; a++) {
ethernet->EnetPacketSrc[a] = 0xff;
}
ip->IP_Vers_Len = 0x45;
ip->IP_Tos = 0x00;
ip->IP_Id = 0x00c0;
ip->IP_Frag_Offset = 0x0040;
ip->IP_ttl = 64;
ip->IP_Proto = PROT_UDP;
buffer[TCP_ACKNUM+0] = 0;
buffer[TCP_ACKNUM+1] = 0;
buffer[TCP_ACKNUM+2] = 0;
buffer[TCP_ACKNUM+3] = 0;
buffer[TCP_SEQNUM+0] = 0;
buffer[TCP_SEQNUM+1] = 0;
buffer[TCP_SEQNUM+2] = 0;
buffer[TCP_SEQNUM+3] = 0;
buffer[TCP_HDRFLAGS+1] = FIN_FLAG;
tcp_store(buffer);
buffer[TCP_SRCPORT+0] = (SOCKET_DHCPD & 0xff);
buffer[TCP_SRCPORT+1] = (SOCKET_DHCPD >> 8);
buffer[TCP_DESTPORT+0] = (SOCKET_DHCP & 0xff);
buffer[TCP_DESTPORT+1] = (SOCKET_DHCP >> 8);
tcp_make(buffer);
// ????? Funktion in tcp.c eingefügt, wie sonst kann man einen leeren Buffer mit einer bestimmten Grösse erzeugen ?
make_zero_data (DHCP_PACKET_SIZE, buffer, &bufferlen);
udpdata = ((buffer[IP_VERS_LEN] & 0x0F) << 2) + 14 + 8;
//nun dem Buffer (UDP Daten) die Struktur aus DHCP_H aufzwängen ;)
dhcp_t* dhcp_packet = (dhcp_t*) &buffer[udpdata];
dhcp_packet->bp_opcode = 0x01; dhcp_packet->bp_htype = 0x01; dhcp_packet->bp_hlen = 0x06; dhcp_packet->bp_hops = 0x00;dhcp_packet->bp_secs = 0x00; dhcp_packet->bp_flags = 0x00;
for (unsigned char a = 0; a < 6; a++)
dhcp_packet->chaddr[a] = mymac[a];
dhcp_packet->bp_xid = transaction;
//magic cookie in options setzen
dhcp_packet->options[0] = 0x63; dhcp_packet->options[1] = 0x82; dhcp_packet->options[2] = 0x53; dhcp_packet->options[3] = 0x63;
//DHCP Message Type setzen
dhcp_packet->options[4] = 0x35; dhcp_packet->options[5] = 0x01; dhcp_packet->options[6] = mode;
// Wir machen ein DISCOVER ohne zusätzliche options
if (mode == 1) {
for (unsigned char a = 0; a < 4; a++)
dhcp_packet->bp_ciaddr[a] = MYIP[a];
dhcp_packet->options[7] = 0xff;
}
// Nun ein DHCP-Request, Options müssen mit dem Werten aus dem DHCPOFFER gefüllt werden
if (mode == 3) {
for (unsigned char a = 0; a < 4; a++)
dhcp_packet->bp_ciaddr[a] = new_ip[a];
dhcp_packet->options[7] = 0x32; dhcp_packet->options[8] = 0x04;
for (unsigned char a = 0; a < 4; a++)
dhcp_packet->options[9+a] = new_ip[a];
dhcp_packet->options[13] = 0x3d; dhcp_packet->options[14] = 0x07; dhcp_packet->options[15] = 0x01;
for (unsigned char a = 0; a < 6; a++)
dhcp_packet->options[16+a] = mymac[a];
dhcp_packet->options[22] = 0x36; dhcp_packet->options[23] = 0x04;
for (unsigned char a = 0; a < 4; a++)
dhcp_packet->options[24+a] = dhcp_server[a];
dhcp_packet->options[28] = 0xff;
}
ip->IP_Destaddr = 0xffffffff;
ip->IP_Hdr_Cksum = 0x0000;
result16 = (ip->IP_Vers_Len & 0x0F) << 2;
result16 = checksum (&ip->IP_Vers_Len, result16, 0);
ip->IP_Hdr_Cksum = ((result16 & 0xFF00) >> 8)|((result16 & 0x00FF)<<8);
Write_Ethernet_Frame (buffer, bufferlen);
}
------------------- dhcp.h ------------------
Code: Alles auswählen
#ifndef _DHCP_H
#define _DHCP_H
#define DHCP_CHADDR_LEN 16
#define DHCP_SNAME_LEN 64
#define DHCP_FILE_LEN 128
#define DHCP_OPTIONS_LEN 68
#define DHCP_MIN_OPTIONS_LEN 68
#define DHCP_PACKET_SIZE (28 + DHCP_CHADDR_LEN + DHCP_SNAME_LEN + DHCP_FILE_LEN + DHCP_OPTIONS_LEN)
typedef struct dhcp_t {
char bp_opcode;
char bp_htype;
char bp_hlen;
char bp_hops;
unsigned long bp_xid;
unsigned int bp_secs;
unsigned int bp_flags;
char bp_ciaddr[4];
char bp_yiaddr[4];
char bp_siaddr[4];
char bp_giaddr[4];
char chaddr[DHCP_CHADDR_LEN];
char sname[DHCP_SNAME_LEN];
char fname[DHCP_FILE_LEN];
char options[DHCP_OPTIONS_LEN];
} dhcp_t;
extern void dhcp_request(char *buffer, int bufferlen, unsigned char mode);
extern void dhclient(char* buffer, int bufferlen);
extern void request_ip(void);
#endif
Folgende Funktion einfügen, und natürlich in tcp.h bekannt machen
Code: Alles auswählen
//############################################################################
//Erzeugt einen leeren Buffer
//############################################################################
char make_zero_data (unsigned int count,char *buffer,int *bufferlen) {
//Variablen Für die Routine
unsigned int result16, userdatacount = 8;
unsigned char Data = 1;
unsigned char Buffer_Full = 0;
//Errechnet startpunkt der Daten im Tcp buffer
//IP Headerlänge + TCP Headerlänge + Ethernetframe
result16 = ((buffer[IP_VERS_LEN] & 0x0F) << 2) + 14 + 8;
for(unsigned int i = 0; i < count; i++) {
buffer[result16] = 0;
result16++;
userdatacount++;
//sind die daten länger als ein Ethernetbuffer dann abbruch
if (result16 > (MTU_SIZE - 1)) {
Buffer_Full = 1;
break;
}
}
buffer[UDP_LENGTH+1] = userdatacount & 0xff;
buffer[UDP_LENGTH] = userdatacount >> 8;
buffer[UDP_CHKSUM+1] = 0x00; // we don't use a chksum !
buffer[UDP_CHKSUM] = 0x00;
TCP_New_Packtlen(buffer, bufferlen, result16);
//*bufferlen = result16;
return (Buffer_Full);
}
Code: Alles auswählen
if ((Ethernet_IP_Datagramm) && (IP_UDP_Packet) && (tcp->TCP_DestPort == SOCKET_DHCP))
dhclient(packet,&packetlen);
Code: Alles auswählen
#define SOCKET_DHCPD 0x4300
#define SOCKET_DHCP 0x4400 //bootpd/dhcp
Wenn ich nichts vergessen habe, sollte es dann durch Aufruf der Request Funktion erfolgreich eine IP geben... Ich habe es "nur" mit meinem Linux Rechner bis jetzt probiert, daher wäre es gut wenn es noch Tests mit anderen Servern geben würde... Was passiert, wenn 2 Server im Netz hängen ???
Hier noch das LOG über die serielle Schnittstelle:
[/code]Option 53: 2
Option 54: c0 a8 1 1
Option 51: 0 0 2 58
Option 1: ff ff ff 0
Option 3: c0 a8 1 2
Option 6: c0 a8 1 1
Option 58: 0 0 1 2c
Option 59: 0 0 2 d
Option 15: 6c 6f 63 61 6c 2e 6e 65 74
Offered Address: 192.168.1.201
Option 53: 5
Option 54: c0 a8 1 1
Option 51: 0 0 2 58
Option 1: ff ff ff 0
Option 3: c0 a8 1 2
Option 6: c0 a8 1 1
Option 58: 0 0 1 2c
Option 59: 0 0 2 d
Option 15: 6c 6f 63 61 6c 2e 6e 65 74
Assigned Address: 192.168.1.201