* Copyright 2003-2004, Waldemar Kornewald <wkornew@gmx.net>
* Distributed under the terms of the MIT License.
*/
#include <ByteOrder.h>
#include <NetBufferUtilities.h>
#include <net_buffer.h>
#include "DiscoveryPacket.h"
DiscoveryPacket::DiscoveryPacket(uint8 code, uint16 sessionID)
: fCode(code),
fSessionID(sessionID),
fInitStatus(B_OK)
{
}
DiscoveryPacket::DiscoveryPacket(net_buffer *packet, uint32 start)
{
NetBufferHeaderReader<pppoe_header> bufferheader(packet);
if (bufferheader.Status() != B_OK) {
dprintf("NetBufferHeaderReader create fail\n");
fInitStatus = B_ERROR;
return;
}
pppoe_header &header = bufferheader.Data();
SetCode(header.code);
uint16 length = ntohs(header.length);
if(length > packet->size - PPPoE_HEADER_SIZE) {
dprintf("packet size less than pppoe payload\n");
dprintf("pppoe payload: %d\n", length);
dprintf("PPPoE_HEADER_SIZE: %d\n", PPPoE_HEADER_SIZE);
dprintf("packet->size: %" B_PRIu32 "\n", packet->size);
fInitStatus = B_ERROR;
return;
}
int32 position = 0;
pppoe_tag *tag;
while(position <= length - 4) {
tag = (pppoe_tag*) (header.data + position);
position += ntohs(tag->length) + 4;
AddTag(ntohs(tag->type), tag->data, ntohs(tag->length));
}
fInitStatus = B_OK;
}
DiscoveryPacket::~DiscoveryPacket()
{
for(int32 index = 0; index < CountTags(); index++)
free(TagAt(index));
}
bool
DiscoveryPacket::AddTag(uint16 type, const void *data, uint16 length, int32 index)
{
pppoe_tag *add = (pppoe_tag*) malloc(length + 4);
add->type = type;
add->length = length;
memcpy(add->data, data, length);
bool status;
if(index < 0)
status = fTags.AddItem(add);
else
status = fTags.AddItem(add, index);
if(!status) {
free(add);
return false;
}
return true;
}
bool
DiscoveryPacket::RemoveTag(pppoe_tag *tag)
{
if(!fTags.HasItem(tag))
return false;
fTags.RemoveItem(tag);
free(tag);
return true;
}
pppoe_tag*
DiscoveryPacket::TagAt(int32 index) const
{
pppoe_tag *tag = fTags.ItemAt(index);
if(tag == fTags.GetDefaultItem())
return NULL;
return tag;
}
pppoe_tag*
DiscoveryPacket::TagWithType(uint16 type) const
{
pppoe_tag *tag;
for(int32 index = 0; index < CountTags(); index++) {
tag = TagAt(index);
if(tag && tag->type == type)
return tag;
}
return NULL;
}
net_buffer*
DiscoveryPacket::ToNetBuffer(uint32 MTU)
{
net_buffer *packet = gBufferModule->create(256);
if (packet == NULL) {
dprintf("create buffer failure\n");
return NULL;
}
pppoe_header *header ;
status_t status = gBufferModule->append_size(packet, 1492, (void **)&header);
if (status != B_OK) {
dprintf("append size failure\n");
return NULL;
}
header->version = PPPoE_VERSION;
header->type = PPPoE_TYPE;
header->code = Code();
header->sessionID = SessionID();
uint16 length = 0;
pppoe_tag *tag;
for(int32 index = 0; index < CountTags(); index++) {
tag = TagAt(index);
if(MTU - length < tag->length) {
gBufferModule->free(packet);
return NULL;
}
*((uint16*)(header->data + length)) = htons(tag->type);
length += 2;
*((uint16*)(header->data + length)) = htons(tag->length);
length += 2;
memcpy(header->data + length, tag->data, tag->length);
length += tag->length;
}
header->length = htons(length);
status = gBufferModule->trim(packet, length + PPPoE_HEADER_SIZE);
if (status != B_OK) {
dprintf("trim buffer failure\n");
return NULL;
}
return packet;
}