5353#include "ui.h"
5454
5555
56+ BOOL ski_nonet ; /* when true network is disabled, i.e. no interface is found */
57+
58+ #define ETH_DETACHED 0x0
59+ #define ETH_ATTACHED 0x1
60+
61+ typedef struct _eth_dev_t
62+ {
63+ struct _eth_dev_t * eth_next ; /* linked list of devices */
64+ int eth_fd ; /* current file descriptor */
65+ int eth_flags ; /* attached|detached */
66+ # if !HAVE_TUN_TAP
67+ char eth_name [IFNAMSIZ ]; /* real name */
68+ unsigned int eth_ipaddr ; /* current ipaddress */
69+ struct sockaddr_ll eth_sa_ll ; /* save extra copies on send */
70+ # endif
71+ }
72+ eth_dev_t ;
73+
74+ /*
75+ * list of currently detected devices
76+ */
77+ static eth_dev_t * eth_list ;
78+
79+ static inline eth_dev_t *
80+ find_eth (int fd )
81+ {
82+ eth_dev_t * p ;
83+
84+ for (p = eth_list ; p ; p = p -> eth_next )
85+ {
86+ if (p -> eth_fd == fd )
87+ return p ;
88+ }
89+ return NULL ;
90+ }
91+
92+ # if HAVE_TUN_TAP
93+
94+ #include <poll.h>
95+ #include <linux/if_tun.h>
96+
97+ int
98+ netdev_open (char * name , unsigned char * macaddr )
99+ {
100+ int fd ;
101+ struct ifreq ifr ;
102+ eth_dev_t * eth ;
103+
104+ if (ski_nonet == YES )
105+ return -1 ;
106+
107+ fd = open ("/dev/net/tun" , O_RDWR );
108+ if (fd == -1 )
109+ {
110+ cmdwPrint ("netdev_open: open /dev/net/tun failed: %d\n" , errno );
111+ return -1 ;
112+ }
113+
114+ memset (& ifr , 0 , sizeof ifr );
115+ ifr .ifr_flags = IFF_TAP | IFF_NO_PI ;
116+ if (name )
117+ strncpy (ifr .ifr_name , name , IFNAMSIZ );
118+
119+ if (ioctl (fd , TUNSETIFF , & ifr ) < 0 )
120+ {
121+ cmdwPrint ("netdev_open: ioctl TUNSETIFF failed: %d\n" , errno );
122+ close (fd );
123+ return -1 ;
124+ }
125+
126+ if (ioctl (fd , SIOCGIFHWADDR , & ifr ) == -1 )
127+ {
128+ cmdwPrint ("netdev_open: ioctl SIOCGIFHWADDR failed: %d\n" , errno );
129+ close (fd );
130+ return -1 ;
131+ }
132+
133+ memcpy (macaddr , (char * ) ifr .ifr_hwaddr .sa_data , IFHWADDRLEN );
134+
135+ eth = malloc (sizeof * eth );
136+ if (!eth )
137+ {
138+ cmdwPrint ("netdev_open: malloc failed: %d\n" , errno );
139+ close (fd );
140+ return -1 ;
141+ }
142+
143+ /*
144+ * the device is not yet attached
145+ */
146+ eth -> eth_fd = fd ;
147+ eth -> eth_next = eth_list ;
148+ eth -> eth_flags = ETH_DETACHED ;
149+ eth_list = eth ; /* we're at the head of the list now */
150+
151+ return fd ;
152+ }
153+
154+ int
155+ netdev_attach (int fd , unsigned int ipaddr )
156+ {
157+ int r ;
158+ eth_dev_t * eth = find_eth (fd );
159+
160+ if (eth == NULL )
161+ progExit ("netdev_attach: can't find eth %d\n" , fd );
162+
163+ /*
164+ * prepare for SIGIO: set ownership + asynchronous notification
165+ */
166+ r = fcntl (fd , F_SETOWN , getpid ());
167+ if (r == -1 )
168+ progExit ("netdev_attach: f_setown %d\n" , errno );
169+
170+ r = fcntl (fd , F_SETFL , fcntl (fd , F_GETFL , 0 ) | O_ASYNC | O_NONBLOCK );
171+ if (r == -1 )
172+ progExit ("netdev_attach: f_setfl %d\n" , errno );
173+
174+ eth -> eth_flags = ETH_ATTACHED ;
175+
176+ return 0 ;
177+ }
178+
179+ int
180+ netdev_detach (int fd )
181+ {
182+ int r ;
183+ eth_dev_t * eth = find_eth (fd );
184+
185+ if (eth == NULL )
186+ progExit ("netdev_detach: can't find eth %d\n" , fd );
187+
188+ /*
189+ * don't notify
190+ *
191+ * should also remove ownership but it does not really matter
192+ */
193+ r = fcntl (fd , F_SETFL , fcntl (fd , F_GETFL , 0 ) & (~O_ASYNC | O_NONBLOCK ));
194+ if (r == -1 )
195+ progExit ("netdev_detach: f_setfl %d\n" , errno );
196+
197+ eth -> eth_flags = ETH_DETACHED ;
198+
199+ return 0 ;
200+ }
201+
202+ /*
203+ * read the next frame from interface
204+ */
205+ long
206+ netdev_recv (int fd , char * fbuf , int len )
207+ {
208+ int r ;
209+
210+ if ((unsigned long ) fbuf & 0x3 )
211+ progExit ("receive frame not aligned" );
212+
213+ r = read (fd , fbuf , len );
214+ if (r == -1 && errno != EAGAIN )
215+ progExit ("netdev_recv: error on read %d\n" , errno );
216+
217+ return (long ) (r > 0 ? r : 0 );
218+ }
219+
220+ /*
221+ * write next frame to interface
222+ */
223+ long
224+ netdev_send (int fd , char * fbuf , int len )
225+ {
226+ int r ;
227+ eth_dev_t * eth = find_eth (fd );
228+
229+ if ((unsigned long ) fbuf & 0x3 )
230+ progExit ("trasmit frame not aligned" );
231+
232+ if (eth == NULL )
233+ progExit ("netdev_send: can't find %d\n" , fd );
234+
235+ r = write (fd , fbuf , len );
236+ if (r == -1 )
237+ progExit ("netdev_send: error on write %d\n" , errno );
238+
239+ return (long ) len ;
240+ }
241+
242+ static int
243+ netdev_can_read (int fd )
244+ {
245+ struct pollfd pfd ;
246+ int r ;
247+
248+ pfd .fd = fd ;
249+ pfd .events = POLLIN ;
250+ pfd .revents = 0 ;
251+ r = poll (& pfd , 1 , 0 );
252+ if (r == -1 || r == 0 )
253+ return r ;
254+ return pfd .revents & POLLIN ;
255+ }
256+
257+ # else /* !HAVE_TUN_TAP */
258+
56259#define MAX_FRAME_SIZE 1536 /* should be more than enough for ethernet */
57260
58261#define MAX_FD 256
59262
60- BOOL ski_nonet ; /* when true network is disabled, i.e. no interface is found */
61-
62263/*
63264 * thanks to tcpdump for the program dump
64265 *
@@ -119,38 +320,6 @@ static struct sock_filter insns[] =
119320 BPF_STMT (BPF_RET + BPF_K , 0xffffffff )
120321};
121322
122- #define ETH_DETACHED 0x0
123- #define ETH_ATTACHED 0x1
124-
125- typedef struct _eth_dev_t
126- {
127- struct _eth_dev_t * eth_next ; /* linked list of devices */
128- char eth_name [IFNAMSIZ ]; /* real name */
129- unsigned int eth_ipaddr ; /* current IP address */
130- int eth_fd ; /* current field descriptor */
131- int eth_flags ; /* attached|detached */
132- struct sockaddr_ll eth_sa_ll ; /* save extra copies on send */
133- }
134- eth_dev_t ;
135-
136- /*
137- * list of currently detected devices
138- */
139- static eth_dev_t * eth_list ;
140-
141- static inline eth_dev_t *
142- find_eth (int fd )
143- {
144- eth_dev_t * p ;
145-
146- for (p = eth_list ; p ; p = p -> eth_next )
147- {
148- if (p -> eth_fd == fd )
149- return p ;
150- }
151- return NULL ;
152- }
153-
154323/*
155324 * taken and adapted from
156325 * https://github.com/torvalds/linux/blob/v3.10/Documentation/networking/ifenslave.c
@@ -394,7 +563,6 @@ netdev_detach (int fd)
394563 return 0 ;
395564}
396565
397-
398566/*
399567 * read the next frame from interface
400568 */
@@ -437,6 +605,20 @@ netdev_send (int fd, char *fbuf, int len)
437605 return (long ) len ;
438606}
439607
608+ static int
609+ netdev_can_read (int fd )
610+ {
611+ char c ;
612+
613+ /*
614+ * We can't use FIONREAD here because it's only supported
615+ * by TCP sockets.
616+ */
617+ return recv (fd , & c , 1 , MSG_PEEK );
618+ }
619+
620+ # endif /* !HAVE_TUN_TAP */
621+
440622/*
441623 * check if SIGIO was because of network I/O
442624 * the other possible reason is keyboard input
449631isnetio (void )
450632{
451633 int r ;
452- char c ;
453634 eth_dev_t * p ;
454635
455636 if (eth_list == NULL )
@@ -462,11 +643,7 @@ isnetio (void)
462643 if (p -> eth_flags != ETH_ATTACHED )
463644 continue ;
464645
465- /*
466- * We can't use FIONREAD here because it's only supported
467- * by TCP sockets.
468- */
469- r = recv (p -> eth_fd , & c , 1 , MSG_PEEK );
646+ r = netdev_can_read (p -> eth_fd );
470647 if (r > 0 )
471648 return 1 ;
472649
0 commit comments