diff options
22 files changed, 1170 insertions, 567 deletions
diff --git a/freebsd/contrib/tcpdump/tcpdump.c b/freebsd/contrib/tcpdump/tcpdump.c index b1e7f0d1..5b658412 100644 --- a/freebsd/contrib/tcpdump/tcpdump.c +++ b/freebsd/contrib/tcpdump/tcpdump.c @@ -139,6 +139,7 @@ The Regents of the University of California. All rights reserved.\n"; #include <sys/sysctl.h> #include <machine/rtems-bsd-commands.h> #include <assert.h> +#include <sched.h> #include <rtems.h> #include <rtems/linkersets.h> #define setpriority(a, b, c) @@ -206,8 +207,10 @@ cap_channel_t *capdns; static void error(FORMAT_STRING(const char *), ...) NORETURN PRINTFLIKE(1, 2); static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2); static void exit_tcpdump(int) NORETURN; +#ifndef __rtems__ static RETSIGTYPE cleanup(int); static RETSIGTYPE child_cleanup(int); +#endif /* __rtems__ */ static void print_version(void); static void print_usage(void); static void show_tstamp_types_and_exit(pcap_t *, const char *device) NORETURN; @@ -219,6 +222,7 @@ static void show_devices_and_exit (void) NORETURN; static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *); static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); +#ifndef __rtems__ static void droproot(const char *, const char *); #ifdef SIGNAL_REQ_INFO @@ -232,6 +236,7 @@ RETSIGTYPE requestinfo(int); #elif defined(HAVE_ALARM) static void verbose_stats_dump(int sig); #endif +#endif /* __rtems__ */ static void info(int); static u_int packets_captured; @@ -623,6 +628,7 @@ static const struct option longopts[] = { { NULL, 0, NULL, 0 } }; +#ifndef __rtems__ #ifndef _WIN32 /* Drop root privileges and chroot if necessary */ static void @@ -654,7 +660,6 @@ droproot(const char *username, const char *chroot_dir) fprintf(stderr, "dropped privs to %s\n", username); } #else -#ifndef __rtems__ if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { fprintf(stderr, "%s: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", @@ -667,7 +672,6 @@ droproot(const char *username, const char *chroot_dir) else { fprintf(stderr, "dropped privs to %s\n", username); } -#endif /* __rtems__ */ #endif /* HAVE_LIBCAP_NG */ } else { @@ -689,6 +693,7 @@ droproot(const char *username, const char *chroot_dir) } #endif /* _WIN32 */ +#endif /* __rtems__ */ static int getWflagChars(int x) @@ -1196,26 +1201,22 @@ typedef struct { FILE *in; pcap_t *pd; rtems_id master; + bool terminate; } pcap_loop_context; static void pcap_loop_monitor(rtems_task_argument arg) { - pcap_loop_context *ctx; + const pcap_loop_context *ctx; FILE *in; pcap_t *pd; - rtems_id master; rtems_status_code sc; - ctx = (pcap_loop_context *)arg; + ctx = (const pcap_loop_context *)arg; in = ctx->in; pd = ctx->pd; - master = ctx->master; - - sc = rtems_event_transient_send(master); - assert(sc == RTEMS_SUCCESSFUL); - while (true) { + while (!ctx->terminate) { int c; c = fgetc(in); @@ -1224,19 +1225,22 @@ pcap_loop_monitor(rtems_task_argument arg) pcap_breakloop(pd); break; } + + sched_yield(); } - rtems_task_delete(RTEMS_SELF); - assert(0); + sc = rtems_event_transient_send(ctx->master); + assert(sc == RTEMS_SUCCESSFUL); + + rtems_task_exit(); } -static int -pcap_loop_wrapper(pcap_t *pd, int cnt, pcap_handler cb, u_char *ud) +static void +pcap_create_loop_monitor(pcap_loop_context *ctx, pcap_t *pd) { rtems_status_code sc; rtems_task_priority priority; rtems_id id; - pcap_loop_context ctx; sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority); @@ -1246,27 +1250,38 @@ pcap_loop_wrapper(pcap_t *pd, int cnt, pcap_handler cb, u_char *ud) RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &id); if (sc != RTEMS_SUCCESSFUL) { - fprintf(stderr, "tcpdump: cannot create helper thread: %s\n", + error("cannot create pcap loop monitor thread: %s\n", rtems_status_text(sc)); - return (-1); } fprintf(stdout, "tcpdump: press <ENTER> or 'q' or 'Q' to quit\n"); - ctx.in = stdin; - ctx.pd = pd; - ctx.master = rtems_task_self(); + ctx->in = stdin; + ctx->pd = pd; + ctx->master = rtems_task_self(); + ctx->terminate = false; sc = rtems_task_start(id, pcap_loop_monitor, - (rtems_task_argument)&ctx); + (rtems_task_argument)ctx); assert(sc == RTEMS_SUCCESSFUL); +} + +static void +pcap_terminate_loop_monitor(pcap_loop_context *ctx) +{ + rtems_status_code sc; + + ctx->terminate = true; sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); assert(sc == RTEMS_SUCCESSFUL); - - return (pcap_loop(pd, cnt, cb, ud)); } -#define pcap_loop(pd, cnt, cb, ud) pcap_loop_wrapper(pd, cnt, cb, ud) +static void +destroy_pcap_dumper(void *arg) +{ + + pcap_dump_close(arg); +} #endif /* __rtems__ */ int #ifndef __rtems__ @@ -1283,15 +1298,19 @@ main(int argc, char **argv) int dlt; const char *dlt_name; struct bpf_program fcode; +#ifndef __rtems__ #ifndef _WIN32 RETSIGTYPE (*oldhandler)(int); #endif +#endif /* __rtems__ */ struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; char VFileLine[PATH_MAX + 1]; +#ifndef __rtems__ char *username = NULL; char *chroot_dir = NULL; +#endif /* __rtems__ */ char *ret = NULL; char *end; #ifdef HAVE_PCAP_FINDALLDEVS @@ -1663,9 +1682,11 @@ main(int argc, char **argv) zflag = optarg; break; +#ifndef __rtems__ case 'Z': username = optarg; break; +#endif /* __rtems__ */ case '#': ndo->ndo_packet_number = 1; @@ -1962,6 +1983,7 @@ main(int argc, char **argv) init_print(ndo, localnet, netmask, timezone_offset); +#ifndef __rtems__ #ifndef _WIN32 (void)setsignal(SIGPIPE, cleanup); (void)setsignal(SIGTERM, cleanup); @@ -2029,6 +2051,7 @@ main(int argc, char **argv) } #endif /* _WIN32 */ +#endif /* __rtems__ */ if (pcap_setfilter(pd, &fcode) < 0) error("%s", pcap_geterr(pd)); @@ -2123,6 +2146,12 @@ main(int argc, char **argv) if (Uflag) pcap_dump_flush(p); #endif +#ifdef __rtems__ + if (rtems_bsd_program_add_destructor(destroy_pcap_dumper, p) == + NULL) { + error("cannot add destructor"); + } +#endif /* __rtems__ */ } else { dlt = pcap_datalink(pd); ndo->ndo_if_printer = get_if_printer(ndo, dlt); @@ -2130,6 +2159,7 @@ main(int argc, char **argv) pcap_userdata = (u_char *)ndo; } +#ifndef __rtems__ #ifdef SIGNAL_REQ_INFO /* * We can't get statistics when reading from a file rather @@ -2154,6 +2184,7 @@ main(int argc, char **argv) alarm(1); #endif } +#endif /* __rtems__ */ if (RFileName == NULL) { /* @@ -2196,7 +2227,19 @@ main(int argc, char **argv) #endif /* HAVE_CAPSICUM */ do { +#ifdef __rtems__ + pcap_loop_context ctx; + + if (RFileName == NULL) { + pcap_create_loop_monitor(&ctx, pd); + } +#endif /* __rtems__ */ status = pcap_loop(pd, cnt, callback, pcap_userdata); +#ifdef __rtems__ + if (RFileName == NULL) { + pcap_terminate_loop_monitor(&ctx); + } +#endif /* __rtems__ */ if (WFileName == NULL) { /* * We're printing packets. Flush the printed output, @@ -2315,6 +2358,7 @@ main(int argc, char **argv) exit_tcpdump(status == -1 ? 1 : 0); } +#ifndef __rtems__ /* make a clean exit on interrupts */ static RETSIGTYPE cleanup(int signo _U_) @@ -2367,6 +2411,7 @@ child_cleanup(int signo _U_) wait(NULL); } #endif /* HAVE_FORK && HAVE_VFORK */ +#endif /* __rtems__ */ static void info(register int verbose) @@ -2727,6 +2772,7 @@ print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) char Wpcap_version[]="3.1"; #endif +#ifndef __rtems__ #ifdef SIGNAL_REQ_INFO RETSIGTYPE requestinfo(int signo _U_) { @@ -2755,6 +2801,7 @@ static void verbose_stats_dump(int sig _U_) alarm(1); } #endif +#endif /* __rtems__ */ USES_APPLE_DEPRECATED_API static void diff --git a/freebsd/sbin/pfctl/pfctl_parser.c b/freebsd/sbin/pfctl/pfctl_parser.c index 56f548ba..8a93b39e 100644 --- a/freebsd/sbin/pfctl/pfctl_parser.c +++ b/freebsd/sbin/pfctl/pfctl_parser.c @@ -1351,10 +1351,17 @@ get_socket_domain(void) return (sdom); } +#ifdef __rtems__ +static int pfctl_s = -1; +#endif /* __rtems__ */ int get_query_socket(void) { +#ifndef __rtems__ static int s = -1; +#else /* __rtems__ */ +#define s pfctl_s +#endif /* __rtems__ */ if (s == -1) { if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) @@ -1362,6 +1369,9 @@ get_query_socket(void) } return (s); +#ifdef __rtems__ +#undef s +#endif /* __rtems__ */ } /* diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h index 3d805ea1..c43866bb 100644 --- a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h @@ -35,6 +35,7 @@ #define parseport _bsd_pfctl_parseport #define pfctl_cmdline_symset _bsd_pfctl_pfctl_cmdline_symset #define pfctl_load_anchors _bsd_pfctl_pfctl_load_anchors +#define pfctl_s _bsd_pfctl_s #define pfctlychar _bsd_pfctl_pfctlychar #define pfctlydebug _bsd_pfctl_pfctlydebug #define pfctlyerrflag _bsd_pfctl_pfctlyerrflag diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h index 4c39bea9..59b3541d 100644 --- a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h @@ -4,8 +4,6 @@ /* pfctl_altq.c */ RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char r2sbuf[][16]); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int idx); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc lssc); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc rtsc); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct hsearch_data if_map); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct hsearch_data qid_map); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct hsearch_data queue_map); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h index f9a7f49f..ac6655cc 100644 --- a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h @@ -4,3 +4,4 @@ /* pfctl_parser.c */ RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct hsearch_data isgroup_map); RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_host *iftab); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pfctl_s); diff --git a/freebsd/sys/dev/dc/if_dc.c b/freebsd/sys/dev/dc/if_dc.c index 7fc0ef54..b36967da 100644 --- a/freebsd/sys/dev/dc/if_dc.c +++ b/freebsd/sys/dev/dc/if_dc.c @@ -156,6 +156,10 @@ MODULE_DEPEND(dc, miibus, 1, 1, 1); * Various supported device vendors/types and their names. */ static const struct dc_type dc_devs[] = { +#ifdef __rtems__ + { DC_DEVID(DC_VENDORID_DEC, DC_DEVICEID_21140A), 0, + "Intel 21140A 10/100BaseTX" }, +#endif /* __rtems__ */ { DC_DEVID(DC_VENDORID_DEC, DC_DEVICEID_21143), 0, "Intel 21143 10/100BaseTX" }, { DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9009), 0, @@ -2076,6 +2080,9 @@ dc_attach(device_t dev) dc_eeprom_width(sc); switch (sc->dc_info->dc_devid) { +#ifdef __rtems__ + case DC_DEVID(DC_VENDORID_DEC, DC_DEVICEID_21140A): +#endif /* __rtems__ */ case DC_DEVID(DC_VENDORID_DEC, DC_DEVICEID_21143): sc->dc_type = DC_TYPE_21143; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; diff --git a/freebsd/sys/dev/dc/if_dcreg.h b/freebsd/sys/dev/dc/if_dcreg.h index 9ae26cc6..1c5d39a0 100644 --- a/freebsd/sys/dev/dc/if_dcreg.h +++ b/freebsd/sys/dev/dc/if_dcreg.h @@ -824,6 +824,13 @@ struct dc_softc { */ #define DC_VENDORID_DEC 0x1011 +#ifdef __rtems__ +/* + * DEC/Intel 21140 PCI device ID + */ +#define DC_DEVICEID_21140A 0x0009 + +#endif /* __rtems__ */ /* * DEC/Intel 21143 PCI device ID */ diff --git a/ipsec-tools/src/racoon/session.c b/ipsec-tools/src/racoon/session.c index 90120c76..77e4f6f6 100644 --- a/ipsec-tools/src/racoon/session.c +++ b/ipsec-tools/src/racoon/session.c @@ -209,6 +209,8 @@ session(void) #ifndef __rtems__ FD_ZERO(&preset_mask); #else /* __rtems__ */ + size_t allocated_mask_size = sizeof(fd_set) * + howmany(rtems_libio_number_iops, sizeof(fd_set) * 8); allocated_preset_mask = calloc(sizeof(fd_set), howmany(rtems_libio_number_iops, sizeof(fd_set) * 8)); if (allocated_preset_mask == NULL) @@ -342,7 +344,12 @@ session(void) /* schedular can change select() mask, so we reset * the working copy here */ +#ifndef __rtems__ active_mask = preset_mask; +#else /* __rtems__ */ + memcpy(allocated_active_mask, allocated_preset_mask, + allocated_mask_size); +#endif /* __rtems__ */ error = select(nfds + 1, &active_mask, NULL, NULL, timeout); if (error < 0) { @@ -2639,7 +2639,7 @@ class pci(builder.Module): ] ) self.addCPUDependentFreeBSDSourceFiles( - [ 'i386' ], + [ 'i386', 'powerpc' ], [ 'sys/x86/x86/legacy.c', 'sys/x86/pci/pci_bus.c', @@ -5230,6 +5230,7 @@ class tests(builder.Module): self.addTest(mm.generator['test']('ipsec01', ['test_main'])) self.addTest(mm.generator['test']('openssl01', ['test_main'])) self.addTest(mm.generator['test']('openssl02', ['test_main'])) + self.addTest(mm.generator['test']('tcpdump01', ['test_main'])) def load(mm): diff --git a/rtemsbsd/include/bsp/nexus-devices.h b/rtemsbsd/include/bsp/nexus-devices.h index d2ceab8e..86305e9c 100644 --- a/rtemsbsd/include/bsp/nexus-devices.h +++ b/rtemsbsd/include/bsp/nexus-devices.h @@ -197,6 +197,12 @@ SYSINIT_DRIVER_REFERENCE(ukphy, miibus); RTEMS_BSD_DEFINE_NEXUS_DEVICE(fec, 0, 0, NULL); SYSINIT_DRIVER_REFERENCE(ukphy, miibus); -#endif +#elif defined(LIBBSP_POWERPC_MOTOROLA_POWERPC_BSP_H) + +RTEMS_BSD_DRIVER_PC_LEGACY; +RTEMS_BSD_DRIVER_PCI_DC; +RTEMS_BSD_DRIVER_UKPHY; + +#endif /* LIBBSP_POWERPC_MOTOROLA_POWERPC_BSP_H */ #endif diff --git a/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h b/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h index ff545dc0..c2d71eed 100644 --- a/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h +++ b/rtemsbsd/include/machine/rtems-bsd-nexus-bus.h @@ -77,6 +77,7 @@ * RTEMS_BSD_DRIVER_ICSPHY * RTEMS_BSD_DRIVER_REPHY * RTEMS_BSD_DRIVER_PHY_MIC + * RTEMS_BSD_DRIVER_UKPHY */ #if !defined(RTEMS_BSD_NEXUS_BUS_h) @@ -441,6 +442,14 @@ extern "C" { SYSINIT_DRIVER_REFERENCE(re, pci); #endif /* RTEMS_BSD_DRIVER_PCI_RE */ +/* + * DEC Tulip Driver + */ +#if !defined(RTEMS_BSD_DRIVER_PCI_DC) + #define RTEMS_BSD_DRIVER_PCI_DC \ + SYSINIT_DRIVER_REFERENCE(dc, pci); +#endif /* RTEMS_BSD_DRIVER_PCI_DC */ + /** ** MMI Physical Layer Support. **/ @@ -477,6 +486,14 @@ extern "C" { SYSINIT_DRIVER_REFERENCE(micphy, miibus); #endif /* RTEMS_BSD_DRIVER_PHY_MIC */ +/* + * UK PHY (for unknown PHY devices) + */ +#if !defined(RTEMS_BSD_DRIVER_UKPHY) + #define RTEMS_BSD_DRIVER_UKPHY \ + SYSINIT_DRIVER_REFERENCE(ukphy, miibus); +#endif /* RTEMS_BSD_DRIVER_UKPHY */ + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/rtemsbsd/include/machine/rtems-bsd-program.h b/rtemsbsd/include/machine/rtems-bsd-program.h index f71ac9cd..96d4bfef 100644 --- a/rtemsbsd/include/machine/rtems-bsd-program.h +++ b/rtemsbsd/include/machine/rtems-bsd-program.h @@ -60,6 +60,12 @@ rtems_bsd_program_call_main_with_data_restore(const char *name, int (*main)(int, char **), int argc, char **argv, void *data_buf, const size_t data_size); +void * +rtems_bsd_program_add_destructor(void (*destructor)(void *), void *arg); + +void +rtems_bsd_program_remove_destructor(void *cookie, bool call); + void rtems_bsd_program_exit(int exit_code) __dead2; diff --git a/rtemsbsd/powerpc/include/machine/legacyvar.h b/rtemsbsd/powerpc/include/machine/legacyvar.h new file mode 100644 index 00000000..8683a0e5 --- /dev/null +++ b/rtemsbsd/powerpc/include/machine/legacyvar.h @@ -0,0 +1,2 @@ +/* See freebsd/sys/x86/include/machine/legacyvar.h */ +#include <x86/include/machine/legacyvar.h> diff --git a/rtemsbsd/powerpc/include/machine/pci_cfgreg.h b/rtemsbsd/powerpc/include/machine/pci_cfgreg.h new file mode 100644 index 00000000..1bfa468e --- /dev/null +++ b/rtemsbsd/powerpc/include/machine/pci_cfgreg.h @@ -0,0 +1,2 @@ +/* See freebsd/sys/x86/include/machine/pci_cfgreg.h */ +#include <x86/include/machine/pci_cfgreg.h> diff --git a/rtemsbsd/rtems/program-internal.h b/rtemsbsd/rtems/program-internal.h index da817130..2104c064 100644 --- a/rtemsbsd/rtems/program-internal.h +++ b/rtemsbsd/rtems/program-internal.h @@ -60,6 +60,12 @@ struct program_allocmem_item { LIST_ENTRY(program_allocmem_item) entries; }; +struct program_destructor { + void (*destructor)(void *); + void *arg; + LIST_ENTRY(program_destructor) link; +}; + struct rtems_bsd_program_control { void *context; int exit_code; @@ -68,6 +74,7 @@ struct rtems_bsd_program_control { LIST_HEAD(, program_fd_item) open_fd; LIST_HEAD(, program_file_item) open_file; LIST_HEAD(, program_allocmem_item) allocated_mem; + LIST_HEAD(, program_destructor) destructors; }; struct rtems_bsd_program_control *rtems_bsd_program_get_control_or_null(void); diff --git a/rtemsbsd/rtems/rtems-program.c b/rtemsbsd/rtems/rtems-program.c index 204ed248..1ca8e3b9 100644 --- a/rtemsbsd/rtems/rtems-program.c +++ b/rtemsbsd/rtems/rtems-program.c @@ -224,6 +224,18 @@ allocmem_free_all(struct rtems_bsd_program_control *prog_ctrl) } } +static void +call_destructors(struct rtems_bsd_program_control *prog_ctrl) +{ + struct program_destructor *node; + struct program_destructor *tmp; + + LIST_FOREACH_SAFE(node, &prog_ctrl->destructors, link, tmp) { + (*node->destructor)(node->arg); + free(node); + } +} + int rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context) { @@ -251,6 +263,7 @@ rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context) LIST_INIT(&prog_ctrl->open_fd); LIST_INIT(&prog_ctrl->open_file); LIST_INIT(&prog_ctrl->allocated_mem); + LIST_INIT(&prog_ctrl->destructors); if (setjmp(prog_ctrl->return_context) == 0) { exit_code = (*prog)(context); @@ -262,10 +275,48 @@ rtems_bsd_program_call(const char *name, int (*prog)(void *), void *context) fd_close_all(prog_ctrl); file_close_all(prog_ctrl); allocmem_free_all(prog_ctrl); + call_destructors(prog_ctrl); free(prog_ctrl); return (exit_code); } +void * +rtems_bsd_program_add_destructor(void (*destructor)(void *), void *arg) +{ + struct rtems_bsd_program_control *prog_ctrl; + struct program_destructor *node; + + prog_ctrl = rtems_bsd_program_get_control_or_null(); + if (prog_ctrl == NULL) { + return (NULL); + } + + node = malloc(sizeof(*node)); + if (node == NULL) { + return (NULL); + } + + node->destructor = destructor; + node->arg = arg; + LIST_INSERT_HEAD(&prog_ctrl->destructors, node, link); + return (node); +} + +void +rtems_bsd_program_remove_destructor(void *cookie, bool call) +{ + struct program_destructor *node; + + node = cookie; + LIST_REMOVE(node, link); + + if (call) { + (*node->destructor)(node->arg); + } + + free(node); +} + void rtems_bsd_program_exit(int exit_code) { diff --git a/rtemsbsd/sys/dev/atsam/if_atsam.c b/rtemsbsd/sys/dev/atsam/if_atsam.c index ff8219f4..21a28fcd 100644 --- a/rtemsbsd/sys/dev/atsam/if_atsam.c +++ b/rtemsbsd/sys/dev/atsam/if_atsam.c @@ -42,6 +42,7 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/mbuf.h> +#include <sys/sbuf.h> #include <sys/socket.h> #include <sys/sockio.h> #include <sys/kernel.h> @@ -49,7 +50,9 @@ #include <sys/bus.h> #include <sys/sysctl.h> +#include <net/bpf.h> #include <net/if.h> +#include <net/if_dl.h> #include <net/if_var.h> #include <net/if_types.h> #include <net/if_media.h> @@ -66,6 +69,7 @@ #include <rtems/bsd/local/miibus_if.h> #include <rtems/bsd/if_atsam.h> +#include <rtems/bsd/bsd.h> /* * Number of interfaces supported by the driver @@ -90,46 +94,40 @@ /** The runtime pin configure list for GMAC */ #define BOARD_GMAC_RUN_PINS BOARD_GMAC_PINS -/** Multicast Enable */ -#define GMAC_MC_ENABLE (1u << 6) -#define HASH_INDEX_AMOUNT 6 -#define HASH_ELEMENTS_PER_INDEX 8 -#define MAC_ADDR_MASK 0x0000FFFFFFFFFFFF -#define MAC_IDX_MASK (1u << 0) - -/** Promiscuous Mode Enable */ -#define GMAC_PROM_ENABLE (1u << 4) - /** RX Defines */ #define GMAC_RX_BUFFER_SIZE 1536 #define GMAC_RX_BUF_DESC_ADDR_MASK 0xFFFFFFFC -#define GMAC_RX_SET_OFFSET (1u << 15) -#define GMAC_RX_SET_USED_WRAP ((1u << 1) | (1u << 0)) -#define GMAC_RX_SET_WRAP (1u << 1) -#define GMAC_RX_SET_USED (1u << 0) -/** TX Defines */ -#define GMAC_TX_SET_EOF (1u << 15) -#define GMAC_TX_SET_WRAP (1u << 30) -#define GMAC_TX_SET_USED (1u << 31) #define GMAC_DESCRIPTOR_ALIGNMENT 8 /** Events */ #define ATSAMV7_ETH_RX_EVENT_INTERRUPT RTEMS_EVENT_1 -#define ATSAMV7_ETH_TX_EVENT_INTERRUPT RTEMS_EVENT_2 -#define ATSAMV7_ETH_START_TRANSMIT_EVENT RTEMS_EVENT_3 - -#define ATSAMV7_ETH_RX_DATA_OFFSET 2 - -#define WATCHDOG_TIMEOUT 5 /* FIXME: Make these configurable */ #define MDIO_RETRIES 10 #define MDIO_PHY MII_PHY_ANY -#define RXBUF_COUNT 8 -#define TXBUF_COUNT 64 #define IGNORE_RX_ERR false +#define RX_INTERRUPTS (GMAC_ISR_RCOMP | GMAC_ISR_RXUBR | GMAC_ISR_ROVR) + +#define RX_DESC_LOG2 3 +#define RX_DESC_COUNT (1U << RX_DESC_LOG2) +#define RX_DESC_WRAP(idx) \ + ((((idx) + 1) & RX_DESC_COUNT) >> (RX_DESC_LOG2 - 1)) +RTEMS_STATIC_ASSERT(RX_DESC_WRAP(RX_DESC_COUNT - 1) == + GMAC_RX_WRAP_BIT, rx_desc_wrap); +RTEMS_STATIC_ASSERT(RX_DESC_WRAP(RX_DESC_COUNT - 2) == + 0, rx_desc_no_wrap); + +#define TX_DESC_LOG2 6 +#define TX_DESC_COUNT (1U << TX_DESC_LOG2) +#define TX_DESC_WRAP(idx) \ + ((((idx) + 1) & TX_DESC_COUNT) << (30 - TX_DESC_LOG2)) +RTEMS_STATIC_ASSERT(TX_DESC_WRAP(TX_DESC_COUNT - 1) == + GMAC_TX_WRAP_BIT, tx_desc_wrap); +RTEMS_STATIC_ASSERT(TX_DESC_WRAP(TX_DESC_COUNT - 2) == + 0, tx_desc_no_wrap); + /** The PINs for GMAC */ static const Pin gmacPins[] = { BOARD_GMAC_RUN_PINS }; @@ -139,11 +137,13 @@ typedef struct if_atsam_gmac { uint32_t retries; } if_atsam_gmac; -typedef struct ring_buffer { - unsigned tx_bd_used; - unsigned tx_bd_free; - size_t length; -} ring_buffer; +struct if_atsam_tx_bds { + volatile sGmacTxDescriptor bds[TX_DESC_COUNT]; +}; + +struct if_atsam_rx_bds { + volatile sGmacRxDescriptor bds[RX_DESC_COUNT]; +}; /* * Per-device data @@ -156,17 +156,16 @@ typedef struct if_atsam_softc { struct ifnet *ifp; struct mtx mtx; if_atsam_gmac Gmac_inst; + size_t tx_idx_head; + size_t tx_idx_tail; + struct if_atsam_tx_bds *tx; + struct mbuf *tx_mbufs[TX_DESC_COUNT]; + size_t rx_idx_head; + struct if_atsam_rx_bds *rx; + struct mbuf *rx_mbufs[RX_DESC_COUNT]; uint8_t GMacAddress[6]; rtems_id rx_daemon_tid; - rtems_id tx_daemon_tid; rtems_vector_number interrupt_number; - struct mbuf **rx_mbuf; - struct mbuf **tx_mbuf; - volatile sGmacTxDescriptor *tx_bd_base; - size_t rx_bd_fill_idx; - size_t amount_rx_buf; - size_t amount_tx_buf; - ring_buffer tx_ring; struct callout tick_ch; /* @@ -190,13 +189,12 @@ typedef struct if_atsam_softc { struct if_atsam_stats { /* Software */ uint32_t rx_overrun_errors; + uint32_t rx_used_bit_reads; uint32_t rx_interrupts; - uint32_t tx_complete_int; uint32_t tx_tur_errors; uint32_t tx_rlex_errors; uint32_t tx_tfc_errors; uint32_t tx_hresp_errors; - uint32_t tx_interrupts; /* Hardware */ uint64_t octets_transm; @@ -243,6 +241,8 @@ typedef struct if_atsam_softc { uint32_t tcp_checksum_errors; uint32_t udp_checksum_errors; } stats; + + int if_flags; } if_atsam_softc; static void if_atsam_poll_hw_stats(struct if_atsam_softc *sc); @@ -251,27 +251,6 @@ static void if_atsam_poll_hw_stats(struct if_atsam_softc *sc); #define IF_ATSAM_UNLOCK(sc) mtx_unlock(&(sc)->mtx) -static void if_atsam_event_send(rtems_id task, rtems_event_set event) -{ - rtems_event_send(task, event); -} - - -static void if_atsam_event_receive(if_atsam_softc *sc, rtems_event_set in) -{ - rtems_event_set out; - - IF_ATSAM_UNLOCK(sc); - rtems_event_receive( - in, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &out - ); - IF_ATSAM_LOCK(sc); -} - - static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp) { struct mbuf *m; @@ -356,11 +335,10 @@ if_atsam_miibus_readreg(device_t dev, int phy, int reg) static int if_atsam_miibus_writereg(device_t dev, int phy, int reg, int data) { - uint8_t err; if_atsam_softc *sc = device_get_softc(dev); IF_ATSAM_LOCK(sc); - err = if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw, + (void)if_atsam_write_phy(sc->Gmac_inst.gGmacd.pHw, (uint8_t)phy, (uint8_t)reg, data, sc->Gmac_inst.retries); IF_ATSAM_UNLOCK(sc); @@ -403,63 +381,53 @@ if_atsam_init_phy(if_atsam_gmac *gmac_inst, uint32_t mck, static void if_atsam_interrupt_handler(void *arg) { if_atsam_softc *sc = (if_atsam_softc *)arg; - uint32_t irq_status_val; - rtems_event_set rx_event = 0; - rtems_event_set tx_event = 0; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + uint32_t is; /* Get interrupt status */ - irq_status_val = GMAC_GetItStatus(pHw, 0); + is = pHw->GMAC_ISR; - /* Check receive interrupts */ - if ((irq_status_val & GMAC_IER_ROVR) != 0) { - ++sc->stats.rx_overrun_errors; - rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_RCOMP) != 0) { - rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT; + if (__predict_false((is & GMAC_TX_ERR_BIT) != 0)) { + if ((is & GMAC_IER_TUR) != 0) { + ++sc->stats.tx_tur_errors; + } + if ((is & GMAC_IER_RLEX) != 0) { + ++sc->stats.tx_rlex_errors; + } + if ((is & GMAC_IER_TFC) != 0) { + ++sc->stats.tx_tfc_errors; + } + if ((is & GMAC_IER_HRESP) != 0) { + ++sc->stats.tx_hresp_errors; + } } - /* Send events to receive task and switch off rx interrupts */ - if (rx_event != 0) { + + /* Check receive interrupts */ + if (__predict_true((is & RX_INTERRUPTS) != 0)) { + if (__predict_false((is & GMAC_ISR_RXUBR) != 0)) { + ++sc->stats.rx_used_bit_reads; + } + + if (__predict_false((is & GMAC_ISR_ROVR) != 0)) { + ++sc->stats.rx_overrun_errors; + } + ++sc->stats.rx_interrupts; - /* Erase the interrupts for RX completion and errors */ - GMAC_DisableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); - (void)if_atsam_event_send(sc->rx_daemon_tid, rx_event); - } - if ((irq_status_val & GMAC_IER_TUR) != 0) { - ++sc->stats.tx_tur_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_RLEX) != 0) { - ++sc->stats.tx_rlex_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_TFC) != 0) { - ++sc->stats.tx_tfc_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_HRESP) != 0) { - ++sc->stats.tx_hresp_errors; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - if ((irq_status_val & GMAC_IER_TCOMP) != 0) { - ++sc->stats.tx_complete_int; - tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT; - } - /* Send events to transmit task and switch off tx interrupts */ - if (tx_event != 0) { - ++sc->stats.tx_interrupts; - /* Erase the interrupts for TX completion and errors */ - GMAC_DisableIt(pHw, GMAC_INT_TX_BITS, 0); - (void)if_atsam_event_send(sc->tx_daemon_tid, tx_event); + + /* Disable RX interrupts */ + pHw->GMAC_IDR = RX_INTERRUPTS; + + (void)rtems_event_send(sc->rx_daemon_tid, + ATSAMV7_ETH_RX_EVENT_INTERRUPT); } } -static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc) +static void +if_atsam_rx_update_mbuf(struct mbuf *m, uint32_t status) { int frame_len; - frame_len = (int) (buffer_desc->status.bm.len); + frame_len = (int)(status & GMAC_LENGTH_FRAME); m->m_data = mtod(m, char*)+ETHER_ALIGN; m->m_len = frame_len; @@ -467,7 +435,7 @@ static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc) /* check checksum offload result */ m->m_pkthdr.csum_flags = 0; - switch (buffer_desc->status.bm.typeIDMatchOrCksumResult) { + switch ((status >> 22) & 0x3) { case GMAC_RXDESC_ST_CKSUM_RESULT_IP_CHECKED: m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID; m->m_pkthdr.csum_data = 0xffff; @@ -481,21 +449,17 @@ static void rx_update_mbuf(struct mbuf *m, sGmacRxDescriptor *buffer_desc) } } -/* - * Receive daemon - */ -static void if_atsam_rx_daemon(void *arg) +static void +if_atsam_rx_daemon(rtems_task_argument arg) { if_atsam_softc *sc = (if_atsam_softc *)arg; struct ifnet *ifp = sc->ifp; - rtems_event_set events = 0; - void *rx_bd_base; - struct mbuf *m; - struct mbuf *n; - volatile sGmacRxDescriptor *buffer_desc; - uint32_t tmp_rx_bd_address; - size_t i; + volatile sGmacRxDescriptor *base; + struct if_atsam_rx_bds *rx; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + size_t idx; + struct mbuf **mbufs; + struct mbuf *m; IF_ATSAM_LOCK(sc); @@ -506,47 +470,37 @@ static void if_atsam_rx_daemon(void *arg) } /* Allocate memory space for priority queue descriptor list */ - rx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacRxDescriptor), + base = rtems_cache_coherent_allocate(sizeof(*base), GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(rx_bd_base != NULL); + assert(base != NULL); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; - buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP; - buffer_desc->status.val = 0; + base->addr.val = GMAC_RX_OWNERSHIP_BIT | GMAC_RX_WRAP_BIT; + base->status.val = 0; - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1); - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2); + GMAC_SetRxQueue(pHw, (uint32_t)base, 1); + GMAC_SetRxQueue(pHw, (uint32_t)base, 2); /* Allocate memory space for buffer descriptor list */ - rx_bd_base = rtems_cache_coherent_allocate( - sc->amount_rx_buf * sizeof(sGmacRxDescriptor), + rx = rtems_cache_coherent_allocate(sizeof(*rx), GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(rx_bd_base != NULL); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; + assert(rx != NULL); + sc->rx = rx; + mbufs = &sc->rx_mbufs[0]; /* Create descriptor list and mark as empty */ - for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf; - ++sc->rx_bd_fill_idx) { + for (idx = 0; idx < RX_DESC_COUNT; ++idx) { m = if_atsam_new_mbuf(ifp); assert(m != NULL); - sc->rx_mbuf[sc->rx_bd_fill_idx] = m; - buffer_desc->addr.val = ((uint32_t)m->m_data) & - GMAC_RX_BUF_DESC_ADDR_MASK; - buffer_desc->status.val = 0; - if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) { - buffer_desc->addr.bm.bWrap = 1; - } else { - buffer_desc++; - } + mbufs[idx] = m; + rx->bds[idx].addr.val = mtod(m, uint32_t) | RX_DESC_WRAP(idx); } - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; /* Set 2 Byte Receive Buffer Offset */ - pHw->GMAC_NCFGR |= GMAC_RX_SET_OFFSET; + pHw->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(2); /* Write Buffer Queue Base Address Register */ GMAC_ReceiveEnable(pHw, 0); - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0); + GMAC_SetRxQueue(pHw, (uint32_t)&rx->bds[0], 0); /* Set address for address matching */ GMAC_SetAddress(pHw, 0, sc->GMacAddress); @@ -554,306 +508,230 @@ static void if_atsam_rx_daemon(void *arg) /* Enable Receiving of data */ GMAC_ReceiveEnable(pHw, 1); - /* Setup the interrupts for RX completion and errors */ - GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); + IF_ATSAM_UNLOCK(sc); - sc->rx_bd_fill_idx = 0; + idx = 0; while (true) { - /* Wait for events */ - if_atsam_event_receive(sc, ATSAMV7_ETH_RX_EVENT_INTERRUPT); + rtems_event_set out; - /* - * Check for all packets with a set ownership bit - */ - while (buffer_desc->addr.bm.bOwnership == 1) { - if (buffer_desc->status.bm.bEof == 1) { - m = sc->rx_mbuf[sc->rx_bd_fill_idx]; + sc->rx_idx_head = idx; - /* New mbuf for desc */ - n = if_atsam_new_mbuf(ifp); - if (n != NULL) { - rx_update_mbuf(m, buffer_desc); + /* Enable RX interrupts */ + pHw->GMAC_IER = RX_INTERRUPTS; - IF_ATSAM_UNLOCK(sc); - sc->ifp->if_input(ifp, m); - IF_ATSAM_LOCK(sc); - m = n; - } else { - (void)if_atsam_event_send( - sc->tx_daemon_tid, ATSAMV7_ETH_START_TRANSMIT_EVENT); - } - sc->rx_mbuf[sc->rx_bd_fill_idx] = m; - tmp_rx_bd_address = (uint32_t)m->m_data & - GMAC_RX_BUF_DESC_ADDR_MASK; - - /* Switch pointer to next buffer descriptor */ - if (sc->rx_bd_fill_idx == - (sc->amount_rx_buf - 1)) { - tmp_rx_bd_address |= GMAC_RX_SET_WRAP; - sc->rx_bd_fill_idx = 0; - } else { - ++sc->rx_bd_fill_idx; - } + (void) rtems_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT, + RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &out); - /* - * Give ownership to GMAC for further processing - */ - tmp_rx_bd_address &= ~GMAC_RX_SET_USED; - _ARM_Data_synchronization_barrier(); - buffer_desc->addr.val = tmp_rx_bd_address; + while (true) { + uint32_t addr; + uint32_t status; - buffer_desc = (sGmacRxDescriptor *)rx_bd_base - + sc->rx_bd_fill_idx; + addr = rx->bds[idx].addr.val; + if ((addr & GMAC_RX_OWNERSHIP_BIT) == 0) { + break; } - } - /* Setup the interrupts for RX completion and errors */ - GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); - } -} -/* - * Update of current transmit buffer position. - */ -static void if_atsam_tx_bd_pos_update(size_t *pos, size_t amount_tx_buf) -{ - *pos = (*pos + 1) % amount_tx_buf; -} + status = rx->bds[idx].status.val; + m = mbufs[idx]; -/* - * Is RingBuffer empty - */ -static bool if_atsam_ring_buffer_empty(ring_buffer *ring_buffer) -{ - return (ring_buffer->tx_bd_used == ring_buffer->tx_bd_free); -} + if (__predict_true((status & GMAC_RX_EOF_BIT) != 0)) { + struct mbuf *n; -/* - * Is RingBuffer full - */ -static bool if_atsam_ring_buffer_full(ring_buffer *ring_buffer) -{ - size_t tx_bd_used_next = ring_buffer->tx_bd_used; + n = if_atsam_new_mbuf(ifp); + if (n != NULL) { + if_atsam_rx_update_mbuf(m, status); + (*ifp->if_input)(ifp, m); + m = n; + } + } else { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + } - if_atsam_tx_bd_pos_update(&tx_bd_used_next, ring_buffer->length); - return (tx_bd_used_next == ring_buffer->tx_bd_free); -} + mbufs[idx] = m; + rx->bds[idx].addr.val = mtod(m, uint32_t) | + RX_DESC_WRAP(idx); -/* - * Cleanup transmit file descriptors by freeing mbufs which are not needed any - * longer due to correct transmission. - */ -static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc) -{ - struct mbuf *m; - volatile sGmacTxDescriptor *cur; - bool eof_needed = false; - - while (!if_atsam_ring_buffer_empty(&sc->tx_ring)){ - cur = sc->tx_bd_base + sc->tx_ring.tx_bd_free; - if (((cur->status.bm.bUsed == 1) && !eof_needed) || eof_needed) { - eof_needed = true; - cur->status.val |= GMAC_TX_SET_USED; - m = sc->tx_mbuf[sc->tx_ring.tx_bd_free]; - m_free(m); - sc->tx_mbuf[sc->tx_ring.tx_bd_free] = 0; - if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_free, - sc->tx_ring.length); - if (cur->status.bm.bLastBuffer) { - eof_needed = false; - } - } else { - break; + idx = (idx + 1) % RX_DESC_COUNT; } } } -/* - * Prepare Ethernet frame to start transmission. - */ -static bool if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m) +static void +if_atsam_tx_reclaim(struct if_atsam_softc *sc, struct ifnet *ifp) { - volatile sGmacTxDescriptor *cur; - volatile sGmacTxDescriptor *start_packet_tx_bd = 0; - int pos = 0; - uint32_t tmp_val = 0; - Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; - bool success; - int csum_flags = m->m_pkthdr.csum_flags; + uint32_t head_idx; + uint32_t tail_idx; + volatile sGmacTxDescriptor *base; - if_atsam_tx_bd_cleanup(sc); - /* Wait for interrupt in case no buffer descriptors are available */ - /* Wait for events */ - while (true) { - if (if_atsam_ring_buffer_full(&sc->tx_ring)) { - /* Setup the interrupts for TX completion and errors */ - GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0); - success = false; + head_idx = sc->tx_idx_head; + tail_idx = sc->tx_idx_tail; + base = &sc->tx->bds[0]; + + while (head_idx != tail_idx) { + uint32_t status; + ift_counter cnt; + struct mbuf *m; + + status = base[tail_idx].status.val; + + if ((status & GMAC_TX_USED_BIT) == 0) { break; } - /* - * Get current mbuf for data fill - */ - cur = &sc->tx_bd_base[sc->tx_ring.tx_bd_used]; - /* Set the transfer data */ - if (m->m_len) { - uintptr_t cache_adjustment = mtod(m, uintptr_t) % 32; - - rtems_cache_flush_multiple_data_lines( - mtod(m, const char *) - cache_adjustment, - (size_t)(m->m_len + cache_adjustment)); - - cur->addr = mtod(m, uint32_t); - tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED; - if (sc->tx_ring.tx_bd_used == (sc->tx_ring.length - 1)) { - tmp_val |= GMAC_TX_SET_WRAP; - } - if (pos == 0) { - start_packet_tx_bd = cur; - } - sc->tx_mbuf[sc->tx_ring.tx_bd_used] = m; - m = m->m_next; - if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_used, - sc->tx_ring.length); + if (__predict_true((status & GMAC_TX_ERR_BITS) == 0)) { + cnt = IFCOUNTER_OPACKETS; } else { - /* Discard empty mbufs */ - m = m_free(m); + cnt = IFCOUNTER_OERRORS; } - /* - * Send out the buffer once the complete mbuf_chain has been - * processed - */ - if (m == NULL) { - tmp_val |= GMAC_TX_SET_EOF; - tmp_val &= ~GMAC_TX_SET_USED; - if ((csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | - CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) != 0) { - start_packet_tx_bd->status.bm.bNoCRC = 0; - } else { - start_packet_tx_bd->status.bm.bNoCRC = 1; - } - _ARM_Data_synchronization_barrier(); - cur->status.val = tmp_val; - start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED; - _ARM_Data_synchronization_barrier(); - GMAC_TransmissionStart(pHw); - success = true; - break; - } else { - if (pos > 0) { - tmp_val &= ~GMAC_TX_SET_USED; + while ((m = sc->tx_mbufs[tail_idx]) == NULL ) { + base[tail_idx].status.val = status | GMAC_TX_USED_BIT; + tail_idx = (tail_idx + 1) % TX_DESC_COUNT; + status = base[tail_idx].status.val; + + if (__predict_false((status & GMAC_TX_ERR_BITS) != 0)) { + cnt = IFCOUNTER_OERRORS; } - pos++; - cur->status.val = tmp_val; } + + base[tail_idx].status.val = status | GMAC_TX_USED_BIT; + if_inc_counter(ifp, cnt, 1); + sc->tx_mbufs[tail_idx] = NULL; + m_freem(m); + + tail_idx = (tail_idx + 1) % TX_DESC_COUNT; } - return success; -} + sc->tx_idx_tail = tail_idx; +} -/* - * Transmit daemon - */ -static void if_atsam_tx_daemon(void *arg) +static void +if_atsam_cache_flush(uintptr_t begin, uintptr_t size) { - if_atsam_softc *sc = (if_atsam_softc *)arg; - rtems_event_set events = 0; - sGmacTxDescriptor *buffer_desc; - int bd_number; - void *tx_bd_base; - struct mbuf *m; - bool success; + uintptr_t end; + uintptr_t mask; + + /* Align begin and end of the data to a cache line */ + end = begin + size; + mask = CPU_CACHE_LINE_BYTES - 1; + begin &= ~mask; + end = (end + mask) & ~mask; + rtems_cache_flush_multiple_data_lines((void *)begin, end - begin); +} - IF_ATSAM_LOCK(sc); +static int +if_atsam_tx_enqueue(struct if_atsam_softc *sc, struct ifnet *ifp, struct mbuf *m) +{ + size_t head_idx; + size_t tail_idx; + size_t capacity; + size_t idx; + volatile sGmacTxDescriptor *base; + volatile sGmacTxDescriptor *desc; + size_t bufs; + uint32_t status; + struct mbuf *n; - Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; - struct ifnet *ifp = sc->ifp; + head_idx = sc->tx_idx_head; + tail_idx = sc->tx_idx_tail; + capacity = (tail_idx - head_idx - 1) % TX_DESC_COUNT; - GMAC_TransmitEnable(pHw, 0); + idx = head_idx; + base = &sc->tx->bds[0]; + bufs = 0; + n = m; - /* Allocate memory space for priority queue descriptor list */ - tx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacTxDescriptor), - GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(tx_bd_base != NULL); + do { + uint32_t size; - buffer_desc = (sGmacTxDescriptor *)tx_bd_base; - buffer_desc->addr = 0; - buffer_desc->status.val = GMAC_TX_SET_USED | GMAC_TX_SET_WRAP; + desc = &base[idx]; - GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 1); - GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 2); + size = (uint32_t)n->m_len; + if (__predict_true(size > 0)) { + uintptr_t begin; - /* Allocate memory space for buffer descriptor list */ - tx_bd_base = rtems_cache_coherent_allocate( - sc->amount_tx_buf * sizeof(sGmacTxDescriptor), - GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(tx_bd_base != NULL); - buffer_desc = (sGmacTxDescriptor *)tx_bd_base; + ++bufs; + if (__predict_false(bufs > capacity)) { + return (ENOBUFS); + } - /* Create descriptor list and mark as empty */ - for (bd_number = 0; bd_number < sc->amount_tx_buf; bd_number++) { - buffer_desc->addr = 0; - buffer_desc->status.val = GMAC_TX_SET_USED; - if (bd_number == (sc->amount_tx_buf - 1)) { - buffer_desc->status.bm.bWrap = 1; - } else { - buffer_desc++; + begin = mtod(n, uintptr_t); + desc->addr = (uint32_t)begin; + status = GMAC_TX_USED_BIT | TX_DESC_WRAP(idx) | size; + desc->status.val = status; + if_atsam_cache_flush(begin, size); + idx = (idx + 1) % TX_DESC_COUNT; } + + n = n->m_next; + } while (n != NULL); + + sc->tx_idx_head = idx; + + idx = (idx - 1) % TX_DESC_COUNT; + desc = &base[idx]; + sc->tx_mbufs[idx] = m; + status = GMAC_TX_LAST_BUFFER_BIT; + + while (idx != head_idx) { + desc->status.val = (desc->status.val & ~GMAC_TX_USED_BIT) | + status; + status = 0; + + idx = (idx - 1) % TX_DESC_COUNT; + desc = &base[idx]; } - buffer_desc = (sGmacTxDescriptor *)tx_bd_base; - /* Write Buffer Queue Base Address Register */ - GMAC_SetTxQueue(pHw, (uint32_t)buffer_desc, 0); + desc->status.val = (desc->status.val & ~GMAC_TX_USED_BIT) | status; + _ARM_Data_synchronization_barrier(); + sc->Gmac_inst.gGmacd.pHw->GMAC_NCR |= GMAC_NCR_TSTART; + ETHER_BPF_MTAP(ifp, m); + return (0); +} - /* Enable Transmission of data */ - GMAC_TransmitEnable(pHw, 1); +static int +if_atsam_transmit(struct ifnet *ifp, struct mbuf *m) +{ + struct if_atsam_softc *sc; + int error; - /* Set variables in context */ - sc->tx_bd_base = tx_bd_base; + if (__predict_false((m->m_flags & M_VLANTAG) != 0)) { + struct mbuf *n; - while (true) { - /* Wait for events */ - if_atsam_event_receive(sc, - ATSAMV7_ETH_START_TRANSMIT_EVENT | - ATSAMV7_ETH_TX_EVENT_INTERRUPT); - //printf("TX Transmit Event received\n"); - - /* - * Send packets till queue is empty - */ - while (true) { - /* - * Get the mbuf chain to transmit - */ - if_atsam_tx_bd_cleanup(sc); - IF_DEQUEUE(&ifp->if_snd, m); - if (!m) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - break; - } - success = if_atsam_send_packet(sc, m); - if (!success){ - break; - } + n = ether_vlanencap(m, m->m_pkthdr.ether_vtag); + if (n == NULL) { + m_freem(m); + return (ENOBUFS); } + + m = n; } -} + sc = ifp->if_softc; + IF_ATSAM_LOCK(sc); -/* - * Send packet (caller provides header). - */ -static void if_atsam_enet_start(struct ifnet *ifp) -{ - if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc; + error = if_atsam_tx_enqueue(sc, ifp, m); + if_atsam_tx_reclaim(sc, ifp); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - if_atsam_event_send(sc->tx_daemon_tid, - ATSAMV7_ETH_START_TRANSMIT_EVENT); -} + if (__predict_false(error != 0)) { + struct mbuf *n; + n = m_defrag(m, M_NOWAIT); + if (n != NULL) { + m = n; + } + + error = if_atsam_tx_enqueue(sc, ifp, m); + if (error != 0) { + m_freem(m); + if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); + } + } + + IF_ATSAM_UNLOCK(sc); + return (error); +} static uint8_t if_atsam_get_gmac_linkspeed_from_media(uint32_t media_subtype) { @@ -975,23 +853,55 @@ if_atsam_tick(void *context) callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc); } +static void +if_atsam_setup_tx(struct if_atsam_softc *sc) +{ + sGmacTxDescriptor *base; + struct if_atsam_tx_bds *tx; + size_t i; + Gmac *pHw; -/* - * Sets up the hardware and chooses the interface to be used - */ -static void if_atsam_init(void *arg) + pHw = sc->Gmac_inst.gGmacd.pHw; + GMAC_TransmitEnable(pHw, 0); + + /* Allocate memory space for priority queue descriptor list */ + base = rtems_cache_coherent_allocate(sizeof(base), + GMAC_DESCRIPTOR_ALIGNMENT, 0); + assert(base != NULL); + + base->addr = 0; + base->status.val = GMAC_TX_USED_BIT | GMAC_TX_WRAP_BIT; + + GMAC_SetTxQueue(pHw, (uint32_t)base, 1); + GMAC_SetTxQueue(pHw, (uint32_t)base, 2); + + /* Allocate memory space for buffer descriptor list */ + tx = rtems_cache_coherent_allocate(sizeof(*sc->tx), + GMAC_DESCRIPTOR_ALIGNMENT, 0); + assert(tx != NULL); + + /* Set variables in context */ + sc->tx = tx; + + /* Create descriptor list and mark as empty */ + for (i = 0; i < TX_DESC_COUNT; ++i) { + tx->bds[i].addr = 0; + tx->bds[i].status.val = GMAC_TX_USED_BIT | TX_DESC_WRAP(i); + } + + /* Write Buffer Queue Base Address Register */ + GMAC_SetTxQueue(pHw, (uint32_t)&tx->bds[0], 0); + + /* Enable Transmission of data */ + GMAC_TransmitEnable(pHw, 1); +} + +static void +if_atsam_init(if_atsam_softc *sc) { rtems_status_code status; - - if_atsam_softc *sc = (if_atsam_softc *)arg; - struct ifnet *ifp = sc->ifp; uint32_t dmac_cfg = 0; - uint32_t gmii_val = 0; - if (ifp->if_flags & IFF_DRV_RUNNING) { - return; - } - ifp->if_flags |= IFF_DRV_RUNNING; sc->interrupt_number = GMAC_IRQn; /* Enable Peripheral Clock */ @@ -1000,7 +910,6 @@ static void if_atsam_init(void *arg) } /* Setup interrupts */ NVIC_ClearPendingIRQ(GMAC_IRQn); - NVIC_EnableIRQ(GMAC_IRQn); /* Configuration of DMAC */ dmac_cfg = (GMAC_DCFGR_DRBS(GMAC_RX_BUFFER_SIZE >> 6)) | @@ -1011,20 +920,17 @@ static void if_atsam_init(void *arg) /* Enable hardware checksum offload for receive */ sc->Gmac_inst.gGmacd.pHw->GMAC_NCFGR |= GMAC_NCFGR_RXCOEN; + /* Use Multicast Hash Filter */ + sc->Gmac_inst.gGmacd.pHw->GMAC_NCFGR |= GMAC_NCFGR_MTIHEN; + sc->Gmac_inst.gGmacd.pHw->GMAC_HRB = 0; + sc->Gmac_inst.gGmacd.pHw->GMAC_HRT = 0; + /* Shut down Transmit and Receive */ GMAC_ReceiveEnable(sc->Gmac_inst.gGmacd.pHw, 0); GMAC_TransmitEnable(sc->Gmac_inst.gGmacd.pHw, 0); GMAC_StatisticsWriteEnable(sc->Gmac_inst.gGmacd.pHw, 1); - /* - * Allocate mbuf pointers - */ - sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf, - M_TEMP, M_NOWAIT); - sc->tx_mbuf = malloc(sc->amount_tx_buf * sizeof *sc->tx_mbuf, - M_TEMP, M_NOWAIT); - /* Install interrupt handler */ status = rtems_interrupt_handler_install(sc->interrupt_number, "Ethernet", @@ -1036,30 +942,143 @@ static void if_atsam_init(void *arg) /* * Start driver tasks */ - sc->rx_daemon_tid = rtems_bsdnet_newproc("SCrx", 4096, - if_atsam_rx_daemon, sc); - sc->tx_daemon_tid = rtems_bsdnet_newproc("SCtx", 4096, - if_atsam_tx_daemon, sc); + + status = rtems_task_create(rtems_build_name('S', 'C', 'r', 'x'), + rtems_bsd_get_task_priority(device_get_name(sc->dev)), 4096, + RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_MODES, &sc->rx_daemon_tid); + assert(status == RTEMS_SUCCESSFUL); + + status = rtems_task_start(sc->rx_daemon_tid, if_atsam_rx_daemon, + (rtems_task_argument)sc); + assert(status == RTEMS_SUCCESSFUL); callout_reset(&sc->tick_ch, hz, if_atsam_tick, sc); + if_atsam_setup_tx(sc); +} + +static int +if_atsam_get_hash_index(const uint8_t *eaddr) +{ + uint64_t eaddr64; + int index; + int i; + + eaddr64 = eaddr[5]; + + for (i = 4; i >= 0; --i) { + eaddr64 <<= 8; + eaddr64 |= eaddr[i]; + } + + index = 0; + + for (i = 0; i < 6; ++i) { + uint64_t bits; + int j; + int hash; + + bits = eaddr64 >> i; + hash = bits & 1; + + for (j = 1; j < 8; ++j) { + bits >>= 6; + hash ^= bits & 1; + } + + index |= hash << i; + } + + return index; +} + +static void +if_atsam_setup_rxfilter(struct if_atsam_softc *sc) +{ + struct ifnet *ifp; + struct ifmultiaddr *ifma; + uint64_t mhash; + Gmac *pHw; + + pHw = sc->Gmac_inst.gGmacd.pHw; + + if ((sc->ifp->if_flags & IFF_PROMISC) != 0) { + pHw->GMAC_NCFGR |= GMAC_NCFGR_CAF; + } else { + pHw->GMAC_NCFGR &= ~GMAC_NCFGR_CAF; + } + + ifp = sc->ifp; + + if ((ifp->if_flags & IFF_ALLMULTI)) + mhash = 0xffffffffffffffffLLU; + else { + mhash = 0; + if_maddr_rlock(ifp); + CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + mhash |= 1LLU << if_atsam_get_hash_index( + LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); + } + if_maddr_runlock(ifp); + } + + pHw->GMAC_HRB = (uint32_t)mhash; + pHw->GMAC_HRT = (uint32_t)(mhash >> 32); +} + +static void +if_atsam_start_locked(struct if_atsam_softc *sc) +{ + struct ifnet *ifp = sc->ifp; + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + return; + } + ifp->if_drv_flags |= IFF_DRV_RUNNING; + + if_atsam_setup_rxfilter(sc); + + /* Enable TX/RX */ + pHw->GMAC_NCR |= GMAC_NCR_RXEN | GMAC_NCR_TXEN; } +static void +if_atsam_start(void *arg) +{ + struct if_atsam_softc *sc = arg; -/* - * Stop the device - */ -static void if_atsam_stop(struct if_atsam_softc *sc) + IF_ATSAM_LOCK(sc); + if_atsam_start_locked(sc); + IF_ATSAM_UNLOCK(sc); +} + +static void +if_atsam_stop_locked(struct if_atsam_softc *sc) { struct ifnet *ifp = sc->ifp; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + size_t i; - ifp->if_flags &= ~IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - /* Disable MDIO interface and TX/RX */ + /* Disable TX/RX */ pHw->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN); - pHw->GMAC_NCR &= ~GMAC_NCR_MPE; + + /* Reinitialize the TX descriptors */ + + sc->tx_idx_head = 0; + sc->tx_idx_tail = 0; + + for (i = 0; i < TX_DESC_COUNT; ++i) { + sc->tx->bds[i].addr = 0; + sc->tx->bds[i].status.val = GMAC_TX_USED_BIT | TX_DESC_WRAP(i); + m_freem(sc->tx_mbufs[i]); + sc->tx_mbufs[i] = NULL; + } } @@ -1070,7 +1089,7 @@ if_atsam_poll_hw_stats(struct if_atsam_softc *sc) Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; octets = pHw->GMAC_OTLO; - octets |= pHw->GMAC_OTHI << 32; + octets |= (uint64_t)pHw->GMAC_OTHI << 32; sc->stats.octets_transm += octets; sc->stats.frames_transm += pHw->GMAC_FT; sc->stats.broadcast_frames_transm += pHw->GMAC_BCFT; @@ -1092,7 +1111,7 @@ if_atsam_poll_hw_stats(struct if_atsam_softc *sc) sc->stats.carrier_sense_errors += pHw->GMAC_CSE; octets = pHw->GMAC_ORLO; - octets |= pHw->GMAC_ORHI << 32; + octets |= (uint64_t)pHw->GMAC_ORHI << 32; sc->stats.octets_rec += octets; sc->stats.frames_rec += pHw->GMAC_FR; sc->stats.broadcast_frames_rec += pHw->GMAC_BCFR; @@ -1120,24 +1139,159 @@ if_atsam_poll_hw_stats(struct if_atsam_softc *sc) sc->stats.udp_checksum_errors += pHw->GMAC_UCE; } +static int +if_atsam_stats_reset(SYSCTL_HANDLER_ARGS) +{ + struct if_atsam_softc *sc = arg1; + int value; + int error; + + value = 0; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error != 0 || req->newptr == NULL) { + return (error); + } + + if (value != 0) { + IF_ATSAM_LOCK(sc); + if_atsam_poll_hw_stats(sc); + memset(&sc->stats, 0, sizeof(sc->stats)); + IF_ATSAM_UNLOCK(sc); + } + + return (0); +} + +static int +if_atsam_sysctl_reg(SYSCTL_HANDLER_ARGS) +{ + u_int value; + + value = *(uint32_t *)arg1; + return (sysctl_handle_int(oidp, &value, 0, req)); +} + +static int +if_atsam_sysctl_tx_desc(SYSCTL_HANDLER_ARGS) +{ + struct if_atsam_softc *sc = arg1; + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + struct sbuf *sb; + int error; + size_t i; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) { + return (error); + } + + sb = sbuf_new_for_sysctl(NULL, NULL, 1024, req); + if (sb == NULL) { + return (ENOMEM); + } + + sbuf_printf(sb, "\n\tHead %u\n", sc->tx_idx_head); + sbuf_printf(sb, "\tTail %u\n", sc->tx_idx_tail); + sbuf_printf(sb, "\tDMA %u\n", + (pHw->GMAC_TBQB - (uintptr_t)&sc->tx->bds[0]) / 8); + + for (i = 0; i < TX_DESC_COUNT; ++i) { + sbuf_printf(sb, "\t[%2u] %08x %08x\n", i, + sc->tx->bds[i].status.val, sc->tx->bds[i].addr); + } + + error = sbuf_finish(sb); + sbuf_delete(sb); + return (error); +} + +static int +if_atsam_sysctl_rx_desc(SYSCTL_HANDLER_ARGS) +{ + struct if_atsam_softc *sc = arg1; + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + struct sbuf *sb; + int error; + size_t i; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) { + return (error); + } + + sb = sbuf_new_for_sysctl(NULL, NULL, 1024, req); + if (sb == NULL) { + return (ENOMEM); + } + + sbuf_printf(sb, "\n\tHead %u\n", sc->rx_idx_head); + sbuf_printf(sb, "\tDMA %u\n", + (pHw->GMAC_RBQB - (uintptr_t)&sc->rx->bds[0]) / 8); + + for (i = 0; i < RX_DESC_COUNT; ++i) { + sbuf_printf(sb, "\t[%2u] %08x %08x\n", i, + sc->rx->bds[i].status.val, sc->rx->bds[i].addr); + } + + error = sbuf_finish(sb); + sbuf_delete(sb); + return (error); +} static void if_atsam_add_sysctls(device_t dev) { struct if_atsam_softc *sc = device_get_softc(dev); + Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *base; struct sysctl_oid_list *statsnode; struct sysctl_oid_list *hwstatsnode; struct sysctl_oid_list *child; struct sysctl_oid *tree; ctx = device_get_sysctl_ctx(dev); - child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); + base = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); - tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, + tree = SYSCTL_ADD_NODE(ctx, base, OID_AUTO, "regs", CTLFLAG_RD, + NULL, "if_atsam registers"); + child = SYSCTL_CHILDREN(tree); + + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txdesc", CTLTYPE_STRING | + CTLFLAG_RD, sc, 0, if_atsam_sysctl_tx_desc, "A", + "Transmit Descriptors"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxdesc", CTLTYPE_STRING | + CTLFLAG_RD, sc, 0, if_atsam_sysctl_rx_desc, "A", + "Receive Descriptors"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "imr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_IMR), 0, + if_atsam_sysctl_reg, "I", "IMR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "isr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_ISR), 0, + if_atsam_sysctl_reg, "I", "ISR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rsr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_RSR), 0, + if_atsam_sysctl_reg, "I", "RSR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tsr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_TSR), 0, + if_atsam_sysctl_reg, "I", "TSR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "nsr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_NSR), 0, + if_atsam_sysctl_reg, "I", "NSR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ncfgr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_NCFGR), 0, + if_atsam_sysctl_reg, "I", "NCFGR"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ncr", CTLTYPE_UINT | + CTLFLAG_RD, __DEVOLATILE(uint32_t *, &pHw->GMAC_NCR), 0, + if_atsam_sysctl_reg, "I", "NCR"); + + tree = SYSCTL_ADD_NODE(ctx, base, OID_AUTO, "stats", CTLFLAG_RD, NULL, "if_atsam statistics"); statsnode = SYSCTL_CHILDREN(tree); + SYSCTL_ADD_PROC(ctx, statsnode, OID_AUTO, "reset", CTLTYPE_INT | + CTLFLAG_WR, sc, 0, if_atsam_stats_reset, "I", "Reset"); + tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "sw", CTLFLAG_RD, NULL, "if_atsam software statistics"); child = SYSCTL_CHILDREN(tree); @@ -1145,12 +1299,12 @@ if_atsam_add_sysctls(device_t dev) SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overrun_errors", CTLFLAG_RD, &sc->stats.rx_overrun_errors, 0, "RX overrun errors"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_used_bit_reads", + CTLFLAG_RD, &sc->stats.rx_used_bit_reads, 0, + "RX used bit reads"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_interrupts", CTLFLAG_RD, &sc->stats.rx_interrupts, 0, "Rx interrupts"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_complete_int", - CTLFLAG_RD, &sc->stats.tx_complete_int, 0, - "Tx complete interrupts"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_tur_errors", CTLFLAG_RD, &sc->stats.tx_tur_errors, 0, "Error Tur Tx interrupts"); @@ -1163,9 +1317,6 @@ if_atsam_add_sysctls(device_t dev) SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_hresp_errors", CTLFLAG_RD, &sc->stats.tx_hresp_errors, 0, "Error Hresp Tx interrupts"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_interrupts", - CTLFLAG_RD, &sc->stats.tx_interrupts, 0, - "Tx interrupts"); tree = SYSCTL_ADD_NODE(ctx, statsnode, OID_AUTO, "hw", CTLFLAG_RD, NULL, "if_atsam hardware statistics"); @@ -1175,40 +1326,40 @@ if_atsam_add_sysctls(device_t dev) NULL, "if_atsam hardware transmit statistics"); child = SYSCTL_CHILDREN(tree); - SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_transm", + SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets", CTLFLAG_RD, &sc->stats.octets_transm, "Octets Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames", CTLFLAG_RD, &sc->stats.frames_transm, 0, "Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames", CTLFLAG_RD, &sc->stats.broadcast_frames_transm, 0, "Broadcast Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames", CTLFLAG_RD, &sc->stats.multicast_frames_transm, 0, "Multicast Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames", CTLFLAG_RD, &sc->stats.pause_frames_transm, 0, "Pause Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_bytes", CTLFLAG_RD, &sc->stats.frames_64_byte_transm, 0, "64 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_bytes", CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_transm, 0, "65 to 127 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_bytes", CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_transm, 0, "128 to 255 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_bytes", CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_transm, 0, "256 to 511 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_bytes", CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_transm, 0, "512 to 1023 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_bytes", CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_transm, 0, "1024 to 1518 Byte Frames Transmitted"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_greater_1518_byte_transm", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_bytes", CTLFLAG_RD, &sc->stats.frames_greater_1518_byte_transm, 0, "Greater Than 1518 Byte Frames Transmitted"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "transmit_underruns", @@ -1237,49 +1388,49 @@ if_atsam_add_sysctls(device_t dev) NULL, "if_atsam hardware receive statistics"); child = SYSCTL_CHILDREN(tree); - SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets_rec", + SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "octets", CTLFLAG_RD, &sc->stats.octets_rec, "Octets Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames", CTLFLAG_RD, &sc->stats.frames_rec, 0, "Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "broadcast_frames", CTLFLAG_RD, &sc->stats.broadcast_frames_rec, 0, "Broadcast Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "multicast_frames", CTLFLAG_RD, &sc->stats.multicast_frames_rec, 0, "Multicast Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pause_frames", CTLFLAG_RD, &sc->stats.pause_frames_rec, 0, "Pause Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_64_bytes", CTLFLAG_RD, &sc->stats.frames_64_byte_rec, 0, "64 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_65_to_127_bytes", CTLFLAG_RD, &sc->stats.frames_65_to_127_byte_rec, 0, "65 to 127 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_128_to_255_bytes", CTLFLAG_RD, &sc->stats.frames_128_to_255_byte_rec, 0, "128 to 255 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_256_to_511_bytes", CTLFLAG_RD, &sc->stats.frames_256_to_511_byte_rec, 0, "256 to 511 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_512_to_1023_bytes", CTLFLAG_RD, &sc->stats.frames_512_to_1023_byte_rec, 0, "512 to 1023 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1024_to_1518_bytes", CTLFLAG_RD, &sc->stats.frames_1024_to_1518_byte_rec, 0, "1024 to 1518 Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_byte_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frames_1519_to_maximum_bytes", CTLFLAG_RD, &sc->stats.frames_1519_to_maximum_byte_rec, 0, "1519 to Maximum Byte Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "undersize_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "undersize_frames", CTLFLAG_RD, &sc->stats.undersize_frames_rec, 0, "Undersize Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "oversize_frames_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "oversize_frames", CTLFLAG_RD, &sc->stats.oversize_frames_rec, 0, "Oversize Frames Received"); - SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "jabbers_rec", + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "jabbers", CTLFLAG_RD, &sc->stats.jabbers_rec, 0, "Jabbers Received"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "frame_check_sequence_errors", @@ -1311,49 +1462,6 @@ if_atsam_add_sysctls(device_t dev) "UDP Checksum Errors"); } - -/* - * Calculates the index that is to be sent into the hash registers - */ -static void if_atsam_get_hash_index(uint64_t addr, uint32_t *val) -{ - uint64_t tmp_val; - uint8_t i, j; - uint64_t idx; - int offset = 0; - - addr &= MAC_ADDR_MASK; - - for (i = 0; i < HASH_INDEX_AMOUNT; ++i) { - tmp_val = 0; - offset = 0; - for (j = 0; j < HASH_ELEMENTS_PER_INDEX; j++) { - idx = (addr >> (offset + i)) & MAC_IDX_MASK; - tmp_val ^= idx; - offset += HASH_INDEX_AMOUNT; - } - if (tmp_val > 0) { - *val |= (1u << i); - } - } -} - - -/* - * Dis/Enable promiscuous Mode - */ -static void if_atsam_promiscuous_mode(if_atsam_softc *sc, bool enable) -{ - Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; - - if (enable) { - pHw->GMAC_NCFGR |= GMAC_PROM_ENABLE; - } else { - pHw->GMAC_NCFGR &= ~GMAC_PROM_ENABLE; - } -} - - static int if_atsam_mediaioctl(if_atsam_softc *sc, struct ifreq *ifr, u_long command) { @@ -1380,8 +1488,6 @@ if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; int rv = 0; - bool prom_enable; - struct mii_data *mii; switch (command) { case SIOCGIFMEDIA: @@ -1389,17 +1495,31 @@ if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) rv = if_atsam_mediaioctl(sc, ifr, command); break; case SIOCSIFFLAGS: + IF_ATSAM_LOCK(sc); if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if_atsam_init(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) { + if_atsam_setup_rxfilter(sc); + } + } else { + if_atsam_start_locked(sc); } - prom_enable = ((ifp->if_flags & IFF_PROMISC) != 0); - if_atsam_promiscuous_mode(sc, prom_enable); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - if_atsam_stop(sc); + if_atsam_stop_locked(sc); } } + sc->if_flags = ifp->if_flags; + IF_ATSAM_UNLOCK(sc); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + IF_ATSAM_LOCK(sc); + if_atsam_setup_rxfilter(sc); + IF_ATSAM_UNLOCK(sc); + } break; default: rv = ether_ioctl(ifp, command, data); @@ -1416,7 +1536,6 @@ static int if_atsam_driver_attach(device_t dev) if_atsam_softc *sc; struct ifnet *ifp; int unit; - char *unitName; uint8_t eaddr[ETHER_ADDR_LEN]; sc = device_get_softc(dev); @@ -1437,13 +1556,6 @@ static int if_atsam_driver_attach(device_t dev) memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN); - sc->amount_rx_buf = RXBUF_COUNT; - sc->amount_tx_buf = TXBUF_COUNT; - - sc->tx_ring.tx_bd_used = 0; - sc->tx_ring.tx_bd_free = 0; - sc->tx_ring.length = sc->amount_tx_buf; - /* Set Initial Link Speed */ sc->link_speed = GMAC_SPEED_100M; sc->link_duplex = GMAC_DUPLEX_FULL; @@ -1486,17 +1598,20 @@ static int if_atsam_driver_attach(device_t dev) */ ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_init = if_atsam_init; + ifp->if_init = if_atsam_start; ifp->if_ioctl = if_atsam_ioctl; - ifp->if_start = if_atsam_enet_start; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_transmit = if_atsam_transmit; + ifp->if_qflush = if_qflush; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | - IFCAP_VLAN_HWCSUM; + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTAGGING; + ifp->if_capenable = ifp->if_capabilities; ifp->if_hwassist = CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP; - IFQ_SET_MAXLEN(&ifp->if_snd, TXBUF_COUNT - 1); - ifp->if_snd.ifq_drv_maxlen = TXBUF_COUNT - 1; + IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); + ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; IFQ_SET_READY(&ifp->if_snd); + ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* * Attach the interface @@ -1504,6 +1619,7 @@ static int if_atsam_driver_attach(device_t dev) ether_ifattach(ifp, eaddr); if_atsam_add_sysctls(dev); + if_atsam_init(sc); return (0); } diff --git a/rtemsbsd/sys/net/if_ppp.c b/rtemsbsd/sys/net/if_ppp.c index 709f13e0..e134dc76 100644 --- a/rtemsbsd/sys/net/if_ppp.c +++ b/rtemsbsd/sys/net/if_ppp.c @@ -313,11 +313,12 @@ static rtems_task ppp_txdaemon(rtems_task_argument arg) frag=0; /* initialize output values */ - sc->sc_outfcs = PPP_INITFCS; - sc->sc_outbuf = (u_char *)0; - sc->sc_outlen = (short )0; - sc->sc_outoff = (short )0; - sc->sc_outfcslen = (short )0; + sc->sc_outfcs = PPP_INITFCS; + sc->sc_outbuf = (u_char *)0; + sc->sc_outlen = (short )0; + sc->sc_outoff = (short )0; + sc->sc_outoff_update = false; + sc->sc_outfcslen = (short )0; /* printf("Start Transmit Packet..\n"); */ diff --git a/rtemsbsd/sys/net/if_pppvar.h b/rtemsbsd/sys/net/if_pppvar.h index fdfb56df..bd11bcbc 100644 --- a/rtemsbsd/sys/net/if_pppvar.h +++ b/rtemsbsd/sys/net/if_pppvar.h @@ -117,6 +117,7 @@ struct ppp_softc { struct ifqueue sc_freeq; /* free packets */ short sc_outoff; /* output packet byte offset */ + bool sc_outoff_update; /* outoff needs update in pppstart */ short sc_outflag; /* output status flag */ short sc_outlen; /* length of output packet */ short sc_outfcslen; /* length of output fcs data */ diff --git a/rtemsbsd/sys/net/ppp_tty.c b/rtemsbsd/sys/net/ppp_tty.c index 80d4fee1..2e850dc7 100644 --- a/rtemsbsd/sys/net/ppp_tty.c +++ b/rtemsbsd/sys/net/ppp_tty.c @@ -124,7 +124,7 @@ int pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args); int pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args); int ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args); int pppinput(int c, struct rtems_termios_tty *tty); -int pppstart(struct rtems_termios_tty *tp); +int pppstart(struct rtems_termios_tty *tp, int len); u_short pppfcs(u_short fcs, u_char *cp, int len); void pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp); @@ -557,7 +557,7 @@ pppasyncctlp( * Called at spltty or higher. */ int -pppstart(struct rtems_termios_tty *tp) +pppstart(struct rtems_termios_tty *tp, int len) { u_char *sendBegin; u_long ioffset = (u_long )0; @@ -567,6 +567,13 @@ pppstart(struct rtems_termios_tty *tp) /* ensure input is valid and we are busy */ if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) { + /* Adapt offsets if necessary */ + if ( sc->sc_outoff_update ) { + sc->sc_stats.ppp_obytes += len; + sc->sc_outoff += len; + sc->sc_outoff_update = false; + } + /* check to see if we need to get the next buffer */ /* Ready with PPP_FLAG Character ? */ @@ -644,8 +651,25 @@ pppstart(struct rtems_termios_tty *tp) /* write out the character(s) and update the stats */ (*tp->handler.write)(ctx, (char *)sendBegin, (ioffset > 0) ? ioffset : 1); - sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1; - sc->sc_outoff += ioffset; + /* + * In case of polled drivers, everything is sent here. So adapt the + * offsets. In case of interrupt or task driven drivers, we don't know + * whether all characters have been sent. We only get feedback via + * rtems_termios_dequeue_characters() function which is the one that is + * calling us. + */ + if (tp->handler.mode == TERMIOS_POLLED) { + sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1; + sc->sc_outoff += ioffset; + sc->sc_outoff_update = false; + } else { + if (ioffset > 0) { + sc->sc_outoff_update = true; + } else { + sc->sc_outoff_update = false; + sc->sc_stats.ppp_obytes += 1; + } + } return (0); } diff --git a/testsuite/pf02/test_main.c b/testsuite/pf02/test_main.c index 5941ea5a..dfb9847b 100644 --- a/testsuite/pf02/test_main.c +++ b/testsuite/pf02/test_main.c @@ -167,6 +167,7 @@ test_main(void) { rtems_status_code sc; int rv; + rtems_shell_env_t env; prepare_files(); @@ -176,9 +177,7 @@ test_main(void) rv = rtems_initialize_ftpd(); assert(rv == 0); - rtems_shell_env_t env; - - memset(&env, 0, sizeof(env)); + rtems_shell_dup_current_env(&env); rtems_shell_main_loop( &env ); exit(0); diff --git a/testsuite/tcpdump01/test_main.c b/testsuite/tcpdump01/test_main.c new file mode 100644 index 00000000..0f31cdde --- /dev/null +++ b/testsuite/tcpdump01/test_main.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @brief Tests the tcpdump command. + */ + +/* + * Copyright (C) 2022 embedded brains GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <vm/uma.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <err.h> + +#include <assert.h> +#include <ck_epoch.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rtems.h> +#include <rtems/bsd/bsd.h> +#include <rtems/console.h> +#include <rtems/libcsupport.h> + +#include <machine/rtems-bsd-commands.h> + +#define TEST_NAME "LIBBSD TCPDUMP 1" + +typedef struct { + rtems_id main_id; + int sp[2]; +} test_context; + +static test_context test_instance; + +static void +epoch_cleanup(void) +{ + rtems_status_code sc; + + sc = rtems_task_wake_after(CK_EPOCH_LENGTH); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void +init_addr(struct sockaddr_in *addr) +{ + int ok; + + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(1234); + ok = inet_aton("127.0.0.1", &addr->sin_addr); + assert(ok != 0); +} + +static rtems_id +start_task(rtems_task_entry entry, void *arg) +{ + rtems_task_priority prio; + rtems_id id; + rtems_status_code sc; + + sc = rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &prio); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_create(rtems_build_name('T', 'E', 'S', 'T' ), prio - 1, + 32 * 1024, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &id); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, entry, (rtems_task_argument)arg); + assert(sc == RTEMS_SUCCESSFUL); + + return id; +} + +static void +test_tcpdump_help(void) +{ + char *argv[] = { + "tcpdump", + "-h", + NULL + }; + rtems_resource_snapshot snapshot; + int exit_code; + + rtems_resource_snapshot_take(&snapshot); + + exit_code = rtems_bsd_command_tcpdump(RTEMS_BSD_ARGC(argv), argv); + assert(exit_code == 0); + + assert(rtems_resource_snapshot_check(&snapshot)); +} + +static const char raw_packets_file[] = "packets.bin"; + +static void +run_tcpdump_write_raw_packets(rtems_task_argument arg) +{ + test_context *ctx; + FILE *file; + FILE *saved_stdin; + FILE *saved_stdout; + FILE *saved_stderr; + int rv; + char *argv[] = { + "tcpdump", + "-n", + "-i", + "lo0", + "-w", + RTEMS_DECONST(char *, raw_packets_file), + NULL + }; + int exit_code; + rtems_status_code sc; + + ctx = (test_context *)arg; + + saved_stdin = stdin; + saved_stdout = stdout; + saved_stderr = stderr; + + file = fdopen(ctx->sp[1], "r+"); + assert(file != NULL); + + stdin = file; + stdout = file; + stderr = file; + + exit_code = rtems_bsd_command_tcpdump(RTEMS_BSD_ARGC(argv), argv); + assert(exit_code == 0); + + stdin = saved_stdin; + stdout = saved_stdout; + stderr = saved_stderr; + + rv = fclose(file); + assert(rv == 0); + + sc = rtems_event_transient_send(ctx->main_id); + assert(sc == RTEMS_SUCCESSFUL); + + rtems_task_exit(); +} + +static void +test_tcpdump_write_raw_packets(test_context *ctx) +{ + char *argv[] = { + "tcpdump", + "-n", + "-r", + RTEMS_DECONST(char *, raw_packets_file), + NULL + }; + rtems_resource_snapshot snapshot; + int in; + int out; + int rv; + char c; + ssize_t n; + struct sockaddr_in addr; + socklen_t addr_len; + rtems_status_code sc; + int exit_code; + + rtems_resource_snapshot_take(&snapshot); + + rv = socketpair(PF_UNIX, SOCK_STREAM, 0, ctx->sp); + assert(rv == 0); + + start_task(run_tcpdump_write_raw_packets, ctx); + + init_addr(&addr); + + in = socket(PF_INET, SOCK_DGRAM, 0); + assert(out >= 0); + + rv = bind(in, (const struct sockaddr *) &addr, sizeof(addr)); + assert(rv == 0); + + out = socket(PF_INET, SOCK_DGRAM, 0); + assert(out >= 0); + + c = 'x'; + n = sendto(out, &c, sizeof(c), 0, + (const struct sockaddr *) &addr, sizeof(addr)); + assert(n == 1); + + c = 'y'; + addr_len = sizeof(addr); + n = recvfrom(in, &c, sizeof(c), 0, + (struct sockaddr *) &addr, &addr_len); + assert(n == 1); + assert(c == 'x'); + + /* The tcpdump pcap read timeout is 1000ms */ + sc = rtems_task_wake_after(rtems_clock_get_ticks_per_second()); + assert(sc == RTEMS_SUCCESSFUL); + + c = 'q'; + n = write(ctx->sp[0], &c, sizeof(c)); + assert(n == 1); + + rv = close(out); + assert(rv == 0); + + rv = close(in); + assert(rv == 0); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + assert(sc == RTEMS_SUCCESSFUL); + + rv = close(ctx->sp[0]); + assert(rv == 0); + + exit_code = rtems_bsd_command_tcpdump(RTEMS_BSD_ARGC(argv), argv); + assert(exit_code == 0); + + rv = unlink(raw_packets_file); + assert(rv == 0); + + epoch_cleanup(); + assert(rtems_resource_snapshot_check(&snapshot)); +} + +static void +test_main(void) +{ + test_context *ctx; + FILE *file; + int rv; + + ctx = &test_instance; + ctx->main_id = rtems_task_self(); + + /* Fill dynamic file pool in Newlib */ + file = fopen(CONSOLE_DEVICE_NAME, "r+"); + assert(file != NULL); + rv = fclose(file); + assert(rv == 0); + + /* + * Stop interferences of uma_timeout() which may need some dynamic + * memory. + */ + rtems_uma_drain_timeout(); + + rtems_bsd_ifconfig_lo0(); + epoch_cleanup(); + + test_tcpdump_help(); + test_tcpdump_write_raw_packets(ctx); + + exit(0); +} + +#include <rtems/bsd/test/default-init.h> |