Fixed compilation error
[bochs-mirror.git] / iodev / eth_linux.cc
blob196ef53a119661e169fa601338fdaf1965eccf06
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: eth_linux.cc,v 1.23 2008/01/26 22:24:01 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 // Peter Grehan (grehan@iprg.nokia.com) coded all of this
28 // NE2000/ether stuff.
30 // eth_linux.cc - A Linux socket filter adaptation of the FreeBSD BPF driver
31 // <splite@purdue.edu> 21 June 2001
33 // Problems and limitations:
34 // - packets cannot be sent from BOCHS to the host
35 // - Linux kernel sometimes gets network watchdog timeouts under emulation
36 // - author doesn't know C++
38 // The config line in .bochsrc should look something like:
40 // ne2k: ioaddr=0x280, irq=10, mac=00:a:b:c:1:2, ethmod=linux, ethdev=eth0
43 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
44 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
45 // is used to know when we are exporting symbols and when we are importing.
46 #define BX_PLUGGABLE
48 #define NO_DEVICE_INCLUDES
49 #include "iodev.h"
51 #if BX_NETWORKING && defined (ETH_LINUX)
53 #include "eth.h"
55 #define LOG_THIS bx_devices.pluginNE2kDevice->
57 extern "C" {
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <sys/types.h>
61 #include <sys/socket.h>
62 #include <sys/ioctl.h>
63 #include <netpacket/packet.h>
64 #include <netinet/in.h>
65 #include <net/ethernet.h>
66 #include <net/if.h>
67 #include <linux/types.h>
68 #include <linux/filter.h>
71 #define BX_PACKET_POLL 1000 // Poll for a frame every 1000 usecs
73 // template filter for a unicast mac address and all
74 // multicast/broadcast frames
75 static const struct sock_filter macfilter[] = {
76 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
77 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
78 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
79 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
80 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
81 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
82 BPF_STMT(BPF_RET, 1514),
83 BPF_STMT(BPF_RET, 0),
85 #define BX_LSF_ICNT 8 // number of lsf instructions in macfilter
87 #if 0
88 // template filter for all frames
89 static const struct sock_filter promiscfilter[] = {
90 BPF_STMT(BPF_RET, 1514)
92 #endif
95 // Define the class. This is private to this module
97 class bx_linux_pktmover_c : public eth_pktmover_c {
98 public:
99 bx_linux_pktmover_c(const char *netif,
100 const char *macaddr,
101 eth_rx_handler_t rxh,
102 void *rxarg,
103 char *script);
104 void sendpkt(void *buf, unsigned io_len);
106 private:
107 unsigned char *linux_macaddr[6];
108 int fd;
109 int ifindex;
110 static void rx_timer_handler(void *);
111 void rx_timer(void);
112 int rx_timer_index;
113 struct sock_filter filter[BX_LSF_ICNT];
118 // Define the static class that registers the derived pktmover class,
119 // and allocates one on request.
121 class bx_linux_locator_c : public eth_locator_c {
122 public:
123 bx_linux_locator_c(void) : eth_locator_c("linux") {}
124 protected:
125 eth_pktmover_c *allocate(const char *netif,
126 const char *macaddr,
127 eth_rx_handler_t rxh,
128 void *rxarg, char *script) {
129 return (new bx_linux_pktmover_c(netif, macaddr, rxh, rxarg, script));
131 } bx_linux_match;
135 // Define the methods for the bx_linux_pktmover derived class
138 // the constructor
140 bx_linux_pktmover_c::bx_linux_pktmover_c(const char *netif,
141 const char *macaddr,
142 eth_rx_handler_t rxh,
143 void *rxarg,
144 char *script)
146 struct sockaddr_ll sll;
147 struct packet_mreq mr;
148 struct ifreq ifr;
149 struct sock_fprog fp;
151 memcpy(linux_macaddr, macaddr, 6);
153 // Open packet socket
155 if ((this->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
156 if (errno == EACCES)
157 BX_PANIC(("eth_linux: must be root or have CAP_NET_RAW capability to open socket"));
158 else
159 BX_PANIC(("eth_linux: could not open socket: %s", strerror(errno)));
160 this->fd = -1;
161 return;
164 // Translate interface name to index
166 memset(&ifr, 0, sizeof(ifr));
167 strcpy(ifr.ifr_name, netif);
168 if (ioctl(this->fd, SIOCGIFINDEX, &ifr) == -1) {
169 BX_PANIC(("eth_linux: could not get index for interface '%s'\n", netif));
170 close(fd);
171 this->fd = -1;
172 return;
174 this->ifindex = ifr.ifr_ifindex;
177 // Bind to given interface
179 memset(&sll, 0, sizeof(sll));
180 sll.sll_family = AF_PACKET;
181 sll.sll_ifindex = this->ifindex;
182 if (bind(fd, (struct sockaddr *)&sll, (socklen_t)sizeof(sll)) == -1) {
183 BX_PANIC(("eth_linux: could not bind to interface '%s': %s\n", netif, strerror(errno)));
184 close(fd);
185 this->fd = -1;
186 return;
189 // Put the device into promisc mode.
191 memset(&mr, 0, sizeof(mr));
192 mr.mr_ifindex = this->ifindex;
193 mr.mr_type = PACKET_MR_PROMISC;
194 if (setsockopt(this->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void *)&mr, (socklen_t)sizeof(mr)) == -1) {
195 BX_PANIC(("eth_linux: could not enable promisc mode: %s\n", strerror(errno)));
196 close(this->fd);
197 this->fd = -1;
198 return;
201 // Set up non-blocking i/o
202 if (fcntl(this->fd, F_SETFL, O_NONBLOCK) == -1) {
203 BX_PANIC(("eth_linux: could not set non-blocking i/o on socket"));
204 close(this->fd);
205 this->fd = -1;
206 return;
209 // Install a filter
210 #ifdef notdef
211 memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
212 fp.len = 1;
213 #endif
214 memcpy(&this->filter, macfilter, sizeof(macfilter));
215 this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 |
216 (macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
217 this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
218 fp.len = BX_LSF_ICNT;
219 fp.filter = this->filter;
220 BX_INFO(("eth_linux: fp.len=%d fp.filter=%lx", fp.len, (unsigned long) fp.filter));
221 if (setsockopt(this->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fp, sizeof(fp)) < 0) {
222 BX_PANIC(("eth_linux: could not set socket filter: %s", strerror(errno)));
223 close(this->fd);
224 this->fd = -1;
225 return;
228 // Start the rx poll
229 this->rx_timer_index =
230 bx_pc_system.register_timer(this, this->rx_timer_handler, BX_PACKET_POLL,
231 1, 1, "eth_linux"); // continuous, active
233 this->rxh = rxh;
234 this->rxarg = rxarg;
235 BX_INFO(("eth_linux: enabled NE2K emulation on interface %s", netif));
238 // the output routine - called with pre-formatted ethernet frame.
239 void
240 bx_linux_pktmover_c::sendpkt(void *buf, unsigned io_len)
242 int status;
244 if (this->fd != -1) {
245 status = write(this->fd, buf, io_len);
246 if (status == -1)
247 BX_INFO(("eth_linux: write failed: %s", strerror(errno)));
251 // The receive poll process
252 void
253 bx_linux_pktmover_c::rx_timer_handler(void *this_ptr)
255 bx_linux_pktmover_c *class_ptr = (bx_linux_pktmover_c *) this_ptr;
257 class_ptr->rx_timer();
260 void
261 bx_linux_pktmover_c::rx_timer(void)
263 int nbytes = 0;
264 Bit8u rxbuf[BX_PACKET_BUFSIZE];
265 struct sockaddr_ll sll;
266 socklen_t fromlen;
268 if (this->fd == -1)
269 return;
271 fromlen = sizeof(sll);
272 nbytes = recvfrom(this->fd, rxbuf, sizeof(rxbuf), 0, (struct sockaddr *)&sll, &fromlen);
274 if (nbytes == -1) {
275 if (errno != EAGAIN)
276 BX_INFO(("eth_linux: error receiving packet: %s\n", strerror(errno)));
277 return;
280 // this should be done with LSF someday
281 // filter out packets sourced by us
282 if (memcmp(sll.sll_addr, this->linux_macaddr, 6) == 0)
283 return;
284 // let through broadcast, multicast, and our mac address
285 // if ((memcmp(rxbuf, broadcast_macaddr, 6) == 0) || (memcmp(rxbuf, this->linux_macaddr, 6) == 0) || rxbuf[0] & 0x01) {
286 BX_DEBUG(("eth_linux: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
287 (*rxh)(rxarg, rxbuf, nbytes);
288 // }
290 #endif /* if BX_NETWORKING && defined ETH_LINUX */