www.pudn.com > dsr-uu-0.2.rar > dsr-pkt.c


/* Copyright (C) Uppsala University
 *
 * This file is distributed under the terms of the GNU general Public
 * License (GPL), see the file LICENSE
 *
 * Author: Erik Nordström, 
 */
#ifdef __KERNEL_
#include 
#include 
#endif

#ifdef NS2
#include "ns-agent.h"
#endif

#include "debug.h"
#include "dsr-opt.h"
#include "dsr.h"

char *dsr_pkt_alloc_opts(struct dsr_pkt *dp, int len)
{
	if (!dp)
		return NULL;

	dp->dh.raw = (char *)MALLOC(len + DEFAULT_TAILROOM, GFP_ATOMIC);

	if (!dp->dh.raw)
		return NULL;

	dp->dh.tail = dp->dh.raw + len;
	dp->dh.end = dp->dh.tail + DEFAULT_TAILROOM;

	return dp->dh.raw;
}

char *dsr_pkt_alloc_opts_expand(struct dsr_pkt *dp, int len)
{
	char *tmp;
	int old_len;

	if (!dp || !dp->dh.raw)
		return NULL;

	if (dsr_pkt_tailroom(dp) > len) {
		tmp = dp->dh.tail;
		dp->dh.tail += len;
		return tmp;
	}

	tmp = dp->dh.raw;
	old_len = dsr_pkt_opts_len(dp);

	if (!dsr_pkt_alloc_opts(dp, old_len + len))
		return NULL;

	memcpy(dp->dh.raw, tmp, old_len);

	FREE(tmp);

	return (dp->dh.raw + old_len);
}

int dsr_pkt_free_opts(struct dsr_pkt *dp)
{
	int len;

	if (!dp->dh.raw)
		return -1;

	len = dsr_pkt_opts_len(dp);

	FREE(dp->dh.raw);

	dp->dh.raw = dp->dh.end = dp->dh.tail = NULL;
	dp->srt_opt = NULL;
	dp->rreq_opt = NULL;
	memset(dp->rrep_opt, 0, sizeof(struct dsr_rrep_opt *) * MAX_RREP_OPTS);
	memset(dp->rerr_opt, 0, sizeof(struct dsr_rerr_opt *) * MAX_RERR_OPTS);
	memset(dp->ack_opt, 0, sizeof(struct dsr_ack_opt *) * MAX_ACK_OPTS);
	dp->num_rrep_opts = dp->num_rerr_opts = dp->num_ack_opts = 0;

	return len;
}

#ifdef NS2
struct dsr_pkt *dsr_pkt_alloc(Packet * p)
{
	struct dsr_pkt *dp;
	struct hdr_cmn *cmh;
	int dsr_opts_len = 0;

	dp = (struct dsr_pkt *)MALLOC(sizeof(struct dsr_pkt), GFP_ATOMIC);

	if (!dp)
		return NULL;

	memset(dp, 0, sizeof(struct dsr_pkt));

	if (p) {
		cmh = hdr_cmn::access(p);

		dp->p = p;
		dp->mac.raw = p->access(hdr_mac::offset_);
		dp->nh.iph = HDR_IP(p);

		dp->src.s_addr =
		    Address::instance().get_nodeaddr(dp->nh.iph->saddr());
		dp->dst.s_addr =
		    Address::instance().get_nodeaddr(dp->nh.iph->daddr());

		if (cmh->ptype() == PT_DSR) {
			struct dsr_opt_hdr *opth;
			
			opth = hdr_dsr::access(p);

			dsr_opts_len = ntohs(opth->p_len) + DSR_OPT_HDR_LEN;

			if (!dsr_pkt_alloc_opts(dp, dsr_opts_len)) {
				FREE(dp);
				return NULL;
			}

			memcpy(dp->dh.raw, (char *)opth, dsr_opts_len);

			dsr_opt_parse(dp);

			if ((DATA_PACKET(dp->dh.opth->nh) ||
			    dp->dh.opth->nh == PT_PING) && 
				ConfVal(UseNetworkLayerAck))
				dp->flags |= PKT_REQUEST_ACK;
		} else if ((DATA_PACKET(cmh->ptype()) || 
			    cmh->ptype() == PT_PING) && 
			   ConfVal(UseNetworkLayerAck))
			dp->flags |= PKT_REQUEST_ACK;

		/* A trick to calculate payload length... */
		dp->payload_len = cmh->size() - dsr_opts_len - IP_HDR_LEN;
	}
	return dp;
}

#else

struct dsr_pkt *dsr_pkt_alloc(struct sk_buff *skb)
{
	struct dsr_pkt *dp;
	int dsr_opts_len = 0;

	dp = (struct dsr_pkt *)MALLOC(sizeof(struct dsr_pkt), GFP_ATOMIC);

	if (!dp)
		return NULL;

	memset(dp, 0, sizeof(struct dsr_pkt));

	if (skb) {
	/* 	skb_unlink(skb); */

		dp->skb = skb;

		dp->mac.raw = skb->mac.raw;
		dp->nh.iph = skb->nh.iph;

		dp->src.s_addr = skb->nh.iph->saddr;
		dp->dst.s_addr = skb->nh.iph->daddr;

		if (dp->nh.iph->protocol == IPPROTO_DSR) {
			struct dsr_opt_hdr *opth;
			int n;

			opth = (struct dsr_opt_hdr *)(dp->nh.raw + (dp->nh.iph->ihl << 2));
			dsr_opts_len = ntohs(opth->p_len) + DSR_OPT_HDR_LEN;

			if (!dsr_pkt_alloc_opts(dp, dsr_opts_len)) {
				FREE(dp);
				return NULL;
			}

			memcpy(dp->dh.raw, (char *)opth, dsr_opts_len);
			
			n = dsr_opt_parse(dp);
			
			DEBUG("Packet has %d DSR option(s)\n", n);
		}

		dp->payload = dp->nh.raw +
		    (dp->nh.iph->ihl << 2) + dsr_opts_len;

		dp->payload_len = ntohs(dp->nh.iph->tot_len) -
		    (dp->nh.iph->ihl << 2) - dsr_opts_len;

		if (dp->payload_len)
			dp->flags |= PKT_REQUEST_ACK;
	}
	return dp;
}

#endif

void dsr_pkt_free(struct dsr_pkt *dp)
{

	if (!dp)
		return;
#ifndef NS2
	if (dp->skb)
		dev_kfree_skb_any(dp->skb);
#endif
	dsr_pkt_free_opts(dp);

	if (dp->srt)
		FREE(dp->srt);

	FREE(dp);

	return;
}