📄 bmf.c
字号:
/* * OLSR Basic Multicast Forwarding (BMF) plugin. * Copyright (c) 2005 - 2007, Thales Communications, Huizen, The Netherlands. * Written by Erik Tromp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of Thales, BMF nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. *//* ------------------------------------------------------------------------- * File : Bmf.c * Description: Multicast forwarding functions * Created : 29 Jun 2006 * * ------------------------------------------------------------------------- */#define _MULTI_THREADED#include "Bmf.h"/* System includes */#include <stddef.h> /* NULL */#include <sys/types.h> /* ssize_t */#include <string.h> /* strerror() */#include <stdarg.h> /* va_list, va_start, va_end */#include <errno.h> /* errno */#include <assert.h> /* assert() */#include <linux/if_ether.h> /* ETH_P_IP */#include <linux/if_packet.h> /* struct sockaddr_ll, PACKET_MULTICAST */#include <pthread.h> /* pthread_t, pthread_create() */#include <signal.h> /* sigset_t, sigfillset(), sigdelset(), SIGINT */#include <netinet/ip.h> /* struct ip */#include <netinet/udp.h> /* struct udphdr *//* OLSRD includes */#include "defs.h" /* olsr_cnf, OLSR_PRINTF */#include "olsr.h" /* olsr_printf */#include "scheduler.h" /* olsr_register_scheduler_event */#include "mid_set.h" /* mid_lookup_main_addr() */#include "mpr_selector_set.h" /* olsr_lookup_mprs_set() */#include "link_set.h" /* get_best_link_to_neighbor() *//* BMF includes */#include "NetworkInterfaces.h" /* TBmfInterface, CreateBmfNetworkInterfaces(), CloseBmfNetworkInterfaces() */#include "Address.h" /* IsMulticast() */#include "Packet.h" /* ENCAP_HDR_LEN, BMF_ENCAP_TYPE, BMF_ENCAP_LEN etc. */#include "PacketHistory.h" /* InitPacketHistory() */static pthread_t BmfThread;static int BmfThreadRunning = 0;/* ------------------------------------------------------------------------- * Function : BmfPError * Description: Prints an error message at OLSR debug level 1. * First the plug-in name is printed. Then (if format is not NULL * and *format is not empty) the arguments are printed, followed * by a colon and a blank. Then the message and a new-line. * Input : format, arguments * Output : none * Return : none * Data Used : none * ------------------------------------------------------------------------- */void BmfPError(char* format, ...){#define MAX_STR_DESC 255 char* strErr = strerror(errno); char strDesc[MAX_STR_DESC]; /* Rely on short-circuit boolean evaluation */ if (format == NULL || *format == '\0') { olsr_printf(1, "%s: %s\n", PLUGIN_NAME, strErr); } else { va_list arglist; olsr_printf(1, "%s: ", PLUGIN_NAME); va_start(arglist, format); vsnprintf(strDesc, MAX_STR_DESC, format, arglist); va_end(arglist); strDesc[MAX_STR_DESC - 1] = '\0'; /* Ensures null termination */ olsr_printf(1, "%s: %s\n", strDesc, strErr); }} /* BmfPError *//* ------------------------------------------------------------------------- * Function : MainAddressOf * Description: Lookup the main address of a node * Input : ip - IP address of the node * Output : none * Return : The main IP address of the node * Data Used : none * ------------------------------------------------------------------------- */union olsr_ip_addr* MainAddressOf(union olsr_ip_addr* ip){ union olsr_ip_addr* result; /* TODO: mid_lookup_main_addr() is not thread-safe! */ result = mid_lookup_main_addr(ip); if (result == NULL) { result = ip; } return result;} /* MainAddressOf *//* ------------------------------------------------------------------------- * Function : EncapsulateAndForwardPacket * Description: Encapsulate a captured raw IP packet and forward it * Input : intf - the network interface on which to forward the packet * encapsulationUdpData - The encapsulation header, followed by * the encapsulated IP packet * Output : none * Return : none * Data Used : none * ------------------------------------------------------------------------- */static void EncapsulateAndForwardPacket( struct TBmfInterface* intf, unsigned char* encapsulationUdpData){ /* The packet */ u_int16_t udpDataLen = GetEncapsulationUdpDataLength(encapsulationUdpData); /* The next destination(s) */ struct TBestNeighbors bestNeighborLinks; int nPossibleNeighbors; struct sockaddr_in forwardTo; /* Next destination of encapsulation packet */ int nPacketsToSend; int nBytesWritten; int i; /* Retrieve at most two best neigbors to forward the packet to */ GetBestTwoNeighbors(&bestNeighborLinks, intf, NULL, NULL, NULL, &nPossibleNeighbors); if (nPossibleNeighbors <= 0) { OLSR_PRINTF( 8, "%s: --> not encap-forwarding on \"%s\": there is no neighbor that needs my retransmission\n", PLUGIN_NAME_SHORT, intf->ifName); return; } /* Compose destination of encapsulation packet */ memset(&forwardTo, 0, sizeof(forwardTo)); forwardTo.sin_family = AF_INET; forwardTo.sin_port = htons(BMF_ENCAP_PORT); /* Start by filling in the local broadcast address */ COPY_IP(&forwardTo.sin_addr.s_addr, &intf->broadAddr); /* - If the BMF mechanism is BM_UNICAST_PROMISCUOUS, always send just one * packet (to the best neighbor). * - If the BMF mechanism is BM_BROADCAST, * - send one unicast packet if there is one possible neighbor, * - send two unicast packets if there are two possible neighbors, and * - only if there are more than two possible neighbors, then send an * (WLAN-air-expensive, less reliable) broadcast packet. */ if (BmfMechanism == BM_UNICAST_PROMISCUOUS || nPossibleNeighbors < 2) { nPacketsToSend = 1; } else /* BmfMechanism == BM_BROADCAST && nPossibleNeighbors >= 2 */ { nPacketsToSend = 2; } for (i = 0; i < nPacketsToSend; i++) { if (BmfMechanism == BM_UNICAST_PROMISCUOUS || nPossibleNeighbors <= 2) { COPY_IP(&forwardTo.sin_addr.s_addr, &bestNeighborLinks.links[i]->neighbor_iface_addr); } /* Forward the BMF packet via the encapsulation socket */ nBytesWritten = sendto( intf->encapsulatingSkfd, encapsulationUdpData, udpDataLen, MSG_DONTROUTE, (struct sockaddr*) &forwardTo, sizeof(forwardTo)); /* Evaluate and display result */ if (nBytesWritten != udpDataLen) { BmfPError("sendto() error forwarding pkt on \"%s\"", intf->ifName); } else { /* Increase counter */ intf->nBmfPacketsTx++; OLSR_PRINTF( 8, "%s: --> encapsulated and forwarded on \"%s\" to %s\n", PLUGIN_NAME_SHORT, intf->ifName, inet_ntoa(forwardTo.sin_addr)); } /* if (nBytesWritten != udpDataLen) */ } /* for */} /* EncapsulateAndForwardPacket *//* ------------------------------------------------------------------------- * Function : BmfPacketCaptured * Description: Handle a captured IP packet * Input : intf - the network interface on which the packet was captured * sllPkttype - the type of packet. Either PACKET_OUTGOING, * PACKET_BROADCAST or PACKET_MULTICAST. * encapsulationUdpData - space for the encapsulation header, followed by * the captured IP packet * Output : none * Return : none * Data Used : BmfInterfaces * Notes : The IP packet is assumed to be captured on a socket of family * PF_PACKET and type SOCK_DGRAM (cooked). * ------------------------------------------------------------------------- */static void BmfPacketCaptured( struct TBmfInterface* intf, unsigned char sllPkttype, unsigned char* encapsulationUdpData){ union olsr_ip_addr src; /* Source IP address in captured packet */ union olsr_ip_addr dst; /* Destination IP address in captured packet */ union olsr_ip_addr* origIp; /* Main OLSR address of source of captured packet */ struct TBmfInterface* walker; int isFromOlsrIntf; int isFromOlsrNeighbor; int iAmMpr; unsigned char* ipPacket; /* The captured IP packet... */ u_int16_t ipPacketLen; /* ...and its length */ struct ip* ipHeader; /* The IP header inside the captured IP packet */ u_int32_t crc32; struct TEncapHeader* encapHdr; ipHeader = GetIpHeader(encapsulationUdpData); COPY_IP(&dst, &ipHeader->ip_dst); /* Only forward multicast packets. If configured, also forward local broadcast packets */ if (IsMulticast(&dst) || (EnableLocalBroadcast != 0 && COMP_IP(&dst, &intf->broadAddr))) { /* continue */ } else { return; } ipPacket = GetIpPacket(encapsulationUdpData); /* Don't forward fragments of IP packets. Also, don't forward OLSR packets (UDP * port 698) and BMF encapsulated packets */ if (IsIpFragment(ipPacket) || IsOlsrOrBmfPacket(ipPacket)) { return; } /* Increase counter */ intf->nBmfPacketsRx++; /* Check if the frame is captured on an OLSR-enabled interface */ isFromOlsrIntf = (intf->olsrIntf != NULL); /* Retrieve the length of the captured packet */ ipPacketLen = GetIpTotalLength(ipPacket); COPY_IP(&src, &ipHeader->ip_src); OLSR_PRINTF( 8, "%s: %s pkt of %ld bytes captured on %s interface \"%s\": %s->%s\n", PLUGIN_NAME_SHORT, sllPkttype == PACKET_OUTGOING ? "outgoing" : "incoming", (long)ipPacketLen, isFromOlsrIntf ? "OLSR" : "non-OLSR", intf->ifName, olsr_ip_to_string(&src), olsr_ip_to_string(&dst)); /* Lookup main address of source in the MID table of OLSR */ origIp = MainAddressOf(&src); /* Calculate packet fingerprint */ crc32 = PacketCrc32(ipPacket, ipPacketLen); /* Check if this packet was seen recently */ if (CheckAndMarkRecentPacket(crc32)) { /* Increase counter */ intf->nBmfPacketsRxDup++; OLSR_PRINTF( 8, "%s: --> discarding: packet is duplicate\n", PLUGIN_NAME_SHORT); return; } /* Compose encapsulation header */ encapHdr = (struct TEncapHeader*) encapsulationUdpData; memset (encapHdr, 0, ENCAP_HDR_LEN); encapHdr->type = BMF_ENCAP_TYPE; encapHdr->len = BMF_ENCAP_LEN; encapHdr->reserved = 0; encapHdr->crc32 = htonl(crc32); /* Check if the frame is captured on an OLSR interface from an OLSR neighbor. * TODO1: get_best_link_to_neighbor() is not thread-safe. * TODO2: get_best_link_to_neighbor() may be very CPU-expensive, a simpler call * would do here (something like 'get_any_link_to_neighbor()'). */ isFromOlsrNeighbor = (isFromOlsrIntf /* The frame is captured on an OLSR interface... */ && get_best_link_to_neighbor(origIp) != NULL); /* ...from an OLSR neighbor */ /* Check with OLSR if I am MPR for that neighbor */ /* TODO: olsr_lookup_mprs_set() is not thread-safe! */ iAmMpr = olsr_lookup_mprs_set(origIp) != NULL; /* Check with each network interface what needs to be done on it */ for (walker = BmfInterfaces; walker != NULL; walker = walker->next) { /* Is the forwarding interface OLSR-enabled? */ int isToOlsrIntf = (walker->olsrIntf != NULL); /* Depending on certain conditions, we decide whether or not to forward * the packet, and if it is forwarded, in which form (encapsulated * or not, TTL decreased or not). These conditions are: * - is the packet is coming in on an OLSR interface or not? (isFromOlsrIntf) * - is the packet going out on an OLSR interface or not? (isToOlsrIntf) * - if the packet if coming in on an OLSR interface: * - is the node that forwarded the packet my OLSR-neighbor? (isFromOlsrNeighbor) * - has the node that forwarded the packet selected me as MPR? (iAmMpr) * * Based on these conditions, the following cases can be distinguished: * * - Case 1: Packet coming in on an OLSR interface. What to * do with it on an OLSR interface? * Answer: * - Case 1.1: If the forwarding node is an OLSR neighbor that has *not*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -