apps/streamer/arping.c

Go to the documentation of this file.
00001 /*
00002  * Modified by Alexander Melichenko for using in Elphel cameras
00003  * 
00004  * arping.c - Ping hosts by ARP requests/replies
00005  *
00006  *  This program is free software: you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation, either version 3 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  *
00019  * Author:      Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
00020  * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
00021  */
00022 
00023 #include <sys/ioctl.h>
00024 #include <sys/signal.h>
00025 #include <sys/time.h>
00026 #include <errno.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 #include <time.h>
00032 #include <arpa/inet.h>
00033 #include <net/if.h>
00034 #include <netinet/ether.h>
00035 #include <netpacket/packet.h>
00036 
00037 #include "arping.h"
00038 
00039 static struct in_addr src;
00040 static struct in_addr dst;
00041 static struct sockaddr_ll me;
00042 static struct sockaddr_ll he;
00043 static int32_t s;
00044 
00045 static int32_t send_pack(int32_t sock, struct in_addr *src_addr,
00046                          struct in_addr *dst_addr, struct sockaddr_ll *ME,
00047                          struct sockaddr_ll *HE)
00048 {
00049     int32_t err;
00050     uint8_t buf[256];
00051     struct arphdr *ah = (struct arphdr *) buf;
00052     uint8_t *p = (uint8_t *) (ah + 1);
00053 
00054     ah->ar_hrd = htons(ME->sll_hatype);
00055     ah->ar_hrd = htons(ARPHRD_ETHER);
00056     ah->ar_pro = htons(ETH_P_IP);
00057     ah->ar_hln = ME->sll_halen;
00058     ah->ar_pln = 4;
00059     ah->ar_op = htons(ARPOP_REQUEST);
00060 
00061     memcpy(p, &ME->sll_addr, ah->ar_hln);
00062     p += ME->sll_halen;
00063 
00064     memcpy(p, src_addr, 4);
00065     p += 4;
00066 
00067     memcpy(p, &HE->sll_addr, ah->ar_hln);
00068     p += ah->ar_hln;
00069 
00070     memcpy(p, dst_addr, 4);
00071     p += 4;
00072 
00073     err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
00074     return err;
00075 }
00076 
00077 
00078 int32_t recv_pack(uint8_t * buf, int32_t len, struct sockaddr_ll * FROM,
00079                   uint8_t * mac)
00080 {
00081     struct arphdr *ah = (struct arphdr *) buf;
00082     uint8_t *p = (uint8_t *) (ah + 1);
00083     struct in_addr src_ip, dst_ip;
00084 
00085     /* Filter out wild packets */
00086     if (FROM->sll_pkttype != PACKET_HOST &&
00087         FROM->sll_pkttype != PACKET_BROADCAST &&
00088         FROM->sll_pkttype != PACKET_MULTICAST)
00089         return 0;
00090 
00091     /* Only these types are recognised */
00092     if (ah->ar_op != htons(ARPOP_REQUEST)
00093         && ah->ar_op != htons(ARPOP_REPLY))
00094         return 0;
00095 
00096     /* ARPHRD check and this darned FDDI hack here :-( */
00097     if (ah->ar_hrd != htons(FROM->sll_hatype) &&
00098         (FROM->sll_hatype != ARPHRD_FDDI
00099          || ah->ar_hrd != htons(ARPHRD_ETHER)))
00100         return 0;
00101 
00102     /* Protocol must be IP. */
00103     if (ah->ar_pro != htons(ETH_P_IP))
00104         return 0;
00105     if (ah->ar_pln != 4)
00106         return 0;
00107     if (ah->ar_hln != me.sll_halen)
00108         return 0;
00109     if (len < sizeof(*ah) + 2 * (4 + ah->ar_hln))
00110         return 0;
00111     memcpy(&src_ip, p + ah->ar_hln, 4);
00112     memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
00113 
00114     if (src_ip.s_addr != dst.s_addr)
00115         return 0;
00116     if (src.s_addr != dst_ip.s_addr)
00117         return 0;
00118     if (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln))
00119         return 0;
00120 
00121     memcpy(mac, p, 6);
00122 
00123     return 1;
00124 }
00125 
00126 int32_t arping(struct in_addr _src, struct in_addr _dst, uint8_t * mac)
00127 {
00128     int32_t socket_errno;
00129     int32_t ifindex = 0;
00130     int8_t  *device = "eth0";
00131 
00132     dst = _dst;
00133     src = _src;
00134 
00135     s = socket(PF_PACKET, SOCK_DGRAM, 0);
00136     socket_errno = errno;
00137 
00138     if (s < 0) {
00139         fprintf(stderr, "socket");
00140         return -1;
00141     }
00142 
00143     {
00144         struct ifreq ifr;
00145 
00146         memset(&ifr, 0, sizeof(ifr));
00147         strncpy(ifr.ifr_name, device, IFNAMSIZ - 1);
00148         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
00149             fprintf(stderr, "Interface %s not found", device);
00150             return -1;
00151         }
00152         ifindex = ifr.ifr_ifindex;
00153 
00154         if (ioctl(s, SIOCGIFFLAGS, (int8_t *) & ifr)) {
00155             fprintf(stderr, "SIOCGIFFLAGS");
00156             return -1;
00157         }
00158         if (!(ifr.ifr_flags & IFF_UP)) {
00159             fprintf(stderr, "Interface %s is down", device);
00160             return -1;
00161         }
00162         if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
00163             fprintf(stderr, "Interface %s is not ARPable\n", device);
00164             return -1;
00165         }
00166     }
00167 
00168     me.sll_family = AF_PACKET;
00169     me.sll_ifindex = ifindex;
00170     me.sll_protocol = htons(ETH_P_ARP);
00171     if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) {
00172         fprintf(stderr, "Error: bind\n");
00173         return -1;
00174     }
00175 
00176     {
00177         int32_t alen = sizeof(me);
00178 
00179         if (getsockname(s, (struct sockaddr *) &me, &alen) == -1) {
00180             fprintf(stderr, "Error: getsockname\n");
00181             return -1;
00182         }
00183     }
00184 
00185     if (me.sll_halen == 0) {
00186         fprintf(stderr,
00187                 "Interface \"%s\" is not ARPable (no ll address)\n",
00188                 device);
00189         return -1;
00190     }
00191     he = me;
00192     memset(he.sll_addr, -1, he.sll_halen);
00193 
00194     {
00195         int8_t packet[4096];
00196         struct sockaddr_ll from;
00197         int32_t alen = sizeof(from);
00198         int32_t cc = 0, res;
00199         struct timeval tm;
00200         int32_t timeout = 3;
00201         time_t prevTime;
00202         fd_set fdset;
00203 
00204         tm.tv_usec = 0;
00205         time(&prevTime);
00206 
00207         send_pack(s, &src, &dst, &me, &he);
00208 
00209         while (timeout > 0) {
00210             FD_ZERO(&fdset);
00211             FD_SET(s, &fdset);
00212             tm.tv_sec = timeout;
00213             res =
00214                 select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL,
00215                        &tm);
00216             if (res < 0) {
00217                 fprintf(stderr, "Error: select\n");
00218                 return -1;
00219             }
00220             if (res == 0) {
00221                 fprintf(stderr, "Error: host not responded\n");
00222                 return -1;
00223             }
00224 
00225             if (FD_ISSET(s, &fdset)) {
00226                 if ((cc = recvfrom(s, packet, sizeof(packet), 0,
00227                                    (struct sockaddr *) &from,
00228                                    &alen)) < 0) {
00229                     fprintf(stderr, "Error: recvfrom\n");
00230                     return -1;
00231                 } else {
00232                     break;
00233                 }
00234             }
00235             timeout -= time(NULL) - prevTime;
00236             time(&prevTime);
00237         }
00238 
00239         res = recv_pack(packet, cc, &from, mac);
00240         if (res != 1)
00241             return -1;
00242     }
00243 
00244     return 0;
00245 }
00246 

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1