|
|
1.1 root 1: /*
2: * Copyright (C) 2010 Piotr JaroszyĆski <[email protected]>
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 <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 __GLIBC__ 2
35: #include <linux/socket.h>
36: #undef __GLIBC__
37: #include <linux/if.h>
38: #include <linux/if_ether.h>
39: #include <linux/if_tun.h>
40:
41: #define RX_BUF_SIZE 1536
42:
43: /** @file
44: *
45: * The TAP driver.
46: *
47: * The TAP is a Virtual Ethernet network device.
48: */
49:
50: struct tap_nic {
51: /** Tap interface name */
52: char * interface;
53: /** File descriptor of the opened tap device */
54: int fd;
55: };
56:
57: /** Open the TAP device */
58: static int tap_open(struct net_device * netdev)
59: {
60: struct tap_nic * nic = netdev->priv;
61: struct ifreq ifr;
62: int ret;
63:
64: nic->fd = linux_open("/dev/net/tun", O_RDWR);
65: if (nic->fd < 0) {
66: DBGC(nic, "tap %p open('/dev/net/tun') = %d (%s)\n", nic, nic->fd, linux_strerror(linux_errno));
67: return nic->fd;
68: }
69:
70: memset(&ifr, 0, sizeof(ifr));
71: /* IFF_NO_PI for no extra packet information */
72: ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
73: strncpy(ifr.ifr_name, nic->interface, IFNAMSIZ);
74: DBGC(nic, "tap %p interface = '%s'\n", nic, nic->interface);
75:
76: ret = linux_ioctl(nic->fd, TUNSETIFF, &ifr);
77:
78: if (ret != 0) {
79: DBGC(nic, "tap %p ioctl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
80: linux_close(nic->fd);
81: return ret;
82: }
83:
84: /* Set nonblocking mode to make tap_poll easier */
85: ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
86:
87: if (ret != 0) {
88: DBGC(nic, "tap %p fcntl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
89: linux_close(nic->fd);
90: return ret;
91: }
92:
93: return 0;
94: }
95:
96: /** Close the TAP device */
97: static void tap_close(struct net_device *netdev)
98: {
99: struct tap_nic * nic = netdev->priv;
100: linux_close(nic->fd);
101: }
102:
103: /**
104: * Transmit an ethernet packet.
105: *
106: * The packet can be written to the TAP device and marked as complete immediately.
107: */
108: static int tap_transmit(struct net_device *netdev, struct io_buffer *iobuf)
109: {
110: struct tap_nic * nic = netdev->priv;
111: int rc;
112:
113: /* Pad and align packet */
114: iob_pad(iobuf, ETH_ZLEN);
115:
116: rc = linux_write(nic->fd, iobuf->data, iobuf->tail - iobuf->data);
117: DBGC2(nic, "tap %p wrote %d bytes\n", nic, rc);
118: netdev_tx_complete(netdev, iobuf);
119:
120: return 0;
121: }
122:
123: /** Poll for new packets */
124: static void tap_poll(struct net_device *netdev)
125: {
126: struct tap_nic * nic = netdev->priv;
127: struct pollfd pfd;
128: struct io_buffer * iobuf;
129: int r;
130:
131: pfd.fd = nic->fd;
132: pfd.events = POLLIN;
133: if (linux_poll(&pfd, 1, 0) == -1) {
134: DBGC(nic, "tap %p poll failed (%s)\n", nic, linux_strerror(linux_errno));
135: return;
136: }
137: if ((pfd.revents & POLLIN) == 0)
138: return;
139:
140: /* At this point we know there is at least one new packet to be read */
141:
142: iobuf = alloc_iob(RX_BUF_SIZE);
143: if (! iobuf)
144: goto allocfail;
145:
146: while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
147: DBGC2(nic, "tap %p read %d bytes\n", nic, r);
148:
149: iob_put(iobuf, r);
150: netdev_rx(netdev, iobuf);
151:
152: iobuf = alloc_iob(RX_BUF_SIZE);
153: if (! iobuf)
154: goto allocfail;
155: }
156:
157: free_iob(iobuf);
158: return;
159:
160: allocfail:
161: DBGC(nic, "tap %p alloc_iob failed\n", nic);
162: }
163:
164: /**
165: * Set irq.
166: *
167: * Not used on linux, provide a dummy implementation.
168: */
169: static void tap_irq(struct net_device *netdev, int enable)
170: {
171: struct tap_nic *nic = netdev->priv;
172:
173: DBGC(nic, "tap %p irq enable = %d\n", nic, enable);
174: }
175:
176: /** Tap operations */
177: static struct net_device_operations tap_operations = {
178: .open = tap_open,
179: .close = tap_close,
180: .transmit = tap_transmit,
181: .poll = tap_poll,
182: .irq = tap_irq,
183: };
184:
185: /** Handle a device request for the tap driver */
186: static int tap_probe(struct linux_device *device, struct linux_device_request *request)
187: {
188: struct linux_setting *if_setting;
189: struct net_device *netdev;
190: struct tap_nic *nic;
191: int rc;
192:
193: netdev = alloc_etherdev(sizeof(*nic));
194: if (! netdev)
195: return -ENOMEM;
196:
197: netdev_init(netdev, &tap_operations);
198: nic = netdev->priv;
199: linux_set_drvdata(device, netdev);
200: netdev->dev = &device->dev;
201: memset(nic, 0, sizeof(*nic));
202:
203: if ((rc = register_netdev(netdev)) != 0)
204: goto err_register;
205:
206: netdev_link_up(netdev);
207:
208: /* Look for the mandatory if setting */
209: if_setting = linux_find_setting("if", &request->settings);
210:
211: /* No if setting */
212: if (! if_setting) {
213: printf("tap missing a mandatory if setting\n");
214: rc = -EINVAL;
215: goto err_settings;
216: }
217:
218: nic->interface = if_setting->value;
219: if_setting->applied = 1;
220:
221: /* Apply rest of the settings */
222: linux_apply_settings(&request->settings, &netdev->settings.settings);
223:
224: return 0;
225:
226: err_settings:
227: unregister_netdev(netdev);
228: err_register:
229: netdev_nullify(netdev);
230: netdev_put(netdev);
231: return rc;
232: }
233:
234: /** Remove the device */
235: static void tap_remove(struct linux_device *device)
236: {
237: struct net_device *netdev = linux_get_drvdata(device);
238: unregister_netdev(netdev);
239: netdev_nullify(netdev);
240: netdev_put(netdev);
241: }
242:
243: /** Tap linux_driver */
244: struct linux_driver tap_driver __linux_driver = {
245: .name = "tap",
246: .probe = tap_probe,
247: .remove = tap_remove,
248: .can_probe = 1,
249: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.