iPXE
tap.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010 Piotr JaroszyƄski <p.jaroszynski@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#undef __GLIBC__
38#include <linux/if.h>
39#include <linux/if_ether.h>
40#include <linux/if_tun.h>
41
42#define RX_BUF_SIZE 1536
43#define RX_QUOTA 4
44
45/** @file
46 *
47 * The TAP driver.
48 *
49 * The TAP is a Virtual Ethernet network device.
50 */
51
52struct tap_nic {
53 /** Tap interface name */
54 char * interface;
55 /** File descriptor of the opened tap device */
56 int fd;
57};
58
59/** Default MAC address */
61 { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
62
63/** Open the TAP device */
64static int tap_open(struct net_device * netdev)
65{
66 struct tap_nic * nic = netdev->priv;
67 struct ifreq ifr;
68 int ret;
69
70 nic->fd = linux_open("/dev/net/tun", O_RDWR);
71 if (nic->fd < 0) {
72 DBGC(nic, "tap %p open('/dev/net/tun') = %d (%s)\n", nic, nic->fd, linux_strerror(linux_errno));
73 return nic->fd;
74 }
75
76 memset(&ifr, 0, sizeof(ifr));
77 /* IFF_NO_PI for no extra packet information */
78 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
79 strncpy(ifr.ifr_name, nic->interface, IFNAMSIZ);
80 DBGC(nic, "tap %p interface = '%s'\n", nic, nic->interface);
81
82 ret = linux_ioctl(nic->fd, TUNSETIFF, &ifr);
83
84 if (ret != 0) {
85 DBGC(nic, "tap %p ioctl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
86 linux_close(nic->fd);
87 return ret;
88 }
89
90 /* Set nonblocking mode to make tap_poll easier */
91 ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
92
93 if (ret != 0) {
94 DBGC(nic, "tap %p fcntl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
95 linux_close(nic->fd);
96 return ret;
97 }
98
99 return 0;
100}
101
102/** Close the TAP device */
103static void tap_close(struct net_device *netdev)
104{
105 struct tap_nic * nic = netdev->priv;
106 linux_close(nic->fd);
107}
108
109/**
110 * Transmit an ethernet packet.
111 *
112 * The packet can be written to the TAP device and marked as complete immediately.
113 */
114static int tap_transmit(struct net_device *netdev, struct io_buffer *iobuf)
115{
116 struct tap_nic * nic = netdev->priv;
117 int rc;
118
119 /* Pad and align packet */
120 iob_pad(iobuf, ETH_ZLEN);
121
122 rc = linux_write(nic->fd, iobuf->data, iobuf->tail - iobuf->data);
123 DBGC2(nic, "tap %p wrote %d bytes\n", nic, rc);
125
126 return 0;
127}
128
129/** Poll for new packets */
130static void tap_poll(struct net_device *netdev)
131{
132 struct tap_nic * nic = netdev->priv;
133 struct pollfd pfd;
134 struct io_buffer * iobuf;
135 unsigned int quota = RX_QUOTA;
136 int r;
137
138 pfd.fd = nic->fd;
139 pfd.events = POLLIN;
140 if (linux_poll(&pfd, 1, 0) == -1) {
141 DBGC(nic, "tap %p poll failed (%s)\n", nic, linux_strerror(linux_errno));
142 return;
143 }
144 if ((pfd.revents & POLLIN) == 0)
145 return;
146
147 /* At this point we know there is at least one new packet to be read */
148
149 iobuf = alloc_iob(RX_BUF_SIZE);
150 if (! iobuf)
151 goto allocfail;
152
153 while (quota-- &&
154 ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0)) {
155 DBGC2(nic, "tap %p read %d bytes\n", nic, r);
156
157 iob_put(iobuf, r);
158 netdev_rx(netdev, iobuf);
159
160 iobuf = alloc_iob(RX_BUF_SIZE);
161 if (! iobuf)
162 goto allocfail;
163 }
164
165 free_iob(iobuf);
166 return;
167
168allocfail:
169 DBGC(nic, "tap %p alloc_iob failed\n", nic);
170}
171
172/**
173 * Set irq.
174 *
175 * Not used on linux, provide a dummy implementation.
176 */
177static void tap_irq(struct net_device *netdev, int enable)
178{
179 struct tap_nic *nic = netdev->priv;
180
181 DBGC(nic, "tap %p irq enable = %d\n", nic, enable);
182}
183
184/** Tap operations */
186 .open = tap_open,
187 .close = tap_close,
188 .transmit = tap_transmit,
189 .poll = tap_poll,
190 .irq = tap_irq,
191};
192
193/** Handle a device request for the tap driver */
195{
196 struct linux_setting *if_setting;
197 struct net_device *netdev;
198 struct tap_nic *nic;
199 int rc;
200
201 netdev = alloc_etherdev(sizeof(*nic));
202 if (! netdev)
203 return -ENOMEM;
204
206 nic = netdev->priv;
208 netdev->dev = &device->dev;
209 memcpy ( netdev->hw_addr, tap_default_mac, ETH_ALEN );
210 memset(nic, 0, sizeof(*nic));
211
212 /* Look for the mandatory if setting */
213 if_setting = linux_find_setting("if", &request->settings);
214
215 /* No if setting */
216 if (! if_setting) {
217 printf("tap missing a mandatory if setting\n");
218 rc = -EINVAL;
219 goto err_settings;
220 }
221
222 nic->interface = if_setting->value;
223 snprintf ( device->dev.name, sizeof ( device->dev.name ), "%s",
224 nic->interface );
226 if_setting->applied = 1;
227
228 /* Apply rest of the settings */
229 linux_apply_settings(&request->settings, &netdev->settings.settings);
230
231 /* Register network device */
232 if ((rc = register_netdev(netdev)) != 0)
233 goto err_register;
234
236
237 return 0;
238
240err_register:
241err_settings:
244 return rc;
245}
246
247/** Remove the device */
255
256/** Tap linux_driver */
257struct linux_driver tap_driver __linux_driver = {
258 .name = "tap",
259 .probe = tap_probe,
260 .remove = tap_remove,
261};
262
263/* Generate build rules */
264LINUX_ROM ( "tap", "Linux TUN/TAP NIC" );
#define RX_BUF_SIZE
Definition 3c90x.h:269
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
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_ZLEN
Definition if_ether.h:11
#define ETH_ALEN
Definition if_ether.h:9
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 iob_pad(struct io_buffer *iobuf, size_t min_len)
Pad I/O buffer.
Definition iobpad.c:50
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.
ssize_t __asmcall linux_write(int fd, const void *buf, size_t count)
int __asmcall linux_open(const char *pathname, int flags,...)
int linux_errno
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_read(int fd, void *buf, size_t count)
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
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
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
Definition tap.c:52
char * interface
Tap interface name.
Definition tap.c:54
int fd
File descriptor of the opened tap device.
Definition tap.c:56
#define RX_QUOTA
Definition tap.c:43
static void tap_poll(struct net_device *netdev)
Poll for new packets.
Definition tap.c:130
static struct net_device_operations tap_operations
Tap operations.
Definition tap.c:185
static int tap_open(struct net_device *netdev)
Open the TAP device.
Definition tap.c:64
static void tap_close(struct net_device *netdev)
Close the TAP device.
Definition tap.c:103
static int tap_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Transmit an ethernet packet.
Definition tap.c:114
static void tap_irq(struct net_device *netdev, int enable)
Set irq.
Definition tap.c:177
static const uint8_t tap_default_mac[ETH_ALEN]
Default MAC address.
Definition tap.c:60
static void tap_remove(struct linux_device *device)
Remove the device.
Definition tap.c:248
static int tap_probe(struct linux_device *device, struct linux_device_request *request)
Handle a device request for the tap driver.
Definition tap.c:194
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