1 /////////////////////////////////////////////////////////////////////////
2 // $Id: eth_linux.cc,v 1.23 2008/01/26 22:24:01 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 MandrakeSoft S.A.
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.
48 #define NO_DEVICE_INCLUDES
51 #if BX_NETWORKING && defined (ETH_LINUX)
55 #define LOG_THIS bx_devices.pluginNE2kDevice->
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>
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),
85 #define BX_LSF_ICNT 8 // number of lsf instructions in macfilter
88 // template filter for all frames
89 static const struct sock_filter promiscfilter
[] = {
90 BPF_STMT(BPF_RET
, 1514)
95 // Define the class. This is private to this module
97 class bx_linux_pktmover_c
: public eth_pktmover_c
{
99 bx_linux_pktmover_c(const char *netif
,
101 eth_rx_handler_t rxh
,
104 void sendpkt(void *buf
, unsigned io_len
);
107 unsigned char *linux_macaddr
[6];
110 static void rx_timer_handler(void *);
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
{
123 bx_linux_locator_c(void) : eth_locator_c("linux") {}
125 eth_pktmover_c
*allocate(const char *netif
,
127 eth_rx_handler_t rxh
,
128 void *rxarg
, char *script
) {
129 return (new bx_linux_pktmover_c(netif
, macaddr
, rxh
, rxarg
, script
));
135 // Define the methods for the bx_linux_pktmover derived class
140 bx_linux_pktmover_c::bx_linux_pktmover_c(const char *netif
,
142 eth_rx_handler_t rxh
,
146 struct sockaddr_ll sll
;
147 struct packet_mreq mr
;
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) {
157 BX_PANIC(("eth_linux: must be root or have CAP_NET_RAW capability to open socket"));
159 BX_PANIC(("eth_linux: could not open socket: %s", strerror(errno
)));
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
));
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
)));
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
)));
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"));
211 memcpy(&this->filter
, promiscfilter
, sizeof(promiscfilter
));
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
)));
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
235 BX_INFO(("eth_linux: enabled NE2K emulation on interface %s", netif
));
238 // the output routine - called with pre-formatted ethernet frame.
240 bx_linux_pktmover_c::sendpkt(void *buf
, unsigned io_len
)
244 if (this->fd
!= -1) {
245 status
= write(this->fd
, buf
, io_len
);
247 BX_INFO(("eth_linux: write failed: %s", strerror(errno
)));
251 // The receive poll process
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();
261 bx_linux_pktmover_c::rx_timer(void)
264 Bit8u rxbuf
[BX_PACKET_BUFSIZE
];
265 struct sockaddr_ll sll
;
271 fromlen
= sizeof(sll
);
272 nbytes
= recvfrom(this->fd
, rxbuf
, sizeof(rxbuf
), 0, (struct sockaddr
*)&sll
, &fromlen
);
276 BX_INFO(("eth_linux: error receiving packet: %s\n", strerror(errno
)));
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)
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
);
290 #endif /* if BX_NETWORKING && defined ETH_LINUX */