OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / Libnet / src / libnet_link_sockpacket.c
1 /*
2  *  $Id: libnet_link_sockpacket.c,v 1.1.1.1 2000/05/25 00:28:49 route Exp $
3  *
4  *  libnet
5  *  libnet_sockpacket.c - linux sockpacket routines
6  *
7  *  Copyright (c) 1998 - 2001 Mike D. Schiffman <mike@infonexus.com>
8  *  All rights reserved.
9  *
10  * Copyright (c) 1996, 1997
11  *      The Regents of the University of California.  All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that: (1) source code distributions
15  * retain the above copyright notice and this paragraph in its entirety, (2)
16  * distributions including binary code include the above copyright notice and
17  * this paragraph in its entirety in the documentation or other materials
18  * provided with the distribution, and (3) all advertising materials mentioning
19  * features or use of this software display the following acknowledgement:
20  * ``This product includes software developed by the University of California,
21  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
22  * the University nor the names of its contributors may be used to endorse
23  * or promote products derived from this software without specific prior
24  * written permission.
25  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
26  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28  */
29
30 #if (HAVE_CONFIG_H)
31 #include "../include/config.h"
32 #endif
33 #include <sys/time.h>
34
35 #include <net/if.h>
36 #if (__GLIBC__)
37 #include <netinet/if_ether.h>
38 #include <net/if_arp.h>
39 #else
40 #include <linux/if_arp.h>
41 #include <linux/if_ether.h>
42 #endif
43
44 #if (HAVE_PF_PACKET)
45 #include <linux/if_packet.h>
46 #ifndef SOL_PACKET
47 #define SOL_PACKET 263
48 #endif  /* SOL_PACKET */
49 #endif  /* HAVE_PF_PACKET */
50
51 #include "../include/bpf.h"
52 #include "../include/libnet.h"
53
54 #include "../include/gnuc.h"
55 #ifdef HAVE_OS_PROTO_H
56 #include "../include/os-proto.h"
57 #endif
58
59 #if (HAVE_PF_PACKET)
60 static int
61 get_iface_index(int fd, const char *device)
62 {
63     struct ifreq ifr;  
64
65     memset(&ifr, 0, sizeof(ifr));
66     strncpy (ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1);
67     ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
68
69     if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1)
70     {
71         return (-1);
72     }
73
74     return ifr.ifr_ifindex;
75 }
76 #endif
77
78
79 struct libnet_link_int *
80 libnet_open_link_interface(char *device, char *ebuf)
81 {
82     register struct libnet_link_int *l;
83     struct ifreq ifr;
84 #if (HAVE_PF_PACKET)
85     struct packet_mreq mr;
86 #endif
87
88     l = (struct libnet_link_int *)malloc(sizeof (*l));
89     if (l == NULL)
90     {
91         sprintf(ebuf, "malloc: %s", ll_strerror(errno));
92         return (NULL);
93     }
94     memset(l, 0, sizeof (*l));
95
96 #if (HAVE_PF_PACKET)
97     l->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
98 #else
99     l->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
100 #endif
101     if (l->fd == -1)
102     {
103         sprintf(ebuf, "socket: %s", ll_strerror(errno));
104         goto bad;
105     }
106
107 #if (HAVE_PF_PACKET)
108     memset(&mr, 0, sizeof(mr));
109     mr.mr_ifindex = get_iface_index (l->fd, device);
110     if (mr.mr_ifindex == -1)
111     {
112         sprintf(ebuf, "SIOCGIFINDEX %s: %s", device, ll_strerror(errno));
113         goto bad;
114     }
115     mr.mr_type = PACKET_MR_ALLMULTI;
116
117     if (setsockopt(l->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (char *)&mr,
118         sizeof (mr)) < 0)
119     {
120         sprintf(ebuf, "setsockopt %s: %s", device, ll_strerror(errno));
121         goto bad;
122     }
123 #endif
124
125     memset(&ifr, 0, sizeof (ifr));
126     strncpy(ifr.ifr_name, device, sizeof (ifr.ifr_name));
127     if (ioctl(l->fd, SIOCGIFHWADDR, &ifr) < 0 )
128     {
129         sprintf(ebuf, "SIOCGIFHWADDR: %s", ll_strerror(errno));
130         goto bad;
131     }
132
133     switch (ifr.ifr_hwaddr.sa_family)
134     {
135         case ARPHRD_ETHER:
136         case ARPHRD_METRICOM:
137 #ifdef ARPHRD_LOOPBACK
138         case ARPHRD_LOOPBACK:   
139 #endif
140             l->linktype = DLT_EN10MB;
141             l->linkoffset = 0xe;
142             break;
143         case ARPHRD_SLIP:
144         case ARPHRD_CSLIP:
145         case ARPHRD_SLIP6:
146         case ARPHRD_CSLIP6:
147         case ARPHRD_PPP:
148             l->linktype = DLT_RAW;
149             break;
150         default:
151             sprintf(ebuf, "unknown physical layer type 0x%x",
152                 ifr.ifr_hwaddr.sa_family);
153         goto bad;
154     }
155     return (l);
156
157 bad:
158     if (l->fd >= 0)
159     {
160         close(l->fd);
161     }
162     free(l);
163     return (NULL);
164 }
165
166
167 int
168 libnet_close_link_interface(struct libnet_link_int *l)
169 {
170     if (close(l->fd) == 0)
171     {
172         return (1);
173     }
174     else
175     {
176         return (-1);
177     }
178 }
179
180
181 int
182 libnet_write_link_layer(struct libnet_link_int *l, const char *device,
183             u_char *buf, int len)
184 {
185     int c;
186 #if (HAVE_PF_PACKET)
187     struct sockaddr_ll sa;
188 #else
189     struct sockaddr sa;
190 #endif
191
192     memset(&sa, 0, sizeof (sa));
193 #if (HAVE_PF_PACKET)  
194     sa.sll_family    = AF_PACKET;
195     sa.sll_ifindex   = get_iface_index(l->fd, device);
196     if (sa.sll_ifindex == -1)
197     {
198         return (-1);
199     }
200     sa.sll_protocol  = htons(ETH_P_ALL);
201 #else
202     strncpy(sa.sa_data, device, sizeof (sa.sa_data));
203 #endif
204
205     c = sendto(l->fd, buf, len, 0, (struct sockaddr *)&sa, sizeof (sa));
206     if (c != len)
207     {
208 #if (__DEBUG)
209         libnet_error(LIBNET_ERR_WARNING,
210             "write_link_layer: %d bytes written (%s)\n", c,
211             strerror(errno));
212 #endif
213     }
214     return (c);
215 }
216
217
218 struct ether_addr *
219 libnet_get_hwaddr(struct libnet_link_int *l, const char *device, char *ebuf)
220 {
221     int fd;
222     struct ifreq ifr;
223     struct ether_addr *eap;
224     /*
225      *  XXX - non-re-entrant!
226      */
227     static struct ether_addr ea;
228
229     /*
230      *  Create dummy socket to perform an ioctl upon.
231      */
232     fd = socket(AF_INET, SOCK_DGRAM, 0);
233     if (fd < 0)
234     {
235         sprintf(ebuf, "get_hwaddr: %s", strerror(errno));
236         return (NULL);
237     }
238
239     memset(&ifr, 0, sizeof(ifr));
240     eap = &ea;
241     strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
242
243     if (ioctl(fd, SIOCGIFHWADDR, (char *)&ifr) < 0)
244     {
245         close(fd);
246         sprintf(ebuf, "get_hwaddr: %s", strerror(errno));
247         return (NULL);
248     }
249     memcpy(eap, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
250     close(fd);
251     return (eap);
252 }
253
254
255 /* EOF */