|
|
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.