iPXE
af_packet.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016 David Decotigny <ddecotig@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include <errno.h>
20#include <string.h>
21#include <stdio.h>
22#include <ipxe/linux_api.h>
23#include <ipxe/list.h>
24#include <ipxe/linux.h>
25#include <ipxe/malloc.h>
26#include <ipxe/device.h>
27#include <ipxe/netdevice.h>
28#include <ipxe/iobuf.h>
29#include <ipxe/ethernet.h>
30#include <ipxe/settings.h>
31#include <ipxe/socket.h>
32
33/* This hack prevents pre-2.6.32 headers from redefining struct sockaddr */
34#define _SYS_SOCKET_H
35#define __GLIBC__ 2
36#include <linux/socket.h>
37#include <linux/if.h>
38#include <linux/if_ether.h>
39#include <linux/if_packet.h>
40#undef __GLIBC__
41#include <byteswap.h>
42
43/* linux-specifc syscall params */
44#define LINUX_AF_PACKET 17
45#define LINUX_SOCK_RAW 3
46#define LINUX_SIOCGIFINDEX 0x8933
47#define LINUX_SIOCGIFHWADDR 0x8927
48
49#define RX_BUF_SIZE 1536
50
51/** @file
52 *
53 * The AF_PACKET driver.
54 *
55 * Bind to an existing linux network interface.
56 */
57
59 /** Linux network interface name */
60 char * ifname;
61 /** Packet socket descriptor */
62 int fd;
63 /** ifindex */
65};
66
67/** Open the linux interface */
68static int af_packet_nic_open ( struct net_device * netdev )
69{
70 struct af_packet_nic * nic = netdev->priv;
71 struct sockaddr_ll socket_address;
72 struct ifreq if_data;
73 int ret;
74
76 htons(ETH_P_ALL));
77 if (nic->fd < 0) {
78 DBGC(nic, "af_packet %p socket(AF_PACKET) = %d (%s)\n",
80 return nic->fd;
81 }
82
83 /* resolve ifindex of ifname */
84 memset(&if_data, 0, sizeof(if_data));
85 strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name));
86 ret = linux_ioctl(nic->fd, LINUX_SIOCGIFINDEX, &if_data);
87 if (ret < 0) {
88 DBGC(nic, "af_packet %p ioctl(SIOCGIFINDEX) = %d (%s)\n",
90 linux_close(nic->fd);
91 return ret;
92 }
93
94 nic->ifindex = if_data.ifr_ifindex;
95
96 /* bind to interface */
97 memset(&socket_address, 0, sizeof(socket_address));
98 socket_address.sll_family = LINUX_AF_PACKET;
99 socket_address.sll_ifindex = nic->ifindex;
100 socket_address.sll_protocol = htons(ETH_P_ALL);
101 ret = linux_bind(nic->fd, (void *) &socket_address,
102 sizeof(socket_address));
103 if (ret == -1) {
104 DBGC(nic, "af_packet %p bind() = %d (%s)\n",
106 linux_close(nic->fd);
107 return ret;
108 }
109
110 /* Set nonblocking mode to make af_packet_nic_poll() easier */
111 ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
112 if (ret != 0) {
113 DBGC(nic, "af_packet %p fcntl(%d, ...) = %d (%s)\n",
114 nic, nic->fd, ret, linux_strerror(linux_errno));
115 linux_close(nic->fd);
116 return ret;
117 }
118
119 return 0;
120}
121
122/** Close the packet socket */
123static void af_packet_nic_close ( struct net_device *netdev )
124{
125 struct af_packet_nic * nic = netdev->priv;
126 linux_close(nic->fd);
127}
128
129/**
130 * Transmit an ethernet packet.
131 *
132 * The packet can be written to the socket and marked as complete immediately.
133 */
135 struct io_buffer *iobuf )
136{
137 struct af_packet_nic * nic = netdev->priv;
138 struct sockaddr_ll socket_address;
139 const struct ethhdr * eh;
140 int rc;
141
142 memset(&socket_address, 0, sizeof(socket_address));
143 socket_address.sll_family = LINUX_AF_PACKET;
144 socket_address.sll_ifindex = nic->ifindex;
145 socket_address.sll_halen = ETH_ALEN;
146
147 eh = iobuf->data;
148 memcpy(socket_address.sll_addr, eh->h_dest, ETH_ALEN);
149
150 rc = linux_sendto(nic->fd, iobuf->data, iobuf->tail - iobuf->data,
151 0, (struct sockaddr *)&socket_address,
152 sizeof(socket_address));
153
154 DBGC2(nic, "af_packet %p wrote %d bytes\n", nic, rc);
156
157 return 0;
158}
159
160/** Poll for new packets */
161static void af_packet_nic_poll ( struct net_device *netdev )
162{
163 struct af_packet_nic * nic = netdev->priv;
164 struct pollfd pfd;
165 struct io_buffer * iobuf;
166 int r;
167
168 pfd.fd = nic->fd;
169 pfd.events = POLLIN;
170 if (linux_poll(&pfd, 1, 0) == -1) {
171 DBGC(nic, "af_packet %p poll failed (%s)\n",
173 return;
174 }
175 if ((pfd.revents & POLLIN) == 0)
176 return;
177
178 /* At this point we know there is at least one new packet to be read */
179
180 iobuf = alloc_iob(RX_BUF_SIZE);
181 if (! iobuf)
182 goto allocfail;
183
184 while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
185 DBGC2(nic, "af_packet %p read %d bytes\n", nic, r);
186
187 iob_put(iobuf, r);
188 netdev_rx(netdev, iobuf);
189
190 iobuf = alloc_iob(RX_BUF_SIZE);
191 if (! iobuf)
192 goto allocfail;
193 }
194
195 free_iob(iobuf);
196 return;
197
198allocfail:
199 DBGC(nic, "af_packet %p alloc_iob failed\n", nic);
200}
201
202/**
203 * Set irq.
204 *
205 * Not used on linux, provide a dummy implementation.
206 */
207static void af_packet_nic_irq ( struct net_device *netdev, int enable )
208{
209 struct af_packet_nic *nic = netdev->priv;
210
211 DBGC(nic, "af_packet %p irq enable = %d\n", nic, enable);
212}
213
214
216{
217 struct af_packet_nic *nic = netdev->priv;
218 struct ifreq if_data;
219 int ret;
220
221 /* retrieve default MAC address */
223 if (fd < 0) {
224 DBGC(nic, "af_packet %p cannot create raw socket (%s)\n",
226 return fd;
227 }
228
229 /* retrieve host's MAC address */
230 memset(&if_data, 0, sizeof(if_data));
231 strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name));
232 ret = linux_ioctl(fd, LINUX_SIOCGIFHWADDR, &if_data);
233 if (ret < 0) {
234 DBGC(nic, "af_packet %p cannot get mac addr (%s)\n",
236 linux_close(fd);
237 return ret;
238 }
239
240 linux_close(fd);
241 /* struct sockaddr = { u16 family, u8 pad[14] (equiv. sa_data) }; */
242 memcpy(netdev->ll_addr, if_data.ifr_hwaddr.pad, ETH_ALEN);
243 return 0;
244}
245
246/** AF_PACKET operations */
248 .open = af_packet_nic_open,
249 .close = af_packet_nic_close,
250 .transmit = af_packet_nic_transmit,
251 .poll = af_packet_nic_poll,
252 .irq = af_packet_nic_irq,
253};
254
255/** Handle a device request for the af_packet driver */
258{
259 struct linux_setting *if_setting;
260 struct net_device *netdev;
261 struct af_packet_nic *nic;
262 int rc;
263
264 netdev = alloc_etherdev(sizeof(*nic));
265 if (! netdev)
266 return -ENOMEM;
267
269 nic = netdev->priv;
271 netdev->dev = &device->dev;
272
273 memset(nic, 0, sizeof(*nic));
274
275 /* Look for the mandatory if setting */
276 if_setting = linux_find_setting("if", &request->settings);
277
278 /* No if setting */
279 if (! if_setting) {
280 printf("af_packet missing a mandatory if setting\n");
281 rc = -EINVAL;
282 goto err_settings;
283 }
284
285 nic->ifname = if_setting->value;
286 snprintf ( device->dev.name, sizeof ( device->dev.name ), "%s",
287 nic->ifname );
290 if_setting->applied = 1;
291
292 /* Apply rest of the settings */
293 linux_apply_settings(&request->settings, &netdev->settings.settings);
294
295 /* Register network device */
296 if ((rc = register_netdev(netdev)) != 0)
297 goto err_register;
298
300
301 return 0;
302
304err_register:
305err_settings:
308 return rc;
309}
310
311/** Remove the device */
319
320/** AF_PACKET linux_driver */
321struct linux_driver af_packet_nic_driver __linux_driver = {
322 .name = "af_packet",
323 .probe = af_packet_nic_probe,
324 .remove = af_packet_nic_remove,
325};
326
327/* Generate build rules */
328LINUX_ROM ( "af_packet", "AF_PACKET binding NIC" );
#define RX_BUF_SIZE
Definition 3c90x.h:269
static struct net_device_operations af_packet_nic_operations
AF_PACKET operations.
Definition af_packet.c:247
#define LINUX_SIOCGIFHWADDR
Definition af_packet.c:47
static void af_packet_nic_poll(struct net_device *netdev)
Poll for new packets.
Definition af_packet.c:161
#define LINUX_AF_PACKET
Definition af_packet.c:44
static int af_packet_nic_probe(struct linux_device *device, struct linux_device_request *request)
Handle a device request for the af_packet driver.
Definition af_packet.c:256
#define LINUX_SOCK_RAW
Definition af_packet.c:45
static void af_packet_nic_close(struct net_device *netdev)
Close the packet socket.
Definition af_packet.c:123
static void af_packet_nic_irq(struct net_device *netdev, int enable)
Set irq.
Definition af_packet.c:207
static int af_packet_update_properties(struct net_device *netdev)
Definition af_packet.c:215
static int af_packet_nic_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit an ethernet packet.
Definition af_packet.c:134
static int af_packet_nic_open(struct net_device *netdev)
Open the linux interface.
Definition af_packet.c:68
#define LINUX_SIOCGIFINDEX
Definition af_packet.c:46
static void af_packet_nic_remove(struct linux_device *device)
Remove the device.
Definition af_packet.c:312
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
Device model.
#define BUS_TYPE_TAP
TAP bus type.
Definition device.h:59
Error codes.
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition ethernet.c:265
Ethernet protocol.
static struct net_device * netdev
Definition gdbudp.c:53
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
u8 request[0]
List of IEs requested.
Definition ieee80211.h:2
#define ETH_ALEN
Definition if_ether.h:9
#define htons(value)
Definition byteswap.h:136
Linux devices, drivers and device requests.
static void linux_set_drvdata(struct linux_device *device, void *priv)
Set linux device driver-private data.
Definition linux.h:78
#define LINUX_ROM(_name, _desc)
Define build rules for a Linux driver.
Definition linux.h:70
void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block)
Apply a list of linux settings to a settings block.
#define __linux_driver
Declare a Linux driver.
Definition linux.h:67
static void * linux_get_drvdata(struct linux_device *device)
Get linux device driver-private data.
Definition linux.h:89
struct linux_setting * linux_find_setting(char *name, struct list_head *settings)
Look for the last occurrence of a setting with the specified name.
Configuration settings.
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
Linux host API.
int linux_errno
int __asmcall linux_bind(int sockfd, const struct sockaddr *addr, size_t addrlen)
int __asmcall linux_ioctl(int fd, unsigned long request,...)
int __asmcall linux_close(int fd)
int __asmcall linux_fcntl(int fd, int cmd,...)
ssize_t __asmcall linux_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, size_t addrlen)
ssize_t __asmcall linux_read(int fd, void *buf, size_t count)
int __asmcall linux_socket(int domain, int type, int protocol)
int __asmcall linux_poll(struct pollfd *fds, unsigned int nfds, int timeout)
const char *__asmcall linux_strerror(int linux_errno)
Linked lists.
Dynamic memory allocation.
static const uint8_t r[3][4]
MD4 shift amounts.
Definition md4.c:54
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition netdevice.c:549
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition netdevice.c:942
int register_netdev(struct net_device *netdev)
Register network device.
Definition netdevice.c:760
Network device management.
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition netdevice.h:789
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition netdevice.h:519
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition netdevice.h:532
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition netdevice.h:767
Socket addresses.
char * strncpy(char *dest, const char *src, size_t max)
Copy string.
Definition string.c:361
int fd
Packet socket descriptor.
Definition af_packet.c:62
char * ifname
Linux network interface name.
Definition af_packet.c:60
int ifindex
ifindex
Definition af_packet.c:64
unsigned int bus_type
Bus type.
Definition device.h:25
A hardware device.
Definition device.h:77
struct device_description desc
Device description.
Definition device.h:83
char name[40]
Name.
Definition device.h:79
An Ethernet link-layer header.
Definition if_ether.h:32
uint8_t h_dest[ETH_ALEN]
Destination MAC address.
Definition if_ether.h:34
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
void * tail
End of data.
Definition iobuf.h:55
A device request.
Definition linux.h:99
A linux device.
Definition linux.h:42
A linux driver.
Definition linux.h:54
A device request setting.
Definition linux.h:109
int applied
Was the setting already applied?
Definition linux.h:115
char * value
Value.
Definition linux.h:113
Network device operations.
Definition netdevice.h:214
A network device.
Definition netdevice.h:353
Definition nic.h:49
Generalized socket address structure.
Definition socket.h:97
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383