1 /** \file   rawnetarch_unix.c
2  * \brief   Raw ethernet interface, architecture-dependent stuff
3  *
4  * \author  Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
5  * \author  Bas Wassink <b.wassink@ziggo.nl>
6  *
7  * These functions let the UI enumerate the available interfaces.
8  *
9  * First, rawnet_arch_enumadapter_open() is used to start enumeration.
10  *
11  * rawnet_arch_enumadapter() is then used to gather information for each adapter
12  * present on the system, where:
13  *
14  * ppname points to a pointer which will hold the name of the interface
15  * ppdescription points to a pointer which will hold the description of the
16  * interface
17  *
18  * For each of these parameters, new memory is allocated, so it has to be
19  * freed with lib_free(), except ppdescription, which can be `NULL`, though
20  * calling lib_free() on `NULL` is safe.
21  *
22  * rawnet_arch_enumadapter_close() must be used to stop processing.
23  *
24  * Each function returns 1 on success, and 0 on failure.
25  * rawnet_arch_enumadapter() only fails if there is no more adpater; in this
26  * case, *ppname and *ppdescription are not altered.
27  */
28 
29 /*
30  * This file is part of VICE, the Versatile Commodore Emulator.
31  * See README for copyright notice.
32  *
33  *  This program is free software; you can redistribute it and/or modify
34  *  it under the terms of the GNU General Public License as published by
35  *  the Free Software Foundation; either version 2 of the License, or
36  *  (at your option) any later version.
37  *
38  *  This program is distributed in the hope that it will be useful,
39  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41  *  GNU General Public License for more details.
42  *
43  *  You should have received a copy of the GNU General Public License
44  *  along with this program; if not, write to the Free Software
45  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
46  *  02111-1307  USA.
47  *
48  */
49 
50 #include <stdint.h>
51 
52 #include "vice.h"
53 
54 #ifdef HAVE_RAWNET
55 
56 /*
57  * if we have a pcap version with either pcap_sendpacket or pcap_inject,
58  * do not use libnet anymore!
59  */
60 #if defined(HAVE_PCAP_SENDPACKET) || defined(HAVE_PCAP_INJECT)
61  #undef HAVE_LIBNET
62 #endif
63 
64 #include "pcap.h"
65 
66 #ifdef HAVE_LIBNET
67 #include "libnet.h"
68 #endif
69 
70 #include <assert.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 
75 #include "lib.h"
76 #include "log.h"
77 #include "rawnetarch.h"
78 
79 /*
80  *  FIXME:  rename all remaining tfe_ stuff to rawnet_
81  */
82 
83 #define RAWNET_DEBUG_WARN 1 /* this should not be deactivated
84                              * If this should not be deactived, why is this
85                              * here at all? --compyx
86                              */
87 
88 
89 /** \brief  Only select devices that are PCAP_IF_UP
90  *
91  * Since on Linux pcap_findalldevs() returns all interfaces, including special
92  * kernal devices such as nfqueue, filtering the list returned by pcap makes
93  * sense. Should this filtering cause trouble on other Unices, this define can
94  * be guarded with #ifdef SOME_UNIX_VERSION to disable the filtering.
95  */
96 #ifdef PCAP_IF_UP
97 #define RAWNET_ONLY_IF_UP
98 #endif
99 
100 
101 /** #define RAWNET_DEBUG_ARCH 1 **/
102 /** #define RAWNET_DEBUG_PKTDUMP 1 **/
103 
104 /* ------------------------------------------------------------------------- */
105 /*    variables needed                                                       */
106 
107 static log_t rawnet_arch_log = LOG_ERR;
108 
109 
110 /** \brief  Iterator for the list returned by pcap_findalldevs()
111  */
112 static pcap_if_t *rawnet_pcap_dev_iter = NULL;
113 
114 
115 /** \brief  Device list returned by pcap_findalldevs()
116  *
117  * Can be `NULL` since pcap_findalldevs() considers not finding any devices a
118  * succesful outcome.
119  */
120 static pcap_if_t *rawnet_pcap_dev_list = NULL;
121 
122 
123 static pcap_t *rawnet_pcap_fp = NULL;
124 
125 #ifdef HAVE_LIBNET
126 #ifdef VICE_USE_LIBNET_1_1
127 static libnet_t *TfeLibnetFP = NULL;
128 #else /* VICE_USE_LIBNET_1_1 */
129 static struct libnet_link_int *TfeLibnetFP = NULL;
130 #endif /* VICE_USE_LIBNET_1_1 */
131 
132 static char TfeLibnetErrBuf[LIBNET_ERRBUF_SIZE];
133 
134 #endif /* HAVE_LIBNET */
135 
136 
137 /** \brief  Buffer for pcap error messages
138  */
139 static char rawnet_pcap_errbuf[PCAP_ERRBUF_SIZE];
140 
141 
142 #ifdef RAWNET_DEBUG_PKTDUMP
143 
debug_output(const char * text,uint8_t * what,int count)144 static void debug_output( const char *text, uint8_t *what, int count )
145 {
146     char buffer[256];
147     char *p = buffer;
148     char *pbuffer1 = what;
149     int len1 = count;
150     int i;
151 
152     sprintf(buffer, "\n%s: length = %u\n", text, len1);
153     fprintf(stderr, "%s", buffer);
154     do {
155         p = buffer;
156         for (i=0; (i<8) && len1>0; len1--, i++) {
157             sprintf(p, "%02x ", (unsigned int)(unsigned char)*pbuffer1++);
158             p += 3;
159         }
160         *(p-1) = '\n'; *p = 0;
161         fprintf(stderr, "%s", buffer);
162     } while (len1>0);
163 }
164 #endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
165 
166 
rawnet_arch_enumadapter_open(void)167 int rawnet_arch_enumadapter_open(void)
168 {
169     if (pcap_findalldevs(&rawnet_pcap_dev_list, rawnet_pcap_errbuf) == -1) {
170         log_message(rawnet_arch_log,
171                 "ERROR in rawnet_arch_enumadapter_open: pcap_findalldevs: '%s'",
172                 rawnet_pcap_errbuf);
173         return 0;
174     }
175 
176     if (!rawnet_pcap_dev_list) {
177         log_message(rawnet_arch_log,
178                 "ERROR in rawnet_arch_enumadapter_open, finding all pcap "
179                 "devices - Do we have the necessary privilege rights?");
180         return 0;
181     }
182 
183     rawnet_pcap_dev_iter = rawnet_pcap_dev_list;
184     return 1;
185 }
186 
187 
188 /** \brief  Get current pcap device iterator values
189  *
190  * The \a ppname and \a ppdescription are heap-allocated via lib_stralloc()
191  * and should thus be freed after use with lib_free(). Please not that
192  * \a ppdescription can be `NULL` due to pcap_if_t->description being `NULL`,
193  * so check against `NULL` before using it. Calling lib_free() on it is safe
194  * though, free(`NULL`) is guaranteed to just do nothing.
195  *
196  * \param[out]  ppname          device name
197  * \param[out]  ppdescription   device description
198  *
199  * \return  bool (1 on success, 0 on failure)
200  */
rawnet_arch_enumadapter(char ** ppname,char ** ppdescription)201 int rawnet_arch_enumadapter(char **ppname, char **ppdescription)
202 {
203 #ifdef RAWNET_ONLY_IF_UP
204     /* only select devices that are up */
205     while (rawnet_pcap_dev_iter != NULL
206             && !(rawnet_pcap_dev_iter->flags & PCAP_IF_UP)) {
207         rawnet_pcap_dev_iter = rawnet_pcap_dev_iter->next;
208     }
209 #endif
210 
211     if (rawnet_pcap_dev_iter == NULL) {
212         return 0;
213     }
214 
215     *ppname = lib_stralloc(rawnet_pcap_dev_iter->name);
216     /* carefull: pcap_if_t->description can be NULL and lib_stralloc() fails on
217      * passing `NULL` */
218     if (rawnet_pcap_dev_iter->description != NULL) {
219         *ppdescription = lib_stralloc(rawnet_pcap_dev_iter->description);
220     } else {
221         *ppdescription = NULL;
222     }
223 
224     rawnet_pcap_dev_iter = rawnet_pcap_dev_iter->next;
225 
226     return 1;
227 }
228 
rawnet_arch_enumadapter_close(void)229 int rawnet_arch_enumadapter_close(void)
230 {
231     if (rawnet_pcap_dev_list) {
232         pcap_freealldevs(rawnet_pcap_dev_list);
233         rawnet_pcap_dev_list = NULL;
234     }
235     return 1;
236 }
237 
rawnet_pcap_open_adapter(const char * interface_name)238 static int rawnet_pcap_open_adapter(const char *interface_name)
239 {
240     rawnet_pcap_fp = pcap_open_live((char*)interface_name, 1700, 1, 20, rawnet_pcap_errbuf);
241     if ( rawnet_pcap_fp == NULL) {
242         log_message(rawnet_arch_log, "ERROR opening adapter: '%s'", rawnet_pcap_errbuf);
243         return 0;
244     }
245 
246     if (pcap_setnonblock(rawnet_pcap_fp, 1, rawnet_pcap_errbuf) < 0) {
247         log_message(rawnet_arch_log, "WARNING: Setting PCAP to non-blocking failed: '%s'", rawnet_pcap_errbuf);
248     }
249 
250     /* Check the link layer. We support only Ethernet for simplicity. */
251     if (pcap_datalink(rawnet_pcap_fp) != DLT_EN10MB) {
252         log_message(rawnet_arch_log, "ERROR: TFE works only on Ethernet networks.");
253         return 0;
254     }
255 
256 #ifdef HAVE_LIBNET
257     /* now, open the libnet device to be able to send afterwards */
258 #ifdef VICE_USE_LIBNET_1_1
259     TfeLibnetFP = libnet_init(LIBNET_LINK, (char *)interface_name, TfeLibnetErrBuf);
260 #else /* VICE_USE_LIBNET_1_1 */
261     TfeLibnetFP = libnet_open_link_interface(interface_name, TfeLibnetErrBuf);
262 #endif /* VICE_USE_LIBNET_1_1 */
263 
264     if (TfeLibnetFP == NULL) {
265         log_message(rawnet_arch_log, "Libnet interface could not be opened: '%s'", TfeLibnetErrBuf);
266 
267         if (rawnet_pcap_fp) {
268             pcap_close(rawnet_pcap_fp);
269             rawnet_pcap_fp = NULL;
270         }
271         return 0;
272     }
273 #endif /* HAVE_LIBNET */
274 
275     return 1;
276 }
277 
278 /* ------------------------------------------------------------------------- */
279 /*    the architecture-dependend functions                                   */
280 
rawnet_arch_init(void)281 int rawnet_arch_init(void)
282 {
283     rawnet_arch_log = log_open("TFEARCH");
284 
285     return 1;
286 }
287 
rawnet_arch_pre_reset(void)288 void rawnet_arch_pre_reset(void)
289 {
290 #ifdef RAWNET_DEBUG_ARCH
291     log_message( rawnet_arch_log, "rawnet_arch_pre_reset()." );
292 #endif
293 }
294 
rawnet_arch_post_reset(void)295 void rawnet_arch_post_reset(void)
296 {
297 #ifdef RAWNET_DEBUG_ARCH
298     log_message( rawnet_arch_log, "rawnet_arch_post_reset()." );
299 #endif
300 }
301 
rawnet_arch_activate(const char * interface_name)302 int rawnet_arch_activate(const char *interface_name)
303 {
304 #ifdef RAWNET_DEBUG_ARCH
305     log_message( rawnet_arch_log, "rawnet_arch_activate()." );
306 #endif
307     if (!rawnet_pcap_open_adapter(interface_name)) {
308         return 0;
309     }
310     return 1;
311 }
312 
rawnet_arch_deactivate(void)313 void rawnet_arch_deactivate( void )
314 {
315 #ifdef RAWNET_DEBUG_ARCH
316     log_message( rawnet_arch_log, "rawnet_arch_deactivate()." );
317 #endif
318 }
319 
rawnet_arch_set_mac(const uint8_t mac[6])320 void rawnet_arch_set_mac( const uint8_t mac[6] )
321 {
322 #ifdef RAWNET_DEBUG_ARCH
323     log_message( rawnet_arch_log, "New MAC address set: %02X:%02X:%02X:%02X:%02X:%02X.", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
324 #endif
325 }
326 
rawnet_arch_set_hashfilter(const uint32_t hash_mask[2])327 void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2])
328 {
329 #ifdef RAWNET_DEBUG_ARCH
330     log_message( rawnet_arch_log, "New hash filter set: %08X:%08X.", hash_mask[1], hash_mask[0]);
331 #endif
332 }
333 
334 /* int bBroadcast   - broadcast */
335 /* int bIA          - individual address (IA) */
336 /* int bMulticast   - multicast if address passes the hash filter */
337 /* int bCorrect     - accept correct frames */
338 /* int bPromiscuous - promiscuous mode */
339 /* int bIAHash      - accept if IA passes the hash filter */
340 
rawnet_arch_recv_ctl(int bBroadcast,int bIA,int bMulticast,int bCorrect,int bPromiscuous,int bIAHash)341 void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash)
342 {
343 #ifdef RAWNET_DEBUG_ARCH
344     log_message(rawnet_arch_log, "rawnet_arch_recv_ctl() called with the following parameters:" );
345     log_message(rawnet_arch_log, "\tbBroadcast   = %s", bBroadcast ? "TRUE" : "FALSE");
346     log_message(rawnet_arch_log, "\tbIA          = %s", bIA ? "TRUE" : "FALSE");
347     log_message(rawnet_arch_log, "\tbMulticast   = %s", bMulticast ? "TRUE" : "FALSE");
348     log_message(rawnet_arch_log, "\tbCorrect     = %s", bCorrect ? "TRUE" : "FALSE");
349     log_message(rawnet_arch_log, "\tbPromiscuous = %s", bPromiscuous ? "TRUE" : "FALSE");
350     log_message(rawnet_arch_log, "\tbIAHash      = %s", bIAHash ? "TRUE" : "FALSE");
351 #endif
352 }
353 
rawnet_arch_line_ctl(int bEnableTransmitter,int bEnableReceiver)354 void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver )
355 {
356 #ifdef RAWNET_DEBUG_ARCH
357     log_message(rawnet_arch_log,
358             "rawnet_arch_line_ctl() called with the following parameters:");
359     log_message(rawnet_arch_log,
360             "\tbEnableTransmitter = %s", bEnableTransmitter ? "TRUE" : "FALSE");
361     log_message(rawnet_arch_log,
362             "\tbEnableReceiver    = %s", bEnableReceiver ? "TRUE" : "FALSE");
363 #endif
364 }
365 
366 
367 /** \brief  Raw pcap packet
368  */
369 typedef struct rawnet_pcap_internal_s {
370     unsigned int len;   /**< length of packet data */
371     uint8_t *buffer;    /**< packet data */
372 } rawnet_pcap_internal_t;
373 
374 
375 /** \brief  Callback function invoked by libpcap for every incoming packet
376  *
377  * \param[in,out]   param       reference to internal VICE packet struct
378  * \param[in]       header      pcap header
379  * \param[in]       pkt_data    packet data
380  */
rawnet_pcap_packet_handler(u_char * param,const struct pcap_pkthdr * header,const u_char * pkt_data)381 static void rawnet_pcap_packet_handler(u_char *param,
382         const struct pcap_pkthdr *header, const u_char *pkt_data)
383 {
384     rawnet_pcap_internal_t *pinternal = (void*)param;
385 
386     /* determine the count of bytes which has been returned,
387      * but make sure not to overrun the buffer
388      */
389     if (header->caplen < pinternal->len) {
390         pinternal->len = header->caplen;
391     }
392 
393     memcpy(pinternal->buffer, pkt_data, pinternal->len);
394 }
395 
396 
397 /** \brief  Receives a frame
398  *
399  * If there's none, it returns a -1 in \a pinternal->len, if there is one,
400  * it returns the length of the frame in bytes in \a pinternal->len.
401  *
402  * It copies the frame to \a buffer and returns the number of copied bytes as
403  * the return value.
404  *
405  * \param[in,out]   pinternal   internal VICE packet struct
406  *
407  * \note    At most 'len' bytes are copied.
408  *
409  * \return  number of bytes copied or -1 on failure
410  */
rawnet_arch_receive_frame(rawnet_pcap_internal_t * pinternal)411 static int rawnet_arch_receive_frame(rawnet_pcap_internal_t *pinternal)
412 {
413     int ret = -1;
414 
415     /* check if there is something to receive */
416     if (pcap_dispatch(rawnet_pcap_fp, 1, rawnet_pcap_packet_handler,
417                 (void*)pinternal) != 0) {
418         /* Something has been received */
419         ret = pinternal->len;
420     }
421 
422 #ifdef RAWNET_DEBUG_ARCH
423     log_message(rawnet_arch_log,
424             "rawnet_arch_receive_frame() called, returns %d.", ret);
425 #endif
426 
427     return ret;
428 }
429 
430 #ifdef HAVE_LIBNET
431 
432 # ifdef VICE_USE_LIBNET_1_1
433 
434 #  define RAWNET_ARCH_TRANSMIT rawnet_arch_transmit_libnet_1_1
435 
rawnet_arch_transmit_libnet_1_1(int force,int onecoll,int inhibit_crc,int tx_pad_dis,int txlength,uint8_t * txframe)436 static void rawnet_arch_transmit_libnet_1_1(int force, int onecoll,
437         int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe)
438 {
439     /* we want to send via libnet */
440 
441     do {
442         libnet_pblock_t *p;
443 
444         p = libnet_pblock_new(TfeLibnetFP, txlength);
445 
446         if (p == NULL) {
447             log_message(rawnet_arch_log,
448                     "WARNING! Could not send packet, libnet_pblock_probe() failed!");
449             break;
450         }
451 
452         if ( libnet_pblock_append(TfeLibnetFP, p, txframe, txlength) == -1 ) {
453             log_message(rawnet_arch_log,
454                     "WARNING! Could not send packet, libnet_pblock_append() failed!");
455             break;
456         }
457 
458         libnet_pblock_update(TfeLibnetFP, p, 0, LIBNET_PBLOCK_ETH_H);
459 
460         if ( libnet_write(TfeLibnetFP) == -1 ) {
461             log_message(rawnet_arch_log,
462                     "WARNING! Could not send packet, libnet_write() failed!");
463             break;
464         }
465 
466         libnet_pblock_delete(TfeLibnetFP, p);
467 
468     } while (0);
469 }
470 
471 # else /* VICE_USE_LIBNET_1_1 */
472 
473 #  define RAWNET_ARCH_TRANSMIT rawnet_arch_transmit_libnet_1_0
474 
rawnet_arch_transmit_libnet_1_0(int force,int onecoll,int inhibit_crc,int tx_pad_dis,int txlength,uint8_t * txframe)475 static void rawnet_arch_transmit_libnet_1_0(int force, int onecoll,
476         int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe)
477 {
478     u_char *plibnet_buffer = NULL;
479 
480     /* we want to send via libnet 1.0 */
481 
482     if (libnet_init_packet(txlength, &plibnet_buffer)==-1) {
483         log_message(rawnet_arch_log, "WARNING! Could not send packet!");
484     } else {
485         if (plibnet_buffer) {
486             memcpy(plibnet_buffer, txframe, txlength);
487             libnet_write_link_layer(TfeLibnetFP, "eth0", plibnet_buffer, txlength);
488             libnet_destroy_packet(&plibnet_buffer);
489         } else {
490             log_message(rawnet_arch_log,
491                     "WARNING! Could not send packet: plibnet_buffer==NULL, "
492                     "but libnet_init_packet() did NOT fail!!");
493         }
494     }
495 
496 }
497 
498 # endif
499 
500 #else /* HAVE_LIBNET */
501 
502 #  define RAWNET_ARCH_TRANSMIT rawnet_arch_transmit_pcap
503 
504  #if defined(HAVE_PCAP_INJECT)
505   #define PCAP_INJECT pcap_inject
506  #elif defined(HAVE_PCAP_SENDPACKET)
507   #define PCAP_INJECT pcap_sendpacket
508  #else
509   #error SHOULD NOT HAPPEN: No libnet, but neither HAVE_PCAP_SENDPACKET nor HAVE_PCAP_INJECT are defined!
510  #endif
511 
512 
513 /** \brief  Transmit a packet(?) via pcap
514  *
515  */
rawnet_arch_transmit_pcap(int force,int onecoll,int inhibit_crc,int tx_pad_dis,int txlength,uint8_t * txframe)516 static void rawnet_arch_transmit_pcap(int force, int onecoll, int inhibit_crc,
517         int tx_pad_dis, int txlength, uint8_t *txframe)
518 {
519     /* we want to send via pcap */
520 
521     if (PCAP_INJECT(rawnet_pcap_fp, txframe, txlength) < 0) {
522         log_message(rawnet_arch_log, "WARNING! Could not send packet!");
523     }
524 }
525 
526 #endif /* HAVE_LIBNET */
527 
528 
529 /** \brief  Transmit a frame
530  *
531  * \param[in]   force       Delete waiting frames in transmit buffer
532  * \param[in]   onecoll     Terminate after just one collision
533  * \param[in]   inhibit_crc Do not append CRC to the transmission
534  * \param[in]   tx_pad_dis  Disable padding to 60 Bytes
535  * \param[in]   txlength    Frame length
536  * \param[in]   txframe     Pointer to the frame to be transmitted
537  */
rawnet_arch_transmit(int force,int onecoll,int inhibit_crc,int tx_pad_dis,int txlength,uint8_t * txframe)538 void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc,
539                           int tx_pad_dis, int txlength, uint8_t *txframe)
540 {
541 #ifdef RAWNET_DEBUG_ARCH
542     log_message(rawnet_arch_log,
543             "rawnet_arch_transmit() called, with: force = %s, onecoll = %s, "
544             "inhibit_crc=%s, tx_pad_dis=%s, txlength=%u",
545             force ? "TRUE" : "FALSE",
546             onecoll ? "TRUE" : "FALSE",
547             inhibit_crc ? "TRUE" : "FALSE",
548             tx_pad_dis ? "TRUE" : "FALSE",
549             txlength);
550 #endif
551 
552 #ifdef RAWNET_DEBUG_PKTDUMP
553     debug_output("Transmit frame: ", txframe, txlength);
554 #endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
555 
556     RAWNET_ARCH_TRANSMIT(force, onecoll, inhibit_crc, tx_pad_dis, txlength,
557             txframe);
558 }
559 
560 
561 /**
562  * \brief   Check if a frame was received
563  *
564  * This function checks if there was a frame received. If so, it returns 1,
565  * else 0.
566  *
567  * If there was no frame, none of the parameters is changed!
568  *
569  * If there was a frame, the following actions are done:
570  *
571  * - at maximum \a plen byte are transferred into the buffer given by \a pbuffer
572  * - \a plen gets the length of the received frame, EVEN if this is more
573  *   than has been copied to \a pbuffer!
574  * - if the dest. address was accepted by the hash filter, \a phashed is set,
575  *   else cleared.
576  * - if the dest. address was accepted by the hash filter, \a phash_index is
577  *   set to the number of the rule leading to the acceptance
578  * - if the receive was ok (good CRC and valid length), \a *prx_ok is set, else
579  *   cleared.
580  * - if the dest. address was accepted because it's exactly our MAC address
581  *   (set by rawnet_arch_set_mac()), \a pcorrect_mac is set, else cleared.
582  * - if the dest. address was accepted since it was a broadcast address,
583  *   \a pbroadcast is set, else cleared.
584  * - if the received frame had a crc error, \a pcrc_error is set, else cleared
585  *
586  * \param[out]      buffer          where to store a frame
587  * \param[in,out]   plen            IN: maximum length of frame to copy;
588  *                                  OUT: length of received frame OUT
589  *                                  can be bigger than IN if received frame was
590  *                                  longer than supplied buffer
591  * \param[out]      phashed         set if the dest. address is accepted by the
592  *                                  hash filter
593  * \param[out]      phash_index     hash table index if hashed == TRUE
594  * \param[out]      prx_ok          set if good CRC and valid length
595  * \param[out]      pcorrect_mac    set if dest. address is exactly our IA
596  * \param[out[      pbroadcast      set if dest. address is a broadcast address
597  * \param[out]      pcrc_error      set if received frame had a CRC error
598 */
rawnet_arch_receive(uint8_t * pbuffer,int * plen,int * phashed,int * phash_index,int * prx_ok,int * pcorrect_mac,int * pbroadcast,int * pcrc_error)599 int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int  *phashed,
600         int *phash_index, int *prx_ok, int *pcorrect_mac, int *pbroadcast,
601         int *pcrc_error)
602 {
603     int len;
604 
605     rawnet_pcap_internal_t internal = { *plen, pbuffer };
606 
607 #ifdef RAWNET_DEBUG_ARCH
608     log_message(rawnet_arch_log,
609             "rawnet_arch_receive() called, with *plen=%u.",
610             *plen);
611 #endif
612 
613     assert((*plen & 1) == 0);
614 
615     len = rawnet_arch_receive_frame(&internal);
616 
617     if (len != -1) {
618 
619 #ifdef RAWNET_DEBUG_PKTDUMP
620         debug_output("Received frame: ", internal.buffer, internal.len);
621 #endif /* #ifdef RAWNET_DEBUG_PKTDUMP */
622 
623         if (len & 1) {
624             ++len;
625         }
626 
627         *plen = len;
628 
629         /* we don't decide if this frame fits the needs;
630          * by setting all zero, we let tfe.c do the work
631          * for us
632          */
633         *phashed =
634         *phash_index =
635         *pbroadcast =
636         *pcorrect_mac =
637         *pcrc_error = 0;
638 
639         /* this frame has been received correctly */
640         *prx_ok = 1;
641 
642         return 1;
643     }
644 
645     return 0;
646 }
647 
648 
649 /** \brief  Find default device on which to capture
650  *
651  * \return  name of standard interface
652  *
653  * \note    pcap_lookupdev() has been deprecated, so the correct way to get
654  *          the default device is to use the first entry returned by
655  *          pcap_findalldevs().
656  *          See http://www.tcpdump.org/manpages/pcap_lookupdev.3pcap.html
657  *
658  * \return  default interface name or `NULL` when not found
659  *
660  * \note    free the returned value with lib_free() if not `NULL`
661  */
rawnet_arch_get_standard_interface(void)662 char *rawnet_arch_get_standard_interface(void)
663 {
664     char *dev = NULL;
665     char errbuf[PCAP_ERRBUF_SIZE];
666     pcap_if_t *list;
667 
668     if (pcap_findalldevs(&list, errbuf) == 0 && list != NULL) {
669         dev = lib_stralloc(list[0].name);
670         pcap_freealldevs(list);
671 #ifdef HAVE_TUNTAP
672     } else {
673         dev = lib_stralloc("tap0");
674 #endif
675     }
676     return dev;
677 }
678 
679 #endif /* #ifdef HAVE_RAWNET */
680