made a copy

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19779 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2007-01-12 21:05:47 +00:00
parent fa4858af26
commit 93b2b9ce66
+347
View File
@@ -0,0 +1,347 @@
/*
* Copyright 2006, Marcus Overhagen <[email protected]. All rights reserved.
* Copyright 2005, Ingo Weinhold <[email protected]>.
* Distributed under the terms of the MIT License.
*/
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <OS.h>
#include <KernelExport.h>
#include <boot/net/Ethernet.h>
#include <boot/net/NetStack.h>
#include "pxe_undi.h"
//#define TRACE_NETWORK
#ifdef TRACE_NETWORK
# define TRACE(x...) dprintf(x)
#else
# define TRACE(x...)
#endif
#ifdef TRACE_NETWORK
static void
hex_dump(const void *_data, int length)
{
uint8 *data = (uint8*)_data;
for (int i = 0; i < length; i++) {
if (i % 4 == 0) {
if (i % 32 == 0) {
if (i != 0)
TRACE("\n");
TRACE("%03x: ", i);
} else
TRACE(" ");
}
TRACE("%02x", data[i]);
}
TRACE("\n");
}
#else // !TRACE_NETWORK
#define hex_dump(data, length)
#endif // !TRACE_NETWORK
class UNDI : public EthernetInterface
{
public:
UNDI();
virtual ~UNDI();
status_t Init();
virtual mac_addr_t MACAddress() const;
virtual void * AllocateSendReceiveBuffer(size_t size);
virtual void FreeSendReceiveBuffer(void *buffer);
virtual ssize_t Send(const void *buffer, size_t size);
virtual ssize_t Receive(void *buffer, size_t size);
private:
mac_addr_t fMACAddress;
bool fRxFinished;
PXE_STRUCT * fPxeData;
};
UNDI::UNDI()
: fMACAddress()
, fRxFinished(true)
, fPxeData(NULL)
{
TRACE("UNDI::UNDI\n");
fPxeData = pxe_undi_find_data();
if (!fPxeData)
panic("can't find !PXE structure");
dprintf("PXE API entrypoint at %04x:%04x\n", fPxeData->EntryPointSP.seg, fPxeData->EntryPointSP.ofs);
}
UNDI::~UNDI()
{
TRACE("UNDI::~UNDI\n");
}
status_t
UNDI::Init()
{
TRACE("UNDI::Init\n");
PXENV_GET_CACHED_INFO cached_info;
PXENV_UNDI_GET_INFORMATION get_info;
PXENV_UNDI_GET_STATE get_state;
PXENV_UNDI_OPEN undi_open;
uint16 res;
cached_info.PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
cached_info.BufferSize = 0;
cached_info.BufferLimit = 0;
cached_info.Buffer.seg = 0;
cached_info.Buffer.ofs = 0;
res = call_pxe_bios(fPxeData, GET_CACHED_INFO, &cached_info);
if (res != 0 || cached_info.Status != 0) {
char s[100];
snprintf(s, sizeof(s), "Can't determine IP address! PXENV_GET_CACHED_INFO res %x, status %x\n", res, cached_info.Status);
panic(s);
}
char *buf = (char *)(cached_info.Buffer.seg * 16 + cached_info.Buffer.ofs);
ip_addr_t ipClient = ntohl(*(ip_addr_t *)(buf + 16));
ip_addr_t ipServer = ntohl(*(ip_addr_t *)(buf + 20));
dprintf("client-ip: %08x, server-ip: %08x\n", (int)ipClient, (int)ipServer);
SetIPAddress(ipClient);
undi_open.OpenFlag = 0;
undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS;
undi_open.R_Mcast_Buf.MCastAddrCount = 0;
res = call_pxe_bios(fPxeData, UNDI_OPEN, &undi_open);
if (res != 0 || undi_open.Status != 0) {
dprintf("PXENV_UNDI_OPEN failed, res %x, status %x, ignoring\n", res, undi_open.Status);
}
res = call_pxe_bios(fPxeData, UNDI_GET_STATE, &get_state);
if (res != 0 || get_state.Status != 0) {
dprintf("PXENV_UNDI_GET_STATE failed, res %x, status %x, ignoring\n", res, get_state.Status);
} else {
switch (get_state.UNDIstate) {
case PXE_UNDI_GET_STATE_STARTED:
TRACE("PXE_UNDI_GET_STATE_STARTED\n");
break;
case PXE_UNDI_GET_STATE_INITIALIZED:
TRACE("PXE_UNDI_GET_STATE_INITIALIZED\n");
break;
case PXE_UNDI_GET_STATE_OPENED:
TRACE("PXE_UNDI_GET_STATE_OPENED\n");
break;
default:
TRACE("unknown undi state 0x%02x\n", get_state.UNDIstate);
break;
}
}
res = call_pxe_bios(fPxeData, UNDI_GET_INFORMATION, &get_info);
if (res != 0 || get_info.Status != 0) {
dprintf("PXENV_UNDI_GET_INFORMATION failed, res %x, status %x\n", res, get_info.Status);
return B_ERROR;
}
TRACE("Status = %x\n", get_info.Status);
TRACE("BaseIo = %x\n", get_info.BaseIo);
TRACE("IntNumber = %x\n", get_info.IntNumber);
TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit);
TRACE("HwType = %x\n", get_info.HwType);
TRACE("HwAddrLen = %x\n", get_info.HwAddrLen);
TRACE("RxBufCt = %x\n", get_info.RxBufCt);
TRACE("TxBufCt = %x\n", get_info.TxBufCt);
fMACAddress = get_info.CurrentNodeAddress;
TRACE("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", fMACAddress[0], fMACAddress[1], fMACAddress[2], fMACAddress[3], fMACAddress[4], fMACAddress[5]);
return B_OK;
}
mac_addr_t
UNDI::MACAddress() const
{
return fMACAddress;
}
void *
UNDI::AllocateSendReceiveBuffer(size_t size)
{
TRACE("UNDI::AllocateSendReceiveBuffer, size %ld\n", size);
if (size > 0x3000)
return NULL;
return (void *)0x500;
}
void
UNDI::FreeSendReceiveBuffer(void *buffer)
{
TRACE("UNDI::FreeSendReceiveBuffer\n");
}
ssize_t
UNDI::Send(const void *buffer, size_t size)
{
TRACE("UNDI::Send, buffer %p, size %ld\n", buffer, size);
// hex_dump(buffer, size);
PXENV_UNDI_TRANSMIT undi_tx;
PXENV_UNDI_TBD undi_tbd;
undi_tx.Protocol = P_UNKNOWN;
undi_tx.XmitFlag = XMT_DESTADDR;
undi_tx.DestAddr.seg = SEG((char *)buffer + 16);
undi_tx.DestAddr.ofs = OFS((char *)buffer + 16);
undi_tx.TBD.seg = SEG(&undi_tbd);
undi_tx.TBD.ofs = OFS(&undi_tbd);
undi_tbd.ImmedLength = size;
undi_tbd.Xmit.seg = SEG(buffer);
undi_tbd.Xmit.ofs = OFS(buffer);
undi_tbd.DataBlkCount = 0;
uint16 res = call_pxe_bios(fPxeData, UNDI_TRANSMIT, &undi_tx);
if (res != 0 || undi_tx.Status != 0) {
dprintf("UNDI_TRANSMIT failed, res %x, status %x\n", res, undi_tx.Status);
return 0;
}
TRACE("UNDI_TRANSMIT success\n");
return size;
}
ssize_t
UNDI::Receive(void *buffer, size_t size)
{
//TRACE("UNDI::Receive, buffer %p, size %ld\n", buffer, size);
PXENV_UNDI_ISR undi_isr;
uint16 res;
if (!fRxFinished) {
TRACE("continue receive...\n");
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
if (res != 0 || undi_isr.Status != 0) {
dprintf("PXENV_UNDI_ISR_IN_GET_NEXT failed, res %x, status %x\n", res, undi_isr.Status);
fRxFinished = true;
return 0;
}
} else {
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
if (res != 0 || undi_isr.Status != 0) {
dprintf("PXENV_UNDI_ISR_IN_START failed, res %x, status %x\n", res, undi_isr.Status);
return -1;
}
if (undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS) {
// TRACE("not ours\n");
return -1;
}
// send EOI to pic ?
// TRACE("PXENV_UNDI_ISR_OUT_OURS\n");
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
if (res != 0 || undi_isr.Status != 0) {
dprintf("PXENV_UNDI_ISR_IN_PROCESS failed, res %x, status %x\n", res, undi_isr.Status);
return -1;
}
}
switch (undi_isr.FuncFlag) {
case PXENV_UNDI_ISR_OUT_TRANSMIT:
TRACE("PXENV_UNDI_ISR_OUT_TRANSMIT\n");
fRxFinished = false;
return 0;
case PXENV_UNDI_ISR_OUT_RECEIVE:
TRACE("PXENV_UNDI_ISR_OUT_RECEIVE\n");
// TRACE("BufferLength %d\n", undi_isr.BufferLength);
// TRACE("FrameLength %d\n", undi_isr.FrameLength);
// TRACE("FrameHeaderLength %d\n", undi_isr.FrameHeaderLength);
if (undi_isr.FrameLength > undi_isr.BufferLength)
panic("UNDI::Receive: multi buffer frames not supported");
if (size > undi_isr.BufferLength)
size = undi_isr.BufferLength;
memcpy(buffer, (const void *)(undi_isr.Frame.seg * 16 + undi_isr.Frame.ofs), size);
// hex_dump(buffer, size);
fRxFinished = false;
return size;
case PXENV_UNDI_ISR_OUT_BUSY:
TRACE("PXENV_UNDI_ISR_OUT_BUSY\n");
fRxFinished = true;
return -1;
case PXENV_UNDI_ISR_OUT_DONE:
TRACE("PXENV_UNDI_ISR_OUT_DONE\n");
fRxFinished = true;
return -1;
default:
TRACE("default!!!\n");
return -1;
}
}
status_t
platform_net_stack_init()
{
TRACE("platform_net_stack_init\n");
UNDI *interface = new(nothrow) UNDI;
if (!interface)
return B_NO_MEMORY;
status_t error = interface->Init();
if (error != B_OK) {
TRACE("platform_net_stack_init: interface init failed\n");
delete interface;
return error;
}
error = NetStack::Default()->AddEthernetInterface(interface);
if (error != B_OK) {
delete interface;
return error;
}
return B_OK;
}