/* $Header: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-option-convert.c,v 1.6 2003/06/27 03:16:27 actmodern Exp $
*
* Copyright 2002, 2003 Thamer Alharbash <tmh@whitefang.com>
*
* 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. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/* FIXME: still a tad messy and a bit over redundant. but it
* works for now until release time. document and prune anything
* that needs pruning. */
#define MODULE_NAME "dhcp-option-convert"
#include "dhcp-local.h"
#include "dhcp-libutil.h"
#include "dhcp-librawnet.h"
#include "dhcp-option.h"
#include "dhcp-option-convert.h"
#include "dhcp-limits.h"
/* * * * * * * * *
* utility routines. *
* * * * * * * * * * * */
/* count internal string atoms, and mark with sentinals. this
* wrecks the string so it should only be used on a copy.
* FIXME: this works but really should be a stringbuffer thing. */
static size_t count_internal_string_atoms_and_mark(char *input)
{
char *ptr;
size_t num = 0;
ptr = input;
while(*ptr) {
switch(*ptr) {
case ';':
num++;
*ptr = 0;
ptr++;
case '\\':
if((*ptr + 1) == ';') {
ptr += 2; /* skip. */
}
default: /* fall through. */
ptr++;
break;
}
}
if(num == 0 && *input != 0)
num++; /* we have at least one. */
return num;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* From internal to network format: *
* *
* *
* uint8, int8 are just copied verbatim since they're octets *
* which need no marshalling. *
* *
* uint16, int16 are htons as they are copied over. *
* *
* uint32, int32 are htonl as they are copied over. *
* *
* signed are wrapped around unsigned conversions since *
* marshalling should not interfere with signedness. *
* *
* copying from a list is a bit more ugly. here we redo *
* everything only we're copying from a list to contigenous *
* memory. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* make a copy of an unsigned byte. */
static uint8_t *uint8_copy_to_network(const void *data, size_t num)
{
uint8_t *uint8_copy;
uint8_copy = xmalloc((sizeof(uint8_t) * num));
memcpy(uint8_copy, data, (sizeof(uint8_t) * num));
return uint8_copy;
}
/* make a copy of an signed byte. */
static int8_t *int8_copy_to_network(const void *data, size_t num)
{
return (int8_t *)uint8_copy_to_network(data, num); /* just cast. since it doesn't matter. */
}
/* make a copy of an unsigned 16-bit integer to network. */
static uint16_t *uint16_copy_to_network(const void *data, size_t num)
{
const uint16_t *uint16_data;
uint16_t *uint16_copy;
size_t i;
uint16_data = data;
uint16_copy = xmalloc((sizeof(uint16_t) * num));
for(i = 0;i < num;i ++) {
uint16_copy[i] = htons(uint16_data[i]);
}
return uint16_copy;
}
/* make a copy of an signed 16-bit integer. */
static int16_t *int16_copy_to_network(const void *data, size_t num)
{
/* just cast. since it doesn't matter as long as we're just copying. */
return (int16_t *)uint16_copy_to_network(data, num);
}
/* make a copy of an unsigned 32-bit integer. */
static uint32_t *uint32_copy_to_network(const void *data, size_t num)
{
const uint32_t *uint32_data;
uint32_t *uint32_copy;
size_t i;
uint32_data = data;
uint32_copy = xmalloc((sizeof(uint32_t) * num));
for(i = 0;i < num;i ++) {
uint32_copy[i] = htonl(uint32_data[i]);
}
return uint32_copy;
}
/* make a copy of an signed 16-bit integer. */
static int32_t *int32_copy_to_network(const void *data, size_t num)
{
/* just cast. since it doesn't matter as long as we're just copying. */
return (int32_t *)uint32_copy_to_network(data, num);
}
static void *int_list_copy_to_network(list_t *list, size_t size, uint8_t sign)
{
void *datum;
void *ret_data;
size_t num;
/* get rid of compiler warnings. these will be initialized but the compiler may not see it .*/
uint8_t *uint8_data = NULL;
uint16_t *uint16_data = NULL;
uint32_t *uint32_data = NULL;
int8_t *int8_data = NULL;
int16_t *int16_data = NULL;
int32_t *int32_data = NULL;
uint8_t *uint8_ptr = NULL;
uint16_t *uint16_ptr = NULL;
uint32_t *uint32_ptr = NULL;
int8_t *int8_ptr = NULL;
int16_t *int16_ptr = NULL;
int32_t *int32_ptr = NULL;
num = list_get_len(list);
/* create datum. it's size * num, but we need to assign it to the right pointer. */
if(sign) {
switch(size) {
case sizeof(int8_t):
int8_data = xmalloc(sizeof(int8_data) * num);
int8_ptr = int8_data;
ret_data = int8_data;
break;
case sizeof(int16_t):
int16_data = xmalloc(sizeof(int16_data) * num);
int16_ptr = int16_data;
ret_data = int16_data;
break;
case sizeof(int32_t):
int32_data = xmalloc(sizeof(int32_data) * num);
int32_ptr = int32_data;
ret_data = int32_data;
break;
default:
FATAL_MESSAGE("illegal size passed for conversion. this is a bug report me.");
exit(1);
}
} else {
switch(size) {
case sizeof(uint8_t):
uint8_data = xmalloc(sizeof(uint8_t) * num);
uint8_ptr = uint8_data;
ret_data = uint8_data;
break;
case sizeof(uint16_t):
uint16_data = xmalloc(sizeof(uint16_t) * num);
uint16_ptr = uint16_data;
ret_data = uint16_data;
break;
case sizeof(uint32_t):
uint32_data = xmalloc(sizeof(uint32_t) * num);
uint32_ptr = uint32_data;
ret_data = uint32_data;
break;
default:
FATAL_MESSAGE("illegal size passed for conversion. this is a bug report me.");
exit(1);
}
}
while((datum = list_next(list)) != NULL) {
if(sign) {
switch(size) {
case sizeof(int8_t):
*int8_ptr = *(int8_t *)datum;
int8_ptr++;
break;
case sizeof(int16_t):
*int16_ptr = htons(*(int16_t *)datum);
int16_ptr++;
break;
case sizeof(int32_t):
memcpy(int32_ptr, datum, sizeof(int32_t));
*int32_ptr = htons(*(int32_t *)datum);
int32_ptr++;
break;
default:
FA