servlib/conv_layers/EthConvergenceLayer.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2004-2006 Intel Corporation
       
     3  * 
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  * 
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  * 
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 #ifdef HAVE_CONFIG_H
       
    18 #  include <dtn-config.h>
       
    19 #endif
       
    20 
       
    21 // Only works on Linux (for now)
       
    22 #ifdef __linux__
       
    23 
       
    24 #include <sys/poll.h>
       
    25 #include <stdlib.h>
       
    26 #include <sys/types.h>
       
    27 #include <sys/socket.h>
       
    28 #include <netinet/in.h>
       
    29 #include <net/ethernet.h>
       
    30 #include <netpacket/packet.h>
       
    31 #include <sys/ioctl.h>
       
    32 
       
    33 #include <oasys/io/NetUtils.h>
       
    34 #include <oasys/io/IO.h>
       
    35 #include <oasys/thread/Timer.h>
       
    36 #include <oasys/util/OptParser.h>
       
    37 #include <oasys/util/StringBuffer.h>
       
    38 
       
    39 #include "EthConvergenceLayer.h"
       
    40 #include "bundling/Bundle.h"
       
    41 #include "bundling/BundleEvent.h"
       
    42 #include "bundling/BundleDaemon.h"
       
    43 #include "bundling/BundleList.h"
       
    44 #include "bundling/BundleProtocol.h"
       
    45 #include "contacts/ContactManager.h"
       
    46 #include "contacts/Link.h"
       
    47 
       
    48 using namespace oasys;
       
    49 namespace dtn {
       
    50 
       
    51 struct EthConvergenceLayer::Params EthConvergenceLayer::defaults_;
       
    52 
       
    53 /******************************************************************************
       
    54  *
       
    55  * EthConvergenceLayer
       
    56  *
       
    57  *****************************************************************************/
       
    58 
       
    59 EthConvergenceLayer::EthConvergenceLayer()
       
    60     : ConvergenceLayer("EthConvergenceLayer", "eth")
       
    61 {
       
    62     defaults_.beacon_interval_          = 1;
       
    63 }
       
    64 
       
    65 /**
       
    66  * Parse variable args into a parameter structure.
       
    67  */
       
    68 bool
       
    69 EthConvergenceLayer::parse_params(Params* params,
       
    70                                   int argc, const char* argv[],
       
    71                                   const char** invalidp)
       
    72 {
       
    73     oasys::OptParser p;
       
    74 
       
    75     p.addopt(new oasys::UIntOpt("beacon_interval", &params->beacon_interval_));
       
    76 
       
    77     if (! p.parse(argc, argv, invalidp)) {
       
    78         return false;
       
    79     }
       
    80 
       
    81     return true;
       
    82 }
       
    83 
       
    84 /* 
       
    85  *   Start listening to, and sending beacons on, the provided interface.
       
    86  *
       
    87  *   For now, we support interface strings on the form
       
    88  *   string://eth0
       
    89  *   
       
    90  *   this should change further down the line to simply be
       
    91  *    eth0
       
    92  *  
       
    93  */
       
    94 
       
    95 bool
       
    96 EthConvergenceLayer::interface_up(Interface* iface,
       
    97                                   int argc, const char* argv[])
       
    98 {
       
    99     Params params = EthConvergenceLayer::defaults_;
       
   100     const char *invalid;
       
   101     if (!parse_params(&params, argc, argv, &invalid)) {
       
   102         log_err("error parsing interface options: invalid option '%s'",
       
   103                 invalid);
       
   104         return false;
       
   105     }
       
   106 
       
   107     // grab the interface name out of the string:// 
       
   108 
       
   109     // XXX/jakob - this fugly mess needs to change when we get the
       
   110     // config stuff right
       
   111     const char* if_name=iface->name().c_str()+strlen("string://");
       
   112     log_info("EthConvergenceLayer::interface_up(%s).", if_name);
       
   113     
       
   114     Receiver* receiver = new Receiver(if_name, &params);
       
   115     receiver->logpathf("/cl/eth");
       
   116     receiver->start();
       
   117     iface->set_cl_info(receiver);
       
   118 
       
   119     // remembers the interface beacon object
       
   120     if_beacon_ = new Beacon(if_name, params.beacon_interval_);
       
   121     if_beacon_->logpathf("/cl/eth");
       
   122     if_beacon_->start();
       
   123     
       
   124     return true;
       
   125 }
       
   126 
       
   127 bool
       
   128 EthConvergenceLayer::interface_down(Interface* iface)
       
   129 {
       
   130   // XXX/jakob - need to keep track of the Beacon and Receiver threads for each 
       
   131   //             interface and kill them.
       
   132   // NOTIMPLEMENTED;
       
   133 
       
   134     // xxx/shawn needs to find a way to delete beacon;
       
   135     if_beacon_->set_should_stop();
       
   136     while (! if_beacon_->is_stopped()) {
       
   137         oasys::Thread::yield();
       
   138     }
       
   139     delete if_beacon_;
       
   140 
       
   141     Receiver *receiver = (Receiver *)iface->cl_info();
       
   142     receiver->set_should_stop();
       
   143     // receiver->interrupt_from_io();
       
   144     while (! receiver->is_stopped()) {
       
   145         oasys::Thread::yield();
       
   146     }
       
   147     delete receiver;
       
   148 
       
   149     return true;
       
   150 }
       
   151 
       
   152 bool
       
   153 EthConvergenceLayer::open_contact(const ContactRef& contact)
       
   154 {
       
   155     LinkRef link = contact->link();
       
   156     ASSERT(link != NULL);
       
   157     ASSERT(!link->isdeleted());
       
   158     ASSERT(link->cl_info() != NULL);
       
   159 
       
   160     log_debug("EthConvergenceLayer::open_contact: "
       
   161               "opening contact to link *%p", link.object());
       
   162 
       
   163     // parse out the address from the contact nexthop
       
   164     eth_addr_t addr;
       
   165     if (!EthernetScheme::parse(link->nexthop(), &addr)) {
       
   166         log_err("EthConvergenceLayer::open_contact: "
       
   167                 "next hop address '%s' not a valid eth uri", link->nexthop());
       
   168         return false;
       
   169     }
       
   170     
       
   171     // create a new connection for the contact
       
   172     Sender* sender = new Sender(((EthCLInfo*)link->cl_info())->if_name_,
       
   173                                 link->contact());
       
   174     contact->set_cl_info(sender);
       
   175 
       
   176     sender->logpathf("/cl/eth");
       
   177 
       
   178     BundleDaemon::post(new ContactUpEvent(contact));
       
   179     return true;
       
   180 }
       
   181 
       
   182 bool
       
   183 EthConvergenceLayer::close_contact(const ContactRef& contact)
       
   184 {  
       
   185     Sender* sender = (Sender*)contact->cl_info();
       
   186     
       
   187     log_info("close_contact *%p", contact.object());
       
   188 
       
   189     if (sender) {            
       
   190         contact->set_cl_info(NULL);
       
   191         delete sender;
       
   192     }
       
   193     
       
   194     return true;
       
   195 }
       
   196 
       
   197 void
       
   198 EthConvergenceLayer::delete_link(const LinkRef& link)
       
   199 {
       
   200     ASSERT(link != NULL);
       
   201     ASSERT(!link->isdeleted());
       
   202 
       
   203     log_debug("EthConvergenceLayer::delete_link: "
       
   204               "deleting link %s", link->name());
       
   205 
       
   206     if (link->cl_info() != NULL) {
       
   207         delete link->cl_info();
       
   208         link->set_cl_info(NULL);
       
   209     }
       
   210 }
       
   211 
       
   212 /**
       
   213  * Send bundles queued up for the contact.
       
   214  */
       
   215 void
       
   216 EthConvergenceLayer::bundle_queued(const LinkRef& link, const BundleRef& bundle)
       
   217 {
       
   218     ASSERT(link != NULL);
       
   219     ASSERT(!link->isdeleted());
       
   220     
       
   221     const ContactRef& contact = link->contact();
       
   222     Sender* sender = (Sender*)contact->cl_info();
       
   223     if (!sender) {
       
   224         log_crit("send_bundles called on contact *%p with no Sender!!",
       
   225                  contact.object());
       
   226         return;
       
   227     }
       
   228     ASSERT(contact == sender->contact_);
       
   229 
       
   230     sender->send_bundle(bundle);
       
   231 }
       
   232 
       
   233 bool
       
   234 EthConvergenceLayer::is_queued(const LinkRef& contact, Bundle* bundle)
       
   235 {
       
   236     (void)contact;
       
   237     (void)bundle;
       
   238 
       
   239     /// The Ethernet convergence layer does not maintain an output queue.
       
   240     return false;
       
   241 }
       
   242 
       
   243 /******************************************************************************
       
   244  *
       
   245  * EthConvergenceLayer::Receiver
       
   246  *
       
   247  *****************************************************************************/
       
   248 EthConvergenceLayer::Receiver::Receiver(const char* if_name,
       
   249                                         EthConvergenceLayer::Params* params)
       
   250   : Logger("EthConvergenceLayer::Receiver", "/dtn/cl/eth/receiver"),
       
   251     Thread("EthConvergenceLayer::Receiver")
       
   252 {
       
   253     memset(if_name_,0, IFNAMSIZ);
       
   254     strcpy(if_name_,if_name);
       
   255     Thread::flags_ |= INTERRUPTABLE;
       
   256     (void)params;
       
   257 }
       
   258 
       
   259 void
       
   260 EthConvergenceLayer::Receiver::process_data(u_char* bp, size_t len)
       
   261 {
       
   262     Bundle* bundle = NULL;       
       
   263     EthCLHeader ethclhdr;
       
   264     size_t bundle_len;
       
   265     struct ether_header* ethhdr=(struct ether_header*)bp;
       
   266     
       
   267     log_debug("Received DTN packet on interface %s, %zu.",if_name_, len);    
       
   268 
       
   269     // copy in the ethcl header.
       
   270     if (len < sizeof(EthCLHeader)) {
       
   271         log_err("process_data: "
       
   272                 "incoming packet too small (len = %zu)", len);
       
   273         return;
       
   274     }
       
   275     memcpy(&ethclhdr, bp+sizeof(struct ether_header), sizeof(EthCLHeader));
       
   276 
       
   277     // check for valid magic number and version
       
   278     if (ethclhdr.version != ETHCL_VERSION) {
       
   279         log_warn("remote sent version %d, expected version %d "
       
   280                  "-- disconnecting.", ethclhdr.version, ETHCL_VERSION);
       
   281         return;
       
   282     }
       
   283 
       
   284     if(ethclhdr.type == ETHCL_BEACON) {
       
   285         ContactManager* cm = BundleDaemon::instance()->contactmgr();
       
   286 
       
   287         char bundles_string[60];
       
   288         memset(bundles_string,0,60);
       
   289         EthernetScheme::to_string(&ethhdr->ether_shost[0],
       
   290                                   bundles_string);
       
   291         char next_hop_string[50], *ptr;
       
   292         memset(next_hop_string,0,50);
       
   293         ptr = strrchr(bundles_string, '/');
       
   294         strcpy(next_hop_string, ptr+1);
       
   295         
       
   296         ConvergenceLayer* cl = ConvergenceLayer::find_clayer("eth");
       
   297         EndpointID remote_eid(bundles_string);
       
   298 
       
   299         LinkRef link = cm->find_link_to(cl,
       
   300                                         next_hop_string,
       
   301                                         remote_eid,
       
   302                                         Link::OPPORTUNISTIC);
       
   303         
       
   304         if(link == NULL) {
       
   305             log_info("EthConvergenceLayer::Receiver::process_data: "
       
   306                      "Discovered next_hop %s on interface %s.",
       
   307                      next_hop_string, if_name_);
       
   308             
       
   309             // registers a new contact with the routing layer
       
   310             link = cm->new_opportunistic_link(cl,
       
   311                                               next_hop_string,
       
   312                                               EndpointID(bundles_string));
       
   313 
       
   314             if (link == NULL) {
       
   315                 log_debug("EthConvergenceLayer::Receiver::process_data: "
       
   316                           "failed to create new opportunistic link");
       
   317                 return;
       
   318             }
       
   319 
       
   320             oasys::ScopeLock l(link->lock(), "EthConvergenceLayer::Receiver");
       
   321             // It is doubtful that the link would be deleted already,
       
   322             // but check just in case.
       
   323             if (link->isdeleted()) {
       
   324                 log_warn("EthConvergenceLayer::Receiver::process_data: "
       
   325                          "link %s deleted before fully initialized",
       
   326                          link->name());
       
   327                 return;
       
   328             }
       
   329             ASSERT(link->cl_info() == NULL);
       
   330             link->set_cl_info(new EthCLInfo(if_name_));
       
   331             l.unlock();
       
   332         }
       
   333 
       
   334         ASSERT(link != NULL);
       
   335         oasys::ScopeLock l(link->lock(), "EthConvergenceLayer::Receiver");
       
   336 
       
   337         if (link->isdeleted()) {
       
   338             log_warn("EthConvergenceLayer::Receiver::process_data: "
       
   339                      "link %s already deleted", link->name());
       
   340             return;
       
   341         }
       
   342 
       
   343         ASSERT(link->cl_info() != NULL);
       
   344         ASSERT(strcmp(((EthCLInfo*)link->cl_info())->if_name_, if_name_) == 0);
       
   345 
       
   346         if(!link->isavailable()) {
       
   347             log_info("EthConvergenceLayer::Receiver::process_data: "
       
   348                      "Got beacon for previously unavailable link %s",
       
   349                      link->name());
       
   350             
       
   351             // XXX/demmer something should be done here to kick the link...
       
   352             log_err("XXX/demmer do something about link availability");
       
   353         }
       
   354         
       
   355         /**
       
   356          * If there already is a timer for this link, cancel it, which
       
   357          * will delete it when it bubbles to the top of the timer
       
   358          * queue. Then create a new timer.
       
   359          */
       
   360         BeaconTimer *timer = ((EthCLInfo*)link->cl_info())->timer;
       
   361         if (timer)
       
   362             timer->cancel();
       
   363 
       
   364         timer = new BeaconTimer(next_hop_string); 
       
   365         timer->schedule_in(ETHCL_BEACON_TIMEOUT_INTERVAL);
       
   366         
       
   367         ((EthCLInfo*)link->cl_info())->timer = timer;
       
   368 
       
   369         l.unlock();
       
   370     }
       
   371     else if(ethclhdr.type == ETHCL_BUNDLE) {
       
   372         // infer the bundle length based on the packet length minus the
       
   373         // eth cl header
       
   374         bundle_len = len - sizeof(EthCLHeader) - sizeof(struct ether_header);
       
   375         
       
   376         log_debug("process_data: got ethcl header -- bundle id %d, length %zu",
       
   377                   ntohl(ethclhdr.bundle_id), bundle_len);
       
   378         
       
   379         // skip past the cl header
       
   380         bp  += (sizeof(EthCLHeader) + sizeof(struct ether_header));
       
   381         len -= (sizeof(EthCLHeader) + sizeof(struct ether_header));
       
   382 
       
   383         bundle = new Bundle();
       
   384         bool complete = false;
       
   385         int cc = BundleProtocol::consume(bundle, bp, len, &complete);
       
   386 
       
   387         if (cc < 0) {
       
   388             log_err("process_data: bundle protocol error");
       
   389             delete bundle;
       
   390             return;
       
   391         }
       
   392 
       
   393         if (!complete) {
       
   394             log_err("process_data: incomplete bundle");
       
   395             delete bundle;
       
   396             return;
       
   397         }
       
   398 
       
   399         log_debug("process_data: new bundle id %d arrival, bundle length %zu",
       
   400                   bundle->bundleid(), bundle_len);
       
   401         
       
   402         BundleDaemon::post(
       
   403             new BundleReceivedEvent(bundle, EVENTSRC_PEER, 
       
   404                                     bundle_len, EndpointID::NULL_EID()));
       
   405     }
       
   406 }
       
   407 
       
   408 void
       
   409 EthConvergenceLayer::Receiver::run()
       
   410 {
       
   411     int sock;
       
   412     int cc;
       
   413     struct sockaddr_ll iface;
       
   414     unsigned char buffer[MAX_ETHER_PACKET];
       
   415 
       
   416     if((sock = socket(PF_PACKET,SOCK_RAW, htons(ETHERTYPE_DTN))) < 0) { 
       
   417         perror("socket");
       
   418         log_err("EthConvergenceLayer::Receiver::run() " 
       
   419                 "Couldn't open socket.");       
       
   420         exit(1);
       
   421     }
       
   422    
       
   423     // figure out the interface index of the device with name if_name_
       
   424     struct ifreq req;
       
   425     strcpy(req.ifr_name, if_name_);
       
   426     ioctl(sock, SIOCGIFINDEX, &req);
       
   427 
       
   428     memset(&iface, 0, sizeof(iface));
       
   429     iface.sll_family=AF_PACKET;
       
   430     iface.sll_protocol=htons(ETHERTYPE_DTN);
       
   431     iface.sll_ifindex=req.ifr_ifindex;
       
   432    
       
   433     if (bind(sock, (struct sockaddr *) &iface, sizeof(iface)) == -1) {
       
   434         perror("bind");
       
   435         exit(1);
       
   436     }
       
   437 
       
   438     log_warn("Reading from socket...");
       
   439     while(true) {
       
   440         cc=read (sock, buffer, MAX_ETHER_PACKET);
       
   441         if(cc<=0) {
       
   442             perror("EthConvergenceLayer::Receiver::run()");
       
   443             exit(1);
       
   444         }
       
   445         struct ether_header* hdr=(struct ether_header*)buffer;
       
   446   
       
   447         if(ntohs(hdr->ether_type)==ETHERTYPE_DTN) {
       
   448             process_data(buffer, cc);
       
   449         }
       
   450         else if(ntohs(hdr->ether_type)!=0x800)
       
   451         {
       
   452             log_err("Got non-DTN packet in Receiver, type %4X.",
       
   453                     ntohs(hdr->ether_type));
       
   454             // exit(1);
       
   455         }
       
   456 
       
   457         if(should_stop())
       
   458             break;
       
   459     }
       
   460 }
       
   461 
       
   462 /******************************************************************************
       
   463  *
       
   464  * EthConvergenceLayer::Sender
       
   465  *
       
   466  *****************************************************************************/
       
   467 
       
   468 /**
       
   469  * Constructor for the active connection side of a connection.
       
   470  */
       
   471 EthConvergenceLayer::Sender::Sender(char* if_name,
       
   472                                     const ContactRef& contact)
       
   473     : Logger("EthConvergenceLayer::Sender", "/dtn/cl/eth/sender"),
       
   474       contact_(contact.object(), "EthConvergenceLayer::Sender")
       
   475 {
       
   476     struct ifreq req;
       
   477     struct sockaddr_ll iface;
       
   478     LinkRef link = contact->link();
       
   479 
       
   480     memset(src_hw_addr_.octet, 0, 6); // determined in Sender::run()
       
   481     EthernetScheme::parse(link->nexthop(), &dst_hw_addr_);
       
   482 
       
   483     strcpy(if_name_, if_name);
       
   484     sock_ = 0;
       
   485 
       
   486     memset(&req, 0, sizeof(req));
       
   487     memset(&iface, 0, sizeof(iface));
       
   488 
       
   489     // Get and bind a RAW socket for this contact. XXX/jakob - seems
       
   490     // like it'd be enough with one socket per interface, not one per
       
   491     // contact. figure this out some time.
       
   492     if((sock_ = socket(AF_PACKET,SOCK_RAW, htons(ETHERTYPE_DTN))) < 0) { 
       
   493         perror("socket");
       
   494         exit(1);
       
   495     }
       
   496 
       
   497     // get the interface name from the contact info
       
   498     strcpy(req.ifr_name, if_name_);
       
   499 
       
   500     // ifreq the interface index for binding the socket    
       
   501     ioctl(sock_, SIOCGIFINDEX, &req);
       
   502     
       
   503     iface.sll_family=AF_PACKET;
       
   504     iface.sll_protocol=htons(ETHERTYPE_DTN);
       
   505     iface.sll_ifindex=req.ifr_ifindex;
       
   506         
       
   507     // store away the ethernet address of the device in question
       
   508     if(ioctl(sock_, SIOCGIFHWADDR, &req))
       
   509     {
       
   510         perror("ioctl");
       
   511         exit(1);
       
   512     } 
       
   513     memcpy(src_hw_addr_.octet,req.ifr_hwaddr.sa_data,6);    
       
   514 
       
   515     if (bind(sock_, (struct sockaddr *) &iface, sizeof(iface)) == -1) {
       
   516         perror("bind");
       
   517         exit(1);
       
   518     }
       
   519 }
       
   520         
       
   521 /* 
       
   522  * Send one bundle.
       
   523  */
       
   524 bool 
       
   525 EthConvergenceLayer::Sender::send_bundle(const BundleRef& bundle) 
       
   526 {
       
   527     int cc;
       
   528     struct iovec iov[3];
       
   529         
       
   530     EthCLHeader ethclhdr;
       
   531     struct ether_header hdr;
       
   532 
       
   533     memset(iov,0,sizeof(iov));
       
   534     
       
   535     // iovec slot 0 holds the ethernet header
       
   536 
       
   537     iov[0].iov_base = (char*)&hdr;
       
   538     iov[0].iov_len = sizeof(struct ether_header);
       
   539 
       
   540     // write the ethernet header
       
   541 
       
   542     memcpy(hdr.ether_dhost,dst_hw_addr_.octet,6);
       
   543     memcpy(hdr.ether_shost,src_hw_addr_.octet,6); // Sender::hw_addr
       
   544     hdr.ether_type=htons(ETHERTYPE_DTN);
       
   545     
       
   546     // iovec slot 1 for the eth cl header
       
   547 
       
   548     iov[1].iov_base = (char*)&ethclhdr;
       
   549     iov[1].iov_len  = sizeof(EthCLHeader);
       
   550     
       
   551     // write the ethcl header
       
   552 
       
   553     ethclhdr.version    = ETHCL_VERSION;
       
   554     ethclhdr.type       = ETHCL_BUNDLE;
       
   555     ethclhdr.bundle_id  = htonl(bundle->bundleid());
       
   556 
       
   557     // iovec slot 2 for the bundle
       
   558     BlockInfoVec* blocks = bundle->xmit_blocks()->find_blocks(contact_->link());
       
   559     ASSERT(blocks != NULL);
       
   560 
       
   561     bool complete = false;
       
   562     size_t total_len = BundleProtocol::produce(bundle.object(), blocks,
       
   563                                                buf_, 0, sizeof(buf_),
       
   564                                                &complete);
       
   565     if (!complete) {
       
   566         size_t formatted_len = BundleProtocol::total_length(blocks);
       
   567         log_err("send_bundle: bundle too big (%zu > %u)",
       
   568                 formatted_len, MAX_ETHER_PACKET);
       
   569         return -1;
       
   570     }
       
   571 
       
   572     iov[2].iov_base = (char *)buf_;
       
   573     iov[2].iov_len  = total_len;
       
   574     
       
   575     // We're done assembling the packet. Now write the whole thing to
       
   576     // the socket!
       
   577     log_info("Sending bundle out interface %s",if_name_);
       
   578 
       
   579     cc=IO::writevall(sock_, iov, 3);
       
   580     if(cc<0) {
       
   581         perror("send");
       
   582         log_err("Send failed!\n");
       
   583     }    
       
   584     log_info("Sent packet, size: %d",cc );
       
   585 
       
   586     // move the bundle off the link queue and onto the inflight queue
       
   587     contact_->link()->del_from_queue(bundle, total_len);
       
   588     contact_->link()->add_to_inflight(bundle, total_len);
       
   589 
       
   590     // check that we successfully wrote it all
       
   591     bool ok;
       
   592     int total = sizeof(EthCLHeader) + sizeof(struct ether_header) + total_len;
       
   593     if (cc != total) {
       
   594         log_err("send_bundle: error writing bundle (wrote %d/%d): %s",
       
   595                 cc, total, strerror(errno));
       
   596         ok = false;
       
   597     } else {
       
   598         // cons up a transmission event and pass it to the router
       
   599         // since this is an unreliable protocol, acked_len = 0, and
       
   600         // ack = false
       
   601         BundleDaemon::post(
       
   602             new BundleTransmittedEvent(bundle.object(), contact_,contact_->link(),
       
   603                                        total_len, false));
       
   604         ok = true;
       
   605     }
       
   606 
       
   607     return ok;
       
   608 }
       
   609 
       
   610 EthConvergenceLayer::Beacon::Beacon(const char* if_name,
       
   611                                     unsigned int beacon_interval)
       
   612   : Logger("EthConvergenceLayer::Beacon", "/dtn/cl/eth/beacon"),
       
   613     Thread("EthConvergenceLayer::Beacon")
       
   614 {
       
   615     Thread::flags_ |= INTERRUPTABLE;
       
   616     memset(if_name_, 0, IFNAMSIZ);
       
   617     strcpy(if_name_, if_name);
       
   618     beacon_interval_ = beacon_interval;
       
   619 }
       
   620 
       
   621 void EthConvergenceLayer::Beacon::run()
       
   622 {
       
   623     // ethernet broadcast address
       
   624     char bcast_mac_addr[6]={0xff,0xff,0xff,0xff,0xff,0xff};
       
   625     
       
   626     struct ether_header hdr;
       
   627     struct sockaddr_ll iface;
       
   628     EthCLHeader ethclhdr;
       
   629     
       
   630     int sock,cc;
       
   631     struct iovec iov[2];
       
   632     
       
   633     memset(&hdr,0,sizeof(hdr));
       
   634     memset(&ethclhdr,0,sizeof(ethclhdr));
       
   635     memset(&iface,0,sizeof(iface));
       
   636 
       
   637     ethclhdr.version = ETHCL_VERSION;
       
   638     ethclhdr.type    = ETHCL_BEACON;
       
   639     
       
   640     hdr.ether_type=htons(ETHERTYPE_DTN);
       
   641     
       
   642     // iovec slot 0 holds the ethernet header
       
   643     iov[0].iov_base = (char*)&hdr;
       
   644     iov[0].iov_len = sizeof(struct ether_header);
       
   645     
       
   646     // use iovec slot 1 for the eth cl header
       
   647     iov[1].iov_base = (char*)&ethclhdr;
       
   648     iov[1].iov_len  = sizeof(EthCLHeader); 
       
   649     
       
   650     /* 
       
   651        Get ourselves a raw socket, and configure it.
       
   652     */
       
   653     if((sock = socket(AF_PACKET,SOCK_RAW, htons(ETHERTYPE_DTN))) < 0) { 
       
   654         perror("socket");
       
   655         exit(1);
       
   656     }
       
   657 
       
   658     struct ifreq req;
       
   659     strcpy(req.ifr_name, if_name_);
       
   660     if(ioctl(sock, SIOCGIFINDEX, &req))
       
   661     {
       
   662         perror("ioctl");
       
   663         exit(1);
       
   664     }    
       
   665 
       
   666     iface.sll_ifindex=req.ifr_ifindex;
       
   667 
       
   668     if(ioctl(sock, SIOCGIFHWADDR, &req))
       
   669     {
       
   670         perror("ioctl");
       
   671         exit(1);
       
   672     } 
       
   673     
       
   674     memcpy(hdr.ether_dhost,bcast_mac_addr,6);
       
   675     memcpy(hdr.ether_shost,req.ifr_hwaddr.sa_data,6);
       
   676     
       
   677     log_info("Interface %s has interface number %d.",if_name_,req.ifr_ifindex);
       
   678     
       
   679     iface.sll_family=AF_PACKET;
       
   680     iface.sll_protocol=htons(ETHERTYPE_DTN);
       
   681     
       
   682     if (bind(sock, (struct sockaddr *) &iface, sizeof(iface)) == -1) {
       
   683         perror("bind");
       
   684         exit(1);
       
   685     }
       
   686 
       
   687     /*
       
   688      * Send the beacon on the socket every beacon_interval_ second.
       
   689      */
       
   690     while(1) {
       
   691         sleep(beacon_interval_);
       
   692 
       
   693         if (should_stop())
       
   694             break;
       
   695 
       
   696         log_debug("Sent beacon out interface %s.\n",if_name_ );
       
   697         
       
   698         cc=IO::writevall(sock, iov, 2);
       
   699         if(cc<0) {
       
   700             perror("send beacon");
       
   701             log_err("Send beacon failed!\n");
       
   702         }
       
   703     }
       
   704 }
       
   705 
       
   706 EthConvergenceLayer::BeaconTimer::BeaconTimer(char * next_hop)
       
   707     :  Logger("EthConvergenceLayer::BeaconTimer", "/dtn/cl/eth/beacontimer")
       
   708 {
       
   709     next_hop_=(char*)malloc(strlen(next_hop)+1);
       
   710     strcpy(next_hop_, next_hop);
       
   711 }
       
   712 
       
   713 EthConvergenceLayer::BeaconTimer::~BeaconTimer()
       
   714 {
       
   715     free(next_hop_);
       
   716 }
       
   717 
       
   718 void
       
   719 EthConvergenceLayer::BeaconTimer::timeout(const struct timeval& now)
       
   720 {
       
   721     ContactManager* cm = BundleDaemon::instance()->contactmgr();
       
   722     ConvergenceLayer* cl = ConvergenceLayer::find_clayer("eth");
       
   723     LinkRef link = cm->find_link_to(cl, next_hop_);
       
   724 
       
   725     (void)now;
       
   726 
       
   727     log_info("Neighbor %s timer expired.",next_hop_);
       
   728 
       
   729     if(link == NULL) {
       
   730       log_warn("No link for next_hop %s.",next_hop_);
       
   731     }
       
   732     else if(link->isopen()) {
       
   733         BundleDaemon::post(
       
   734             new LinkStateChangeRequest(link, Link::CLOSED,
       
   735                                        ContactDownEvent::BROKEN));
       
   736     }
       
   737     else {
       
   738         log_warn("next_hop %s unexpectedly not open",next_hop_);
       
   739     }
       
   740 }
       
   741 
       
   742 Timer *
       
   743 EthConvergenceLayer::BeaconTimer::copy()
       
   744 {
       
   745     return new BeaconTimer(*this);
       
   746 }
       
   747 
       
   748 } // namespace dtn
       
   749 
       
   750 #endif // __linux