/* * dsrarptable.{cc,hh} * Shweta Bhandare, Sagar Sanghani, Sheetalkumar Doshi, Timothy X Brown * Daniel Aguayo * * Copyright (c) 2003 Massachusetts Institute of Technology * Copyright (c) 2003 University of Colorado at Boulder * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dsrarptable.hh" #include "dsr.hh" CLICK_DECLS #define DEBUG_CHATTER if (_debug) click_chatter DSRArpTable::DSRArpTable() : _debug(false) { } DSRArpTable::~DSRArpTable() { } int DSRArpTable::configure(Vector &conf, ErrorHandler *errh) { unsigned int etht = 0x0800; if (cp_va_parse(conf, this, errh, cpIPAddress, "ip address", &_me, cpEthernetAddress,"ethernet address", &_me_ether, cpKeywords, "ETHERTYPE", cpUnsigned, "Ethernet encapsulation type", ðt, "DEBUG", cpBool, "Debug", &_debug, cpEnd) < 0) return -1; _etht = etht; return 0; } int DSRArpTable::initialize(ErrorHandler *) { return 0; } Packet * DSRArpTable::pull(int port) { assert(port == 0 || port == 1); // packets to which we want to add an ethernet header Packet *p_in = input(port).pull(); if (!p_in) return NULL; WritablePacket *q = p_in->push(sizeof(click_ether)); if (!q) { click_chatter("DSRArpTable::pull(%d): could not push space for ethernet header\n", port); return NULL; } click_ether *ether = (click_ether *)(q->data()); IPAddress dst_addr(q->dst_ip_anno()); EtherAddress dst_ether = lookup_ip(dst_addr); if (! dst_ether) { click_chatter ("DSRArpTable::push: missing ARP table entry! src: %s/%s dst: %s/%s\n", _me.s().c_str(), _me_ether.s().c_str(), dst_addr.s().c_str(), dst_ether.s().c_str()); q->kill(); return NULL; } memcpy(ðer->ether_shost, &_me_ether, 6); memcpy(ðer->ether_dhost, dst_ether.data(), 6); ether->ether_type = htons(_etht); return q; } void DSRArpTable::push(int port, Packet *p_in) { // packets from which we want to extract MAC addresses assert(port == 2); const click_ip *iph = (const click_ip*)(p_in->data() + sizeof(click_ether)); if (iph->ip_p != IP_PROTO_DSR) { DEBUG_CHATTER ("DSRArpTable::push: non-DSR packet passing through DSRArpTable\n"); output(2).push(p_in); return; } const click_ether *eth = (const click_ether *)p_in->data(); EtherAddress mac = EtherAddress(eth->ether_shost); IPAddress ip = last_hop_ip(p_in); EtherAddress e = lookup_ip(ip); if (!e) { DEBUG_CHATTER("DSRArpTable::push: adding ARP table entry for IP: %s; MAC: %s", ip.s().c_str(), mac.s().c_str()); add_entry(ip, mac); } else if (e != mac) { click_chatter("DSRArpTable::push: existing entry for %s has different MAC! %s, not %s", ip.s().c_str(), e.s().c_str(), mac.s().c_str()); delete_entry(ip); add_entry(ip, mac); } WritablePacket *p = p_in->uniqueify(); SET_DSR_LAST_HOP_IP_ANNO(p, ip.addr()); const uint16_t *d = e.sdata(); SET_DSR_LAST_HOP_ETH_ANNO1(p, d[0]); SET_DSR_LAST_HOP_ETH_ANNO2(p, d[1]); SET_DSR_LAST_HOP_ETH_ANNO3(p, d[2]); output(2).push(p); } // returns the ip of the last forwarder of this packet. if this is a // route request, this comes from the accumulated route. otherwise it // comes from the IP header (src and dst) and source route. if there // is no source route option, a one-hop source route is implied. IPAddress DSRArpTable::last_hop_ip(Packet *p) { const click_ip *ip = (const click_ip *)(p->data() + sizeof(click_ether)); click_dsr *dsr = (click_dsr *)((char *)ip + sizeof(click_ip)); const unsigned int dsr_len = ntohs(dsr->dsr_len); click_dsr_option *dsr_option = (click_dsr_option *)((char *)dsr + sizeof(click_dsr)); // click_chatter("last_hop_ip: dsr len is %d; first type is %x\n", // dsr_len, dsr_option->dsr_type); if (dsr_option->dsr_type == DSR_TYPE_RREQ) { const click_dsr_rreq *dsr_rreq = (click_dsr_rreq *)dsr_option; const unsigned int num_addr = dsr_rreq->num_addrs(); if (num_addr == 0) { // this route request is on its first hop IPAddress src_addr(ip->ip_src.s_addr); return (src_addr); } else { IPAddress last_hop = dsr_rreq->addr[num_addr-1].ip(); DEBUG_CHATTER ("saw a route request being forwarded by %s\n", last_hop.s().c_str()); return (last_hop); } } else if (dsr_option->dsr_type == DSR_TYPE_RREP) { // if this is a route reply, then we expect a source route option // immediately following -- move the dsr_option pointer down to // the next header and handle as a normal source-routed packet. // if there is no source route option following, then this must be // a one-hop reply. const click_dsr_rrep *dsr_rrep = (click_dsr_rrep *)dsr_option; // DEBUG_CHATTER(" * extracting IP from route reply; num_addr is %d\n", num_addr); if (dsr_rrep->length() == dsr_len) { // if this RREP option is the only option in the header IPAddress src_addr(ip->ip_src.s_addr); return (src_addr); } else { dsr_option = (click_dsr_option *)(dsr_rrep->next_option()); if (dsr_option->dsr_type != DSR_TYPE_SOURCE_ROUTE) { DEBUG_CHATTER(" * DSRArpTable::last_hop: source route option did not follow route reply option (%x)\n", dsr_option->dsr_type); IPAddress zeros; return zeros; } } } else if (dsr_option->dsr_type == DSR_TYPE_RERR) { // if this is a route error, then we expect a source route option // immediately following -- handle as we did with RREP. if there // is no source route option following, then this must be a // one-hop reply. // // XXX we might have multiple RERRs. const click_dsr_rerr *dsr_rerr = (click_dsr_rerr *)dsr_option; if (dsr_rerr->length() == dsr_len) { // if this RERR option is the only option in the header IPAddress src_addr(ip->ip_src.s_addr); return (src_addr); } else { dsr_option = (click_dsr_option *)(dsr_rerr->next_option()); if (dsr_option->dsr_type != DSR_TYPE_SOURCE_ROUTE) { DEBUG_CHATTER(" * DSRArpTable::last_hop: source route option did not follow route error option (%x)\n", dsr_option->dsr_type); IPAddress zeros; return zeros; } } } if (dsr_option->dsr_type == DSR_TYPE_SOURCE_ROUTE) { // either this is a normal source-routed packet, or a RREP or RERR // with a source route header click_dsr_source *dsr_source = (click_dsr_source *)(dsr_option); assert(dsr_source->dsr_type == DSR_TYPE_SOURCE_ROUTE); unsigned char segments = dsr_source->dsr_segsleft; unsigned char source_hops = dsr_source->num_addrs(); assert(segments <= source_hops); int index = source_hops - segments; if (index == 0) { // this is the first hop IPAddress src(ip->ip_src.s_addr); return src; } else { return dsr_source->addr[index-1].ip(); } } assert(0); return IPAddress(); } void DSRArpTable::add_entry(IPAddress ip, EtherAddress eth) { EtherAddress *e =_ip_map.findp(ip); assert(!e); _ip_map.insert(ip, eth); } void DSRArpTable::delete_entry(IPAddress ip) { EtherAddress *e =_ip_map.findp(ip); assert(e); _ip_map.remove(ip); } EtherAddress DSRArpTable::lookup_ip(IPAddress ip) { IPAddress bcast_ip("255.255.255.255"); if (ip == bcast_ip) { EtherAddress bcast_eth((unsigned char *)("\xff\xff\xff\xff\xff\xff")); return bcast_eth; } return (_ip_map.find(ip)); } EXPORT_ELEMENT(DSRArpTable) #include template class HashMap; CLICK_ENDDECLS