diff --git a/examples/ostest/Makefile b/examples/ostest/Makefile index 99d4d3adf..f533364c6 100644 --- a/examples/ostest/Makefile +++ b/examples/ostest/Makefile @@ -71,19 +71,25 @@ endif ifneq ($(CONFIG_DISABLE_PTHREAD),y) CSRCS += cancel.c cond.c mutex.c sem.c semtimed.c barrier.c timedwait.c +CSRCS += pthread_rwlock.c +CSRCS += pthread_rwlock_cancel.c + +ifeq ($(CONFIG_PTHREAD_CLEANUP),y) +CSRCS += pthread_cleanup.c +endif ifneq ($(CONFIG_PTHREAD_MUTEX_UNSAFE),y) CSRCS += robust.c endif -ifeq ($(CONFIG_FS_NAMED_SEMAPHORES),y) -CSRCS += nsem.c -endif - ifeq ($(CONFIG_PTHREAD_MUTEX_TYPES),y) CSRCS += rmutex.c endif +ifeq ($(CONFIG_FS_NAMED_SEMAPHORES),y) +CSRCS += nsem.c +endif + ifneq ($(CONFIG_RR_INTERVAL),0) CSRCS += roundrobin.c endif diff --git a/examples/ostest/ostest.h b/examples/ostest/ostest.h index 17ee5b85d..b271d3f79 100644 --- a/examples/ostest/ostest.h +++ b/examples/ostest/ostest.h @@ -145,7 +145,7 @@ int waitpid_test(void); void mutex_test(void); -/* rmutex.c ******************************************************************/ +/* rmutex.c *****************************************************************/ void recursive_mutex_test(void); @@ -187,7 +187,7 @@ void robust_test(void); void timedwait_test(void); -/* sigprocmask.c ****************************************************************/ +/* sigprocmask.c ************************************************************/ void sigprocmask_test(void); @@ -208,7 +208,7 @@ void sigev_thread_test(void); void rr_test(void); -/* sporadic.c *************************************************************/ +/* sporadic.c ***************************************************************/ void sporadic_test(void); @@ -216,6 +216,18 @@ void sporadic_test(void); void tls_test(void); +/* pthread_rwlock.c *********************************************************/ + +void pthread_rwlock_test(void); + +/* pthread_rwlock_cancel.c **************************************************/ + +void pthread_rwlock_cancel_test(void); + +/* pthread_cleanup.c ********************************************************/ + +void pthread_cleanup_test(void); + /* barrier.c ****************************************************************/ void barrier_test(void); diff --git a/examples/ostest/ostest_main.c b/examples/ostest/ostest_main.c index 7d1734c97..4cfe61cd7 100644 --- a/examples/ostest/ostest_main.c +++ b/examples/ostest/ostest_main.c @@ -424,15 +424,31 @@ static int user_main(int argc, char *argv[]) cond_test(); check_test_memory_usage(); #endif + + /* Verify pthreads rwlock interfaces */ + + printf("\nuser_main: pthread_rwlock test\n"); + pthread_rwlock_test(); + check_test_memory_usage(); + + printf("\nuser_main: pthread_rwlock_cancel test\n"); + pthread_rwlock_cancel_test(); + check_test_memory_usage(); + +#ifdef CONFIG_PTHREAD_CLEANUP + /* Verify pthread cancellation cleanup handlers */ + + printf("\nuser_main: pthread_cleanup test\n"); + pthread_cleanup_test(); + check_test_memory_usage(); #endif -#ifndef CONFIG_DISABLE_PTHREAD /* Verify pthreads and condition variable timed waits */ printf("\nuser_main: timed wait test\n"); timedwait_test(); check_test_memory_usage(); -#endif +#endif /* !CONFIG_DISABLE_PTHREAD */ #if !defined(CONFIG_DISABLE_MQUEUE) && !defined(CONFIG_DISABLE_PTHREAD) /* Verify pthreads and message queues */ diff --git a/examples/ostest/pthread_cleanup.c b/examples/ostest/pthread_cleanup.c new file mode 100644 index 000000000..61c11f0f8 --- /dev/null +++ b/examples/ostest/pthread_cleanup.c @@ -0,0 +1,170 @@ +/**************************************************************************** + * examples/ostest/pthread_cleanup.c + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Author: Juha Niskanen + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sync_s +{ + pthread_cond_t cond; + pthread_mutex_t lock; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void cleanup(FAR void * data) +{ + FAR struct sync_s *sync = (FAR struct sync_s *) data; + int status; + + /* Note: The behavior of canceling pthread_cond_wait() with asynchronous + * cancellation is not defined. On NuttX we get EPERM here, but application + * code must not rely on this. + */ + + status = pthread_mutex_unlock(&sync->lock); +#ifndef CONFIG_CANCELLATION_POINTS + if (status == EPERM) + { + printf("pthread_cleanup: thread did not have mutex locked: %d\n", status); + return; + } +#endif + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_mutex_unlock in cleanup handler. " + "Status: %d\n", status); + } +} + +static void *cleanup_thread(FAR void * data) +{ + FAR struct sync_s *sync = (FAR struct sync_s *) data; + int status; + + status = pthread_mutex_lock(&sync->lock); + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_mutex_lock, status=%d\n", status); + return NULL; + } + + pthread_cleanup_push(&cleanup, sync); + + while(1) + { + status = pthread_cond_wait(&sync->cond, &sync->lock); + if (status != 0) + { + printf("pthread_cleanup: ERROR wait returned. Status: %d\n", status); + } + } + + pthread_cleanup_pop(1); + return NULL; +} + +static void test_cleanup(void) +{ + pthread_t thread1; + int status; + void *result; + struct sync_s sync = { + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER + }; + + status = pthread_create(&thread1, NULL, cleanup_thread, &sync); + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_create, status=%d\n", status); + return; + } + + usleep(500 * 1000); + + status = pthread_cancel(thread1); + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_cancel, status=%d\n", status); + } + + status = pthread_join(thread1, &result); + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_join, status=%d\n", status); + } + else if (result != PTHREAD_CANCELED) + { + printf("pthread_cleanup: ERROR pthread_join returned wrong result: %p\n", result); + } + +#ifdef CONFIG_CANCELLATION_POINTS + /* Do some operations on lock in order to check if it is in usable state. */ + + status = pthread_mutex_trylock(&sync.lock); + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_mutex_trylock, status=%d\n", status); + } + + status = pthread_mutex_unlock(&sync.lock); + if (status != 0) + { + printf("pthread_cleanup: ERROR pthread_mutex_unlock, status=%d\n", status); + } +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void pthread_cleanup_test(void) +{ + printf("pthread_cleanup: Starting test\n"); + test_cleanup(); +} diff --git a/examples/ostest/pthread_rwlock.c b/examples/ostest/pthread_rwlock.c new file mode 100644 index 000000000..22ad446e8 --- /dev/null +++ b/examples/ostest/pthread_rwlock.c @@ -0,0 +1,448 @@ +/**************************************************************************** + * examples/ostest/pthread_rwlock.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct race_cond_s +{ + sem_t * sem1; + sem_t * sem2; + pthread_rwlock_t *rw_lock; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static int g_race_cond_thread_pos; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static FAR void *race_cond_thread1(FAR void *data) +{ + FAR struct race_cond_s *rc = (FAR struct race_cond_s *) data; + int status; + + /* Runs 1st */ + + if (g_race_cond_thread_pos++ != 0) + { + printf("pthread_rwlock: Thread order unexpected. Expected 0, got %d", + g_race_cond_thread_pos); + } + + status = pthread_rwlock_wrlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to lock for writing\n"); + } + + sem_post(rc->sem2); + sem_wait(rc->sem1); + + /* Context Switch -> Runs 3rd */ + + if (g_race_cond_thread_pos++ != 2) + { + printf("pthread_rwlock: Thread order unexpected. Expected 2, got %d", + g_race_cond_thread_pos); + } + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to unlock lock held for writing\n"); + } + + status = pthread_rwlock_rdlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to open rwlock for reading. Status: %d\n", status); + } + + sem_wait(rc->sem1); + + /* Context Switch - Runs 5th */ + + if (g_race_cond_thread_pos++ != 4) + { + printf("pthread_rwlock: Thread order unexpected. Expected 4, got %d", + g_race_cond_thread_pos); + } + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to unlock lock held for writing\n"); + } + + status = pthread_rwlock_rdlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to open rwlock for reading. Status: %d\n", status); + } + + sem_post(rc->sem2); + sem_wait(rc->sem1); + + /* Context switch - Runs 7th */ + + if (g_race_cond_thread_pos++ != 6) + { + printf("pthread_rwlock: Thread order unexpected. Expected 6, got %d", + g_race_cond_thread_pos); + } + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to unlock lock held for reading. Status: %d\n", status); + } + + return NULL; +} + +static FAR void *race_cond_thread2(FAR void *data) +{ + FAR struct race_cond_s *rc = (FAR struct race_cond_s *) data; + int status; + + status = sem_wait(rc->sem2); + + /* Runs 2nd */ + + if (status != 0) + { + printf("pthread_rwlock: Failed to wait on semaphore. Status: %d\n", status); + } + + if (g_race_cond_thread_pos++ != 1) + { + printf("pthread_rwlock: Thread order unexpected. Expected 1, got %d", g_race_cond_thread_pos); + } + + status = pthread_rwlock_tryrdlock(rc->rw_lock); + if (status != EBUSY) + { + printf("pthread_rwlock: Opened rw_lock for rd when locked for writing: %d\n", status); + } + + status = pthread_rwlock_trywrlock(rc->rw_lock); + if (status != EBUSY) + { + printf("pthread_rwlock: Opened rw_lock for wr when locked for writing: %d\n", status); + } + sem_post(rc->sem1); + status = pthread_rwlock_rdlock(rc->rw_lock); + + /* Context - Switch Runs 4th */ + + if (status != 0) + { + printf("pthread_rwlock: Failed to open rwlock for reading. Status: %d\n", status); + } + + if (g_race_cond_thread_pos++ != 3) + { + printf("pthread_rwlock: Thread order unexpected. Expected 3, got %d", + g_race_cond_thread_pos); + } + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to unlock lock held for writing\n"); + } + + sem_post(rc->sem1); + sem_wait(rc->sem2); + + /* Context switch Runs 6th */ + + if (g_race_cond_thread_pos++ != 5) + { + printf("pthread_rwlock: Thread order unexpected. Expected 5, got %d", + g_race_cond_thread_pos); + } + + sem_post(rc->sem1); + status = pthread_rwlock_wrlock(rc->rw_lock); + + /* Context switch runs 8th */ + + if (status != 0) + { + printf("pthread_rwlock: Failed to open rwlock for reading. Status: %d\n", status); + } + + if (g_race_cond_thread_pos++ != 7) + { + printf("pthread_rwlock: Thread order unexpected. Expected 7, got %d", + g_race_cond_thread_pos); + } + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to unlock lock held for writing. Status: %d\n", status); + } + + return NULL; +} + +static void test_two_threads(void) +{ + pthread_rwlock_t rw_lock; + struct race_cond_s rc; + pthread_t thread1; + pthread_t thread2; + sem_t sem1; + sem_t sem2; + int status; + + status = pthread_rwlock_init(&rw_lock, NULL); + if (status != 0) + { + printf("pthread_rwlock: ERROR pthread_rwlock_init failed, status=%d\n", status); + } + + status = sem_init(&sem1, 0, 0); + if (status != 0) + { + printf("pthread_rwlock: ERROR sem_init failed, status=%d\n", status); + } + + status = sem_init(&sem2, 0, 0); + if (status != 0) + { + printf("pthread_rwlock: ERROR sem_init failed, status=%d\n", status); + } + + rc.sem1 = &sem1; + rc.sem2 = &sem2; + rc.rw_lock = &rw_lock; + + g_race_cond_thread_pos = 0; + status = pthread_create(&thread1, NULL, race_cond_thread1, &rc); + status = pthread_create(&thread2, NULL, race_cond_thread2, &rc); + (void) pthread_join(thread1, NULL); + (void) pthread_join(thread2, NULL); +} + +static void * timeout_thread1(FAR void * data) +{ + FAR struct race_cond_s * rc = (FAR struct race_cond_s *) data; + int status; + + status = pthread_rwlock_wrlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to acquire rw_lock. Status: %d\n", status); + } + + sem_wait(rc->sem1); + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to unlock rw_lock. Status: %d\n", status); + } + + return NULL; +} + +static void * timeout_thread2(FAR void * data) +{ + FAR struct race_cond_s * rc = (FAR struct race_cond_s *) data; + struct timespec time; + int status; + + status = clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 2; + + status = pthread_rwlock_timedwrlock(rc->rw_lock, &time); + if (status != ETIMEDOUT) + { + printf("pthread_rwlock: Failed to properly timeout write lock\n"); + } + + status = clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 2; + + status = pthread_rwlock_timedrdlock(rc->rw_lock, &time); + if (status != ETIMEDOUT) + { + printf("pthread_rwlock: Failed to properly timeout rd lock\n"); + } + + status = clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 2; + + sem_post(rc->sem1); + status = pthread_rwlock_timedrdlock(rc->rw_lock, &time); + if (status != 0) + { + printf("pthread_rwlock: Failed to properly acquire rdlock\n"); + } + + status = pthread_rwlock_unlock(rc->rw_lock); + if (status != 0) + { + printf("pthread_rwlock: Failed to release rdlock\n"); + } + + return NULL; +} + +static void test_timeout(void) +{ + pthread_rwlock_t rw_lock; + struct race_cond_s rc; + pthread_t thread1; + pthread_t thread2; + int status; + sem_t sem1; + sem_t sem2; + + status = pthread_rwlock_init(&rw_lock, NULL); + if (status != 0) + { + printf("pthread_rwlock: ERROR pthread_rwlock_init failed, status=%d\n", + status); + } + + status = sem_init(&sem1, 0, 0); + if (status != 0) + { + printf("pthread_rwlock: ERROR sem_init failed, status=%d\n", status); + } + + status = sem_init(&sem2, 0, 0); + if (status != 0) + { + printf("pthread_rwlock: ERROR sem_init failed, status=%d\n", status); + } + + rc.sem1 = &sem1; + rc.sem2 = &sem2; + rc.rw_lock = &rw_lock; + + status = pthread_create(&thread1, NULL, timeout_thread1, &rc); + status = pthread_create(&thread2, NULL, timeout_thread2, &rc); + + (void) pthread_join(thread1, NULL); + (void) pthread_join(thread2, NULL); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void pthread_rwlock_test(void) +{ + pthread_rwlock_t rw_lock; + int status; + + printf("pthread_rwlock: Initializing rwlock\n"); + + status = pthread_rwlock_init(&rw_lock, NULL); + if (status != 0) + { + printf("pthread_rwlock: " + "ERROR pthread_rwlock_init failed, status=%d\n", + status); + } + + status = pthread_rwlock_trywrlock(&rw_lock); + if (status != 0) + { + printf("pthread_rwlock: " + "ERROR pthread_rwlock_trywrlock failed, status=%d\n", + status); + } + + status = pthread_rwlock_unlock(&rw_lock); + if (status != 0) + { + printf("pthread_rwlock: " + "ERROR pthread_rwlock_unlock failed, status=%d\n", + status); + } + + status = pthread_rwlock_trywrlock(&rw_lock); + if (status != 0) + { + printf("pthread_rwlock: " + "ERROR pthread_rwlock_trywrlock failed, status=%d\n", + status); + } + + status = pthread_rwlock_trywrlock(&rw_lock); + if (status != EBUSY) + { + printf("pthread_rwlock: " + "ERROR able to acquire write lock when write lock already acquired\n"); + } + + status = pthread_rwlock_tryrdlock(&rw_lock); + if (status != EBUSY) + { + printf("pthread_rwlock: " + "ERROR able to acquire read lock when write lock already acquired\n"); + } + + status = pthread_rwlock_unlock(&rw_lock); + if (status != 0) + { + printf("pthread_rwlock: " + "ERROR pthread_rwlock_unlock failed, status=%d\n", + status); + } + + test_two_threads(); + + test_timeout(); +} diff --git a/examples/ostest/pthread_rwlock_cancel.c b/examples/ostest/pthread_rwlock_cancel.c new file mode 100644 index 000000000..ced4075d9 --- /dev/null +++ b/examples/ostest/pthread_rwlock_cancel.c @@ -0,0 +1,252 @@ +/**************************************************************************** + * examples/ostest/pthread_rwlock_cancel.c + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Author: Juha Niskanen + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sync_s +{ + pthread_rwlock_t *read_lock; + pthread_rwlock_t *write_lock; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void * timeout_thread1(FAR void * data) +{ + FAR struct sync_s * sync = (FAR struct sync_s *) data; + struct timespec time; + int status; + + while(1) + { + (void)clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 1; + + status = pthread_rwlock_timedrdlock(sync->write_lock, &time); + if (status != ETIMEDOUT) + { + printf("pthread_rwlock_cancel: ERROR Acquired held write_lock. Status: %d\n", status); + } + } + + return NULL; +} + +static void * timeout_thread2(FAR void * data) +{ + FAR struct sync_s * sync = (FAR struct sync_s *) data; + struct timespec time; + int status; + + while (1) + { + (void)clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 1; + + status = pthread_rwlock_timedrdlock(sync->read_lock, &time); + if (status != 0) + { + printf("pthread_rwlock_cancel: Failed to acquire read_lock. Status: %d\n", status); + } + + sched_yield(); /* Not a cancellation point. */ + + if (status == 0) + { + status = pthread_rwlock_unlock(sync->read_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: Failed to release read_lock. Status: %d\n", status); + } + } + + (void)clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 1; + + status = pthread_rwlock_timedwrlock(sync->read_lock, &time); + if (status != ETIMEDOUT) + { + printf("pthread_rwlock_cancel: " + "ERROR Acquired held read_lock for writing. Status: %d\n", status); + } + } + + return NULL; +} + +static void test_timeout(void) +{ + pthread_rwlock_t read_lock; + pthread_rwlock_t write_lock; + struct sync_s sync; + pthread_t thread1, thread2; + int status, i; + + status = pthread_rwlock_init(&read_lock, NULL); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_rwlock_init(read_lock), status=%d\n", + status); + } + + status = pthread_rwlock_init(&write_lock, NULL); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_rwlock_init(write_lock), status=%d\n", + status); + } + + status = pthread_rwlock_rdlock(&read_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_rwlock_rdlock, status=%d\n", + status); + } + + status = pthread_rwlock_wrlock(&write_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_rwlock_wrlock, status=%d\n", + status); + } + + sync.read_lock = &read_lock; + sync.write_lock = &write_lock; + + status = pthread_create(&thread1, NULL, timeout_thread1, &sync); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_create, status=%d\n", status); + } + + status = pthread_create(&thread2, NULL, timeout_thread2, &sync); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_create, status=%d\n", status); + } + + for (i = 0; i < 10; i++) + { + usleep(300 * 1000); /* Give threads few seconds to run */ + } + + status = pthread_cancel(thread1); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_cancel, status=%d\n", status); + } + + status = pthread_cancel(thread2); + if (status != 0) + { + printf("pthread_rwlock_cancel: ERROR pthread_cancel, status=%d\n", status); + } + + (void) pthread_join(thread1, NULL); + (void) pthread_join(thread2, NULL); + + /* Do some operations on locks in order to check if they are still in + * usable state after deferred cancellation. */ + +#ifdef CONFIG_PTHREAD_CLEANUP +#ifdef CONFIG_CANCELLATION_POINTS + status = pthread_rwlock_trywrlock(&write_lock); + if (status != EBUSY) + { + printf("pthread_rwlock_cancel: " + "ERROR able to acquire write lock when write lock already acquired, " + "status=%d\n", status); + } + + status = pthread_rwlock_tryrdlock(&write_lock); + if (status != EBUSY) + { + printf("pthread_rwlock_cancel: " + "ERROR able to acquire read lock when write lock already acquired, " + "status=%d\n", status); + } + + status = pthread_rwlock_unlock(&read_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: " + "ERROR pthread_rwlock_unlock, status=%d\n", status); + } + + status = pthread_rwlock_unlock(&write_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: " + "ERROR pthread_rwlock_unlock, status=%d\n", status); + } + + status = pthread_rwlock_rdlock(&read_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: " + "ERROR pthread_rwlock_rdlock, status=%d\n", status); + } + + status = pthread_rwlock_wrlock(&write_lock); + if (status != 0) + { + printf("pthread_rwlock_cancel: " + "ERROR pthread_rwlock_wrlock, status=%d\n", status); + } +#endif /* CONFIG_CANCELLATION_POINTS */ +#endif /* CONFIG_PTHREAD_CLEANUP */ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void pthread_rwlock_cancel_test(void) +{ + printf("pthread_rwlock_cancel: Starting test\n"); + test_timeout(); +} diff --git a/examples/ostest/roundrobin.c b/examples/ostest/roundrobin.c index 5a807cf5f..4bd2d9ed4 100644 --- a/examples/ostest/roundrobin.c +++ b/examples/ostest/roundrobin.c @@ -127,7 +127,7 @@ static void get_primes(int *count, int *last) static FAR void *get_primes_thread(FAR void *parameter) { - int id = (int)parameter; + int id = (int)((intptr_t)parameter); int count; int last; int i; diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index 697d973c2..4e1ff9fa6 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -114,10 +114,11 @@ int netlib_setmacaddr(FAR const char *ifname, FAR const uint8_t *macaddr); int netlib_getmacaddr(FAR const char *ifname, FAR uint8_t *macaddr); #endif -#ifdef CONFIG_NET_ETHERNET +#ifdef CONFIG_NET_6LOWPAN /* Get IEEE802.15.4 MAC driver node address */ int netlib_setnodeaddr(FAR const char *ifname, FAR const uint8_t *nodeaddr); +bool netlib_nodeaddrconv(FAR const char *hwstr, FAR uint8_t *hw); #endif /* IP address support */ diff --git a/include/wireless/wapi.h b/include/wireless/wapi.h new file mode 100644 index 000000000..69ea3e38f --- /dev/null +++ b/include/wireless/wapi.h @@ -0,0 +1,586 @@ +/**************************************************************************** + * apps/include/wireless/wapi.h + * + * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Adapted for Nuttx from WAPI: + * + * Copyright (c) 2010, Volkan YAZICI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +#ifndef __APPS_INCLUDE_WIRELESS_WAPI_H +#define __APPS_INCLUDE_WIRELESS_WAPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum allowed ESSID size. */ + +#define WAPI_ESSID_MAX_SIZE IW_ESSID_MAX_SIZE + +/* Buffer size while reading lines from PROC_NET_ files. */ + +#define WAPI_PROC_LINE_SIZE 1024 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Generic linked list (dummy) decleration. (No definition!) */ + +typedef struct wapi_list_t wapi_list_t; + +/* Frequency flags. */ + +typedef enum +{ + WAPI_FREQ_AUTO = IW_FREQ_AUTO, + WAPI_FREQ_FIXED = IW_FREQ_FIXED +} wapi_freq_flag_t; + +/* Route target types. */ + +typedef enum +{ + WAPI_ROUTE_TARGET_NET, /* The target is a network. */ + WAPI_ROUTE_TARGET_HOST /* The target is a host. */ +} wapi_route_target_t; + +/* ESSID flags. */ + +typedef enum +{ + WAPI_ESSID_ON, + WAPI_ESSID_OFF +} wapi_essid_flag_t; + +/* Supported operation modes. */ + +typedef enum +{ + WAPI_MODE_AUTO = IW_MODE_AUTO, /* Driver decides. */ + WAPI_MODE_ADHOC = IW_MODE_ADHOC, /* Single cell network. */ + WAPI_MODE_MANAGED = IW_MODE_INFRA, /* Multi cell network, roaming, ... */ + WAPI_MODE_MASTER = IW_MODE_MASTER, /* Synchronisation master or access point. */ + WAPI_MODE_REPEAT = IW_MODE_REPEAT, /* Wireless repeater, forwarder. */ + WAPI_MODE_SECOND = IW_MODE_SECOND, /* Secondary master/repeater, backup. */ + WAPI_MODE_MONITOR = IW_MODE_MONITOR, /* Passive monitor, listen only. */ + WAPI_MODE_MESH = IW_MODE_MESH /* Mesh (IEEE 802.11s) network */ +} wapi_mode_t; + +/* Bitrate flags. + * + * At the moment, unicast (IW_BITRATE_UNICAST) and broadcast + * (IW_BITRATE_BROADCAST) bitrate flags are not supported. + */ + +typedef enum +{ + WAPI_BITRATE_AUTO, + WAPI_BITRATE_FIXED +} wapi_bitrate_flag_t; + +/* Transmit power (txpower) flags. */ + +typedef enum +{ + WAPI_TXPOWER_DBM, /* Value is in dBm. */ + WAPI_TXPOWER_MWATT, /* Value is in mW. */ + WAPI_TXPOWER_RELATIVE /* Value is in arbitrary units. */ +} wapi_txpower_flag_t; + +/* Linked list container for strings. */ + +typedef struct wapi_string_t +{ + FAR struct wapi_string_t *next; + FAR char *data; +} wapi_string_t; + +/* Linked list container for scan results. */ + +typedef struct wapi_scan_info_t +{ + FAR struct wapi_scan_info_t *next; + struct ether_addr ap; + int has_essid; + char essid[WAPI_ESSID_MAX_SIZE + 1]; + wapi_essid_flag_t essid_flag; + int has_freq; + double freq; + int has_mode; + wapi_mode_t mode; + int has_bitrate; + int bitrate; +} wapi_scan_info_t; + +/* Linked list container for routing table rows. */ + +typedef struct wapi_route_info_t +{ + FAR struct wapi_route_info_t *next; + FAR char *ifname; + struct in_addr dest; + struct in_addr gw; + + unsigned int flags;/* See RTF_* in net/route.h for available values. */ + unsigned int refcnt; + unsigned int use; + unsigned int metric; + struct in_addr netmask; + unsigned int mtu; + unsigned int window; + unsigned int irtt; +} wapi_route_info_t; + +/* A generic linked list container. For functions taking wapi_list_t type of + * argument, caller is resposible for releasing allocated memory. + */ + +struct wapi_list_t +{ + union wapi_list_head_t + { + FAR wapi_string_t *string; + FAR wapi_scan_info_t *scan; + FAR wapi_route_info_t *route; + } head; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + + #ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Frequency flag names. */ + +EXTERN FAR const char *g_wapi_freq_flags[]; + +/* ESSID flag names. */ + +EXTERN FAR const char *g_wapi_essid_flags[]; + +/* Supported operation mode names. */ + +EXTERN FAR const char *g_wapi_modes[]; + +/* Bitrate flag names. */ + +EXTERN FAR const char *g_wapi_bitrate_flags[]; + +/* Transmit power flag names. */ + +EXTERN FAR const char *g_wapi_txpower_flags[]; + +/**************************************************************************** + * Public Function Prototyppes + ****************************************************************************/ + +/**************************************************************************** + * Name: wapi_get_ifup + * + * Description: + * Gets the interface up status. + * + * Input Parameters: + * is_up Set to 0, if up; 1, otherwise. + * + ****************************************************************************/ + +int wapi_get_ifup(int sock, const char *ifname, int *is_up); + +/**************************************************************************** + * Name: wapi_set_ifup + * + * Description: + * Activates the interface. + * + ****************************************************************************/ + +int wapi_set_ifup(int sock, const char *ifname); + +/**************************************************************************** + * Name: wapi_set_ifdown + * + * Description: + * Shuts down the interface. + * + ****************************************************************************/ + +int wapi_set_ifdown(int sock, const char *ifname); + +/**************************************************************************** + * Name: wapi_get_ip + * + * Description: + * Gets IP address of the given network interface. + * + ****************************************************************************/ + +int wapi_get_ip(int sock, const char *ifname, struct in_addr *addr); + +/**************************************************************************** + * Name: wapi_set_ip + * + * Description: + * Sets IP adress of the given network interface. + * + ****************************************************************************/ + +int wapi_set_ip(int sock, const char *ifname, const struct in_addr *addr); + +/**************************************************************************** + * Name: wapi_get_netmask + * + * Description: + * Gets netmask of the given network interface. + * + ****************************************************************************/ + +int wapi_get_netmask(int sock, const char *ifname, struct in_addr *addr); + +/**************************************************************************** + * Name: wapi_set_netmask + * + * Description: + * Sets netmask of the given network interface. + * + ****************************************************************************/ + +int wapi_set_netmask(int sock, const char *ifname, const struct in_addr *addr); + +/**************************************************************************** + * Name: wapi_add_route_gw + * + * Description: + * Adds gateway for the given target network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ROUTE +int wapi_add_route_gw(int sock, wapi_route_target_t targettype, + FAR const struct in_addr *target, + FAR const struct in_addr *netmask, + FAR const struct in_addr *gw); +#endif + +/**************************************************************************** + * Name: wapi_del_route_gw + * + * Description: + * Deletes gateway for the given target network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ROUTE +int wapi_del_route_gw(int sock, wapi_route_target_t targettype, + FAR const struct in_addr *target, + FAR const struct in_addr *netmask, + FAR const struct in_addr *gw); +#endif + +/**************************************************************************** + * Name: wapi_get_freq + * + * Description: + * Gets the operating frequency of the device. + * + ****************************************************************************/ + +int wapi_get_freq(int sock, FAR const char *ifname, FAR double *freq, + FAR wapi_freq_flag_t *flag); + +/**************************************************************************** + * Name: wapi_set_freq + * + * Description: + * Sets the operating frequency of the device. + * + ****************************************************************************/ + +int wapi_set_freq(int sock, FAR const char *ifname, double freq, + wapi_freq_flag_t flag); + +/**************************************************************************** + * Name: wapi_freq2chan + * + * Description: + * Finds corresponding channel for the supplied freq. + * + * Returned Value: + * 0, on success; -2, if not found; otherwise, ioctl() return value. + * + ****************************************************************************/ + +int wapi_freq2chan(int sock, FAR const char *ifname, double freq, + FAR int *chan); + +/**************************************************************************** + * Name: wapi_chan2freq + * + * Description: + * Finds corresponding frequency for the supplied chan. + * + * Returned Value: + * 0, on success; -2, if not found; otherwise, ioctl() return value. + * + ****************************************************************************/ + +int wapi_chan2freq(int sock, FAR const char *ifname, int chan, + FAR double *freq); + +/**************************************************************************** + * Name: wapi_get_essid + * + * Description: + * Gets ESSID of the device. + * + * Input Parameters: + * essid - Used to store the ESSID of the device. Buffer must have + * enough space to store WAPI_ESSID_MAX_SIZE+1 characters. + * + ****************************************************************************/ + +int wapi_get_essid(int sock, FAR const char *ifname, FAR char *essid, + FAR wapi_essid_flag_t *flag); + +/**************************************************************************** + * Name: wapi_set_essid + * + * Description: + * Sets ESSID of the device. + * + * essid At most WAPI_ESSID_MAX_SIZE characters are read. + * + ****************************************************************************/ + +int wapi_set_essid(int sock, FAR const char *ifname, FAR const char *essid, + wapi_essid_flag_t flag); + +/**************************************************************************** + * Name: wapi_get_mode + * + * Description: + * Gets the operating mode of the device. + * + ****************************************************************************/ + +int wapi_get_mode(int sock, FAR const char *ifname, FAR wapi_mode_t *mode); + +/**************************************************************************** + * Name: wapi_set_mode + * + * Description: + * Sets the operating mode of the device. + * + ****************************************************************************/ + +int wapi_set_mode(int sock, FAR const char *ifname, wapi_mode_t mode); + +/**************************************************************************** + * Name: wapi_make_broad_ether + * + * Description: + * Creates an ethernet broadcast address. + * + ****************************************************************************/ + +int wapi_make_broad_ether(FAR struct ether_addr *sa); + +/**************************************************************************** + * Name: wapi_make_null_ether + * + * Description: + * Creates an ethernet NULL address. + * + ****************************************************************************/ + +int wapi_make_null_ether(FAR struct ether_addr *sa); + +/**************************************************************************** + * Name: wapi_get_ap + * + * Description: + * Gets access point address of the device. + * + * Input Parameters: + * ap - Set the to MAC address of the device. (For "any", a broadcast + * ethernet address; for "off", a null ethernet address is used.) + * + ****************************************************************************/ + +int wapi_get_ap(int sock, FAR const char *ifname, FAR struct ether_addr *ap); + +/**************************************************************************** + * Name: wapi_set_ap + * + * Description: + * Sets access point address of the device. + * + ****************************************************************************/ + +int wapi_set_ap(int sock, FAR const char *ifname, + FAR const struct ether_addr *ap); + +/**************************************************************************** + * Name: wapi_get_bitrate + * + * Description: + * Gets bitrate of the device. + * + ****************************************************************************/ + +int wapi_get_bitrate(int sock, FAR const char *ifname, + FAR int *bitrate, FAR wapi_bitrate_flag_t *flag); + +/**************************************************************************** + * Name: wapi_set_bitrate + * + * Description: + * Sets bitrate of the device. + * + ****************************************************************************/ + +int wapi_set_bitrate(int sock, FAR const char *ifname, int bitrate, + wapi_bitrate_flag_t flag); + +/**************************************************************************** + * Name: wapi_dbm2mwatt + * + * Description: + * Converts a value in dBm to a value in milliWatt. + * + ****************************************************************************/ + +int wapi_dbm2mwatt(int dbm); + +/**************************************************************************** + * Name: wapi_mwatt2dbm + * + * Description: + * Converts a value in milliWatt to a value in dBm. + * + ****************************************************************************/ + +int wapi_mwatt2dbm(int mwatt); + +/**************************************************************************** + * Name: wapi_get_txpower + * + * Description: + * Gets txpower of the device. + * + ****************************************************************************/ + +int wapi_get_txpower(int sock, FAR const char *ifname, FAR int *power, + FAR wapi_txpower_flag_t *flag); + +/**************************************************************************** + * Name: wapi_set_txpower + * + * Description: + * Sets txpower of the device. + * + ****************************************************************************/ + +int wapi_set_txpower(int sock, FAR const char *ifname, int power, + wapi_txpower_flag_t flag); + +/**************************************************************************** + * Name: wapi_make_socket + * + * Description: + * Creates an AF_INET socket to be used in ioctl() calls. + * + * Returned Value: + * Non-negative on success. + * + ****************************************************************************/ + +int wapi_make_socket(void); + +/**************************************************************************** + * Name: wapi_scan_init + * + * Description: + * Starts a scan on the given interface. Root privileges are required to start a + * scan. + * + ****************************************************************************/ + +int wapi_scan_init(int sock, const char *ifname); + +/**************************************************************************** + * Name: wapi_scan_stat + * + * Description: + * Checks the status of the scan process. + * + * Returned Value: + * Zero, if data is ready; 1, if data is not ready; negative on failure. + * + ****************************************************************************/ + +int wapi_scan_stat(int sock, FAR const char *ifname); + +/**************************************************************************** + * Name: wapi_scan_coll + * + * Description: + * Collects the results of a scan process. + * + * Input Parameters: + * aps - Pushes collected wapi_scan_info_t into this list. + * + ****************************************************************************/ + +int wapi_scan_coll(int sock, FAR const char *ifname, FAR wapi_list_t *aps); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __APPS_INCLUDE_WIRELESS_WAPI_H */ diff --git a/netutils/netlib/Makefile b/netutils/netlib/Makefile index 35030cab5..b5a8f96d2 100644 --- a/netutils/netlib/Makefile +++ b/netutils/netlib/Makefile @@ -87,7 +87,7 @@ CSRCS += netlib_setmacaddr.c netlib_getmacaddr.c endif ifeq ($(CONFIG_NET_6LOWPAN),y) -CSRCS += netlib_setnodeaddr.c +CSRCS += netlib_setnodeaddr.c netlib_nodeaddrconv.c endif # IGMP support diff --git a/netutils/netlib/netlib_nodeaddrconv.c b/netutils/netlib/netlib_nodeaddrconv.c new file mode 100644 index 000000000..02854c516 --- /dev/null +++ b/netutils/netlib/netlib_nodeaddrconv.c @@ -0,0 +1,109 @@ +/**************************************************************************** + * netutils/netlib/netlib_nodeaddrconv.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +#include "netutils/netlib.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlib_nodeaddrconv + ****************************************************************************/ + +bool netlib_nodeaddrconv(FAR const char *hwstr, FAR uint8_t *hw) +{ + unsigned char tmp; + unsigned char i; + unsigned char j; + char ch; + + /* Form xx:xx or xx:xx:xx:xx:xx:xx:xx:xx for extended Rime address */ + + if (strlen(hwstr) != 3 * NET_6LOWPAN_RIMEADDR_SIZE - 1) + { + return false; + } + + tmp = 0; + + for (i = 0; i < NET_6LOWPAN_RIMEADDR_SIZE; ++i) + { + j = 0; + do + { + ch = *hwstr++; + if (++j > 3) + { + return false; + } + + if (ch == ':' || ch == '\0') + { + *hw++ = tmp; + tmp = 0; + } + else if (ch >= '0' && ch <= '9') + { + tmp = (tmp << 4) + (ch - '0'); + } + else if (ch >= 'a' && ch <= 'f') + { + tmp = (tmp << 4) + (ch - 'a' + 10); + } + else if (ch >= 'A' && ch <= 'F') + { + tmp = (tmp << 4) + (ch - 'A' + 10); + } + else + { + return false; + } + } + while (ch != ':' && ch != 0); + } + + return true; +} diff --git a/netutils/netlib/netlib_setnodeaddr.c b/netutils/netlib/netlib_setnodeaddr.c index 942186070..436591eb9 100644 --- a/netutils/netlib/netlib_setnodeaddr.c +++ b/netutils/netlib/netlib_setnodeaddr.c @@ -49,6 +49,8 @@ #include #include +#include + #include "netutils/netlib.h" #if defined(CONFIG_NET_6LOWPAN) && CONFIG_NSOCKET_DESCRIPTORS > 0 @@ -65,7 +67,7 @@ * * Parameters: * ifname The name of the interface to use - * nodeaddr Node address to set, size must be CONFIG_NET_6LOWPAN_RIMEADDR_SIZE + * nodeaddr Node address to set, size must be NET_6LOWPAN_RIMEADDR_SIZE * * Return: * 0 on success; -1 on failure @@ -92,7 +94,7 @@ int netlib_setnodeaddr(FAR const char *ifname, FAR const uint8_t *nodeaddr) /* Put the new MAC address into the request */ req.ifr_hwaddr.sa_family = AF_INET6; - memcpy(&req.ifr_hwaddr.sa_data, nodeaddr, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE); + memcpy(&req.ifr_hwaddr.sa_data, nodeaddr, NET_6LOWPAN_RIMEADDR_SIZE); /* Perform the ioctl to set the MAC address */ diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 94e7e55d8..0231ef510 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -155,8 +155,9 @@ * domain sockets were enable. */ -#if !defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_LOOPBACK) && \ - !defined(CONFIG_NET_SLIP) && !defined(CONFIG_NET_TUN) +#if !defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_6LOWPAN) && \ + !defined(CONFIG_NET_LOOPBACK) && !defined(CONFIG_NET_SLIP) && \ + !defined(CONFIG_NET_TUN) /* No link layer protocol is a good indication that there is no network * device. */ diff --git a/nshlib/nsh_envcmds.c b/nshlib/nsh_envcmds.c index b323d9538..4d80e465c 100644 --- a/nshlib/nsh_envcmds.c +++ b/nshlib/nsh_envcmds.c @@ -316,15 +316,22 @@ int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) { FAR char *value; int ret = OK; +#ifndef CONFIG_DISABLE_ENVIRON int ndx = 1; +#endif #ifndef CONFIG_NSH_DISABLESCRIPT FAR char *popt; const char opts[] = NSH_NP_SET_OPTIONS; int op; +#ifndef CONFIG_DISABLE_ENVIRON /* Support set [{+|-}{e|x|xe|ex}] [ ] */ if (argc == 2 || argc == 4) +#else + /* Support set [{+|-}{e|x|xe|ex}] */ + +#endif { if (strlen(argv[1]) < 2) { @@ -362,17 +369,20 @@ int cmd_set(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) } } +#ifndef CONFIG_DISABLE_ENVIRON if (ret == OK) { ndx = 2; } +#endif } } } -# ifndef CONFIG_DISABLE_ENVIRON + +#ifndef CONFIG_DISABLE_ENVIRON if (ret == OK && (argc == 3 || argc == 4)) -# endif #endif +#endif /* CONFIG_NSH_DISABLESCRIPT */ #ifndef CONFIG_DISABLE_ENVIRON { /* Trim whitespace from the value */ diff --git a/nshlib/nsh_netcmds.c b/nshlib/nsh_netcmds.c index 592f02b3f..35f19354e 100644 --- a/nshlib/nsh_netcmds.c +++ b/nshlib/nsh_netcmds.c @@ -79,6 +79,10 @@ #include #include +#ifdef CONFIG_NET_6LOWPAN +#include +#endif + #if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) && \ !defined(CONFIG_DISABLE_SIGNALS) # include "netutils/netlib.h" @@ -252,7 +256,7 @@ static int ping_options(FAR struct nsh_vtbl_s *vtbl, /* There should be exactly on parameter left on the command-line */ - if (optind == argc-1) + if (optind == argc - 1) { *staddr = argv[optind]; } @@ -371,7 +375,7 @@ int tftpc_parseargs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv, /* There should be exactly one parameter left on the command-line */ - if (optind == argc-1) + if (optind == argc - 1) { args->srcpath = argv[optind]; } @@ -384,7 +388,7 @@ int tftpc_parseargs(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv, goto errout; } - /* optind < argc-1 means that there are too many arguments on the + /* optind < argc - 1 means that there are too many arguments on the * command-line */ @@ -744,7 +748,7 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) FAR char *gwip = NULL; FAR char *mask = NULL; FAR char *tmp = NULL; -#ifdef CONFIG_NET_ETHERNET +#if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_NET_6LOWPAN) FAR char *hw = NULL; #endif #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) @@ -754,7 +758,12 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) bool inet6 = false; #endif bool badarg = false; +#ifdef CONFIG_NET_ETHERNET uint8_t mac[IFHWADDRLEN]; +#endif +#ifdef CONFIG_NET_6LOWPAN + uint8_t nodeaddr[NET_6LOWPAN_RIMEADDR_SIZE]; +#endif #if defined(CONFIG_NSH_DHCPC) FAR void *handle; #endif @@ -802,9 +811,9 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) tmp = argv[i]; if (!strcmp(tmp, "dr") || !strcmp(tmp, "gw") || !strcmp(tmp, "gateway")) { - if (argc-1 >= i+1) + if (argc - 1 >= i + 1) { - gwip = argv[i+1]; + gwip = argv[i + 1]; i++; } else @@ -814,9 +823,9 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) } else if (!strcmp(tmp, "netmask")) { - if (argc-1 >= i+1) + if (argc - 1 >= i + 1) { - mask = argv[i+1]; + mask = argv[i + 1]; i++; } else @@ -841,16 +850,20 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #endif } -#ifdef CONFIG_NET_ETHERNET +#if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_NET_6LOWPAN) /* REVISIT: How will we handle Ethernet and SLIP networks together? */ else if (!strcmp(tmp, "hw")) { - if (argc-1>=i+1) + if (argc - 1 >= i + 1) { - hw = argv[i+1]; + hw = argv[i + 1]; i++; +#ifdef CONFIG_NET_ETHERNET badarg = !netlib_ethaddrconv(hw, mac); +#else + badarg = !netlib_nodeaddrconv(hw, nodeaddr); +#endif } else { @@ -862,9 +875,9 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) #if defined(CONFIG_NSH_DHCPC) || defined(CONFIG_NSH_DNS) else if (!strcmp(tmp, "dns")) { - if (argc-1 >= i+1) + if (argc - 1 >= i + 1) { - dns = argv[i+1]; + dns = argv[i + 1]; i++; } else @@ -883,14 +896,18 @@ int cmd_ifconfig(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) return ERROR; } -#ifdef CONFIG_NET_ETHERNET +#if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_NET_6LOWPAN) /* Set Hardware Ethernet MAC address */ /* REVISIT: How will we handle Ethernet and SLIP networks together? */ if (hw) { ninfo("HW MAC: %s\n", hw); +#ifdef CONFIG_NET_ETHERNET netlib_setmacaddr(intf, mac); +#else + netlib_setnodeaddr(intf, nodeaddr); +#endif } #endif @@ -1620,7 +1637,7 @@ int cmd_wget(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) /* There should be exactly on parameter left on the command-line */ - if (optind == argc-1) + if (optind == argc - 1) { url = argv[optind]; } diff --git a/nshlib/nsh_netinit.c b/nshlib/nsh_netinit.c index 38c862a30..f1f1f557f 100644 --- a/nshlib/nsh_netinit.c +++ b/nshlib/nsh_netinit.c @@ -72,6 +72,10 @@ # include "netutils/dhcpc.h" #endif +#ifdef CONFIG_NET_6LOWPAN +# include +#endif + #ifdef CONFIG_NETUTILS_NTPCLIENT # include "netutils/ntpclient.h" #endif @@ -90,9 +94,9 @@ #if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_NET_6LOWPAN) # define HAVE_MAC 1 # if defined(CONFIG_NET_6LOWPAN) -# if (CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2) && CONFIG_NSH_MACADDR > 0xffff +# if !defined(CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED) && CONFIG_NSH_MACADDR > 0xffff # error Invalid 6loWPAN node address for SIZE == 2 -# elif (CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 8) && CONFIG_NSH_MACADDR > 0xffffffffffffffffull +# elif defined(CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED) && CONFIG_NSH_MACADDR > 0xffffffffffffffffull # error Invalid 6loWPAN node address for SIZE == 8 # endif # endif @@ -249,7 +253,7 @@ static void nsh_netinit_configure(void) #if defined(CONFIG_NET_ETHERNET) uint8_t mac[IFHWADDRLEN]; #elif defined(CONFIG_NET_6LOWPAN) - uint8_t nodeaddr[CONFIG_NET_6LOWPAN_RIMEADDR_SIZE]; + uint8_t nodeaddr[NET_6LOWPAN_RIMEADDR_SIZE]; #endif #endif @@ -275,10 +279,7 @@ static void nsh_netinit_configure(void) #elif defined(CONFIG_NET_6LOWPAN) /* Use the configured, fixed MAC address */ -#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2 - nodeaddr[0] = (CONFIG_NSH_MACADDR >> (8 * 1)) & 0xff; - nodeaddr[1] = (CONFIG_NSH_MACADDR >> (8 * 0)) & 0xff; -#elif CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 8 +#ifdef CONFIG_NET_6LOWPAN_RIMEADDR_EXTENDED nodeaddr[0] = (CONFIG_NSH_MACADDR >> (8 * 7)) & 0xff; nodeaddr[1] = (CONFIG_NSH_MACADDR >> (8 * 6)) & 0xff; nodeaddr[2] = (CONFIG_NSH_MACADDR >> (8 * 5)) & 0xff; @@ -287,6 +288,9 @@ static void nsh_netinit_configure(void) nodeaddr[5] = (CONFIG_NSH_MACADDR >> (8 * 2)) & 0xff; nodeaddr[6] = (CONFIG_NSH_MACADDR >> (8 * 1)) & 0xff; nodeaddr[7] = (CONFIG_NSH_MACADDR >> (8 * 0)) & 0xff; +#else + nodeaddr[0] = (CONFIG_NSH_MACADDR >> (8 * 1)) & 0xff; + nodeaddr[1] = (CONFIG_NSH_MACADDR >> (8 * 0)) & 0xff; #endif /* Set the 6loWPAN node address */ diff --git a/wireless/.gitignore b/wireless/.gitignore new file mode 100644 index 000000000..99f41601f --- /dev/null +++ b/wireless/.gitignore @@ -0,0 +1,2 @@ +/Kconfig + diff --git a/wireless/Make.defs b/wireless/Make.defs new file mode 100644 index 000000000..6f5bcf9f7 --- /dev/null +++ b/wireless/Make.defs @@ -0,0 +1,37 @@ +############################################################################ +# apps/wireless/Make.defs +# Adds selected applications to apps/ build +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +# COPYRIGHT OWNER 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 $(wildcard wireless/*/Make.defs) diff --git a/wireless/Makefile b/wireless/Makefile new file mode 100644 index 000000000..363f15cd6 --- /dev/null +++ b/wireless/Makefile @@ -0,0 +1,38 @@ +############################################################################ +# apps/wireless/Makefile +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +# COPYRIGHT OWNER 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. +# +############################################################################ + +MENUDESC = "Wireless Libraries and NSH Add-Ons" + +include $(APPDIR)/Directory.mk diff --git a/wireless/wapi/.gitignore b/wireless/wapi/.gitignore new file mode 100644 index 000000000..f21c854d1 --- /dev/null +++ b/wireless/wapi/.gitignore @@ -0,0 +1,6 @@ +/.built +/.depend +/Make.dep +/*.src +/*.obj +/*.lst diff --git a/wireless/wapi/Kconfig b/wireless/wapi/Kconfig new file mode 100644 index 000000000..249a1593d --- /dev/null +++ b/wireless/wapi/Kconfig @@ -0,0 +1,40 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig WIRELESS_WAPI + bool "IEEE802.11 Configuration Library" + default n + depends on NET && DRIVERS_WIRELESS && EXPERIMENTAL + ---help--- + Wapi is a tool by Volkan YAZICI that can + be used to manage 802.11 network. + +if WIRELESS_WAPI + +config WIRELESS_WAPI_CMDTOOL + bool "IEEE802.11 Command Line Tool" + default n + ---help--- + By default, Wapi is build as only a library. If this option is + selected than a simple command line tool that can be ran from NSH + will also be generated. + +config WIRELESS_WAPI_PROGNAME + string "Program Name" + default "wapi" + depends on BUILD_KERNEL + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config WIRELESS_WAPI_STACKSIZE + int "Stack Size (bytes)" + default 2048 + +config WIRELESS_WAPI_PRIORITY + int "Command Priority" + default 100 + +endif diff --git a/wireless/wapi/LICENSE b/wireless/wapi/LICENSE new file mode 100644 index 000000000..eeb3ddaae --- /dev/null +++ b/wireless/wapi/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2010, Volkan YAZICI +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. diff --git a/wireless/wapi/Make.defs b/wireless/wapi/Make.defs new file mode 100644 index 000000000..f8cf01b20 --- /dev/null +++ b/wireless/wapi/Make.defs @@ -0,0 +1,40 @@ +############################################################################ +# apps/wireless/wapi/Make.defs +# Adds selected applications to apps/ build +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +# COPYRIGHT OWNER 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. +# +############################################################################ + +ifeq ($(CONFIG_WIRELESS_WAPI),y) +CONFIGURED_APPS += wireless/wapi +endif + diff --git a/wireless/wapi/Makefile b/wireless/wapi/Makefile new file mode 100644 index 000000000..03de538c9 --- /dev/null +++ b/wireless/wapi/Makefile @@ -0,0 +1,149 @@ +############################################################################ +# apps/wireless/wapi/Makefile +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +# COPYRIGHT OWNER 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. +# +############################################################################ + +# TODO, this makefile should run make under the app dirs, instead of +# sourcing the Make.defs! + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# IEEE802.11 Wapi Application + +CONFIG_WIRELESS_WAPI_PRIORITY ?= 100 +CONFIG_WIRELESS_WAPI_STACKSIZE ?= 2048 + +APPNAME = wapi +PRIORITY = $(CONFIG_WIRELESS_WAPI_PRIORITY) +STACKSIZE = $(CONFIG_WIRELESS_WAPI_STACKSIZE) + +ASRCS = +CSRCS = +MAINSRC = + +VPATH = . + +include $(APPDIR)/wireless/wapi/src/Make.defs + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) +OBJS = $(AOBJS) $(COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +CONFIG_WAPI_PROGNAME ?= wapi$(EXEEXT) +PROGNAME = $(CONFIG_WAPI_PROGNAME) + +ROOTDEPPATH = --dep-path . + +# Common build + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + $(Q) touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) +$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) + @echo "LD: $(PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(PROGNAME) + +else +install: + +endif + +# Register application + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat +else +context: +endif + +# Create dependencies + +.depend: Makefile $(SRCS) + $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + $(Q) touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep +.PHONY: preconfig +preconfig: diff --git a/wireless/wapi/README b/wireless/wapi/README new file mode 100644 index 000000000..41cafb9c2 --- /dev/null +++ b/wireless/wapi/README @@ -0,0 +1,42 @@ + + `_`_`_`_____`_____`__` + |`|`|`|``_``|``_``|``| + |`|`|`|`````|```__|``| + |_____|__|__|__|``|__| + +WAPI (Wireless API) provides an easy-to-use function set to configure wireless +network interfaces on a GNU/Linux system. One can think WAPI as a lightweight C +API for iwconfig, wlanconfig, ifconfig, and route commands. (But it is not a +thin wrapper for these command line tools.) It is designed to be used in +wireless heteregenous network research projects and supported by BWRC (Berkeley +Wireless Research Center) and WISERLAB (Wireless Information Systems Engineering +Research Laboratory at Özyeğin University). + +For source codes, see http://github.com/vy/wapi. The most recent version of the +documentation is (hopefully) always available at http://vy.github.com/wapi. + +--- L I C E N S E -------------------------------------------------------------- + +Copyright (c) 2010, Volkan YAZICI +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. diff --git a/wireless/wapi/src/Make.defs b/wireless/wapi/src/Make.defs new file mode 100644 index 000000000..95100bb1c --- /dev/null +++ b/wireless/wapi/src/Make.defs @@ -0,0 +1,49 @@ +############################################################################ +# apps/wireless/src/Make.defs +# +# Copyright (C) 2017 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +# COPYRIGHT OWNER 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. +# +############################################################################ + +ifeq ($(CONFIG_WIRELESS_WAPI),y) + +CSRCS = network.c util.c wireless.c + +ifeq ($(CONFIG_WIRELESS_WAPI_CMDTOOL),y) +MAINSRC = wapi.c +endif + +DEPPATH += --dep-path src +VPATH += :src +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/wireless/wapi/src} + +endif + diff --git a/wireless/wapi/src/network.c b/wireless/wapi/src/network.c new file mode 100644 index 000000000..a2e2a1b9a --- /dev/null +++ b/wireless/wapi/src/network.c @@ -0,0 +1,329 @@ +/**************************************************************************** + * apps/wireless/wapi/examples/network.c + * + * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Adapted for Nuttx from WAPI: + * + * Copyright (c) 2010, Volkan YAZICI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "util.h" +#include "wireless/wapi.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int wapi_get_addr(int sock, FAR const char *ifname, int cmd, + FAR struct in_addr *addr) +{ + struct ifreq ifr; + int ret; + + WAPI_VALIDATE_PTR(addr); + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, cmd, (unsigned long)((uintptr_t)&ifr))) >= 0) + { + struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; + memcpy(addr, &sin->sin_addr, sizeof(struct in_addr)); + } + else + { + WAPI_IOCTL_STRERROR(cmd); + } + + return ret; +} + +static int wapi_set_addr(int sock, FAR const char *ifname, int cmd, + FAR const struct in_addr *addr) +{ + struct sockaddr_in sin; + struct ifreq ifr; + int ret; + + WAPI_VALIDATE_PTR(addr); + + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr, addr, sizeof(struct in_addr)); + memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr_in)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, cmd, (unsigned long)((uintptr_t)&ifr))) < 0) + { + WAPI_IOCTL_STRERROR(cmd); + } + + return ret; +} + +#ifdef CONFIG_NET_ROUTE +static int wapi_act_route_gw(int sock, int act, + wapi_route_target_t targettype, + FAR const struct in_addr *target, + FAR const struct in_addr *netmask, + FAR const struct in_addr *gw) +{ + int ret; + struct rtentry rt; + FAR struct sockaddr_in *sin; + + /* Clean out rtentry. */ + + bzero(&rt, sizeof(struct rtentry)); + + /* Set target. */ + + sin = (struct sockaddr_in *)&rt.rt_dst; + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr, target, sizeof(struct in_addr)); + + /* Set netmask. */ + + sin = (struct sockaddr_in *)&rt.rt_genmask; + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr, netmask, sizeof(struct in_addr)); + + /* Set gateway. */ + + sin = (struct sockaddr_in *)&rt.rt_gateway; + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr, gw, sizeof(struct in_addr)); + + /* Set rt_flags. */ + + rt.rt_flags = RTF_UP | RTF_GATEWAY; + if (targettype == WAPI_ROUTE_TARGET_HOST) + { + rt.rt_flags |= RTF_HOST; + } + + if ((ret = ioctl(sock, act, (unsigned long)((uintptr_t)&rt))) < 0) + { + WAPI_IOCTL_STRERROR(act); + } + + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wapi_get_ifup + * + * Description: + * Gets the interface up status. + * + * Input Parameters: + * is_up Set to 0, if up; 1, otherwise. + * + ****************************************************************************/ + +int wapi_get_ifup(int sock, FAR const char *ifname, FAR int *is_up) +{ + struct ifreq ifr; + int ret; + + WAPI_VALIDATE_PTR(is_up); + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIFFLAGS, (unsigned long)((uintptr_t)&ifr))) >= 0) + { + *is_up = (ifr.ifr_flags & IFF_UP) == IFF_UP; + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIFFLAGS); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_ifup + * + * Description: + * Activates the interface. + * + ****************************************************************************/ + +int wapi_set_ifup(int sock, FAR const char *ifname) +{ + struct ifreq ifr; + int ret; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIFFLAGS, (unsigned long)((uintptr_t)&ifr))) >= 0) + { + ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); + ret = ioctl(sock, SIOCSIFFLAGS, (unsigned long)((uintptr_t)&ifr)); + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIFFLAGS); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_ifdown + * + * Description: + * Shuts down the interface. + * + ****************************************************************************/ + +int wapi_set_ifdown(int sock, FAR const char *ifname) +{ + struct ifreq ifr; + int ret; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIFFLAGS, (unsigned long)((uintptr_t)&ifr))) >= 0) + { + ifr.ifr_flags &= ~IFF_UP; + ret = ioctl(sock, SIOCSIFFLAGS, (unsigned long)((uintptr_t)&ifr)); + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIFFLAGS); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_get_ip + * + * Description: + * Gets IP address of the given network interface. + * + ****************************************************************************/ + +int wapi_get_ip(int sock, FAR const char *ifname, FAR struct in_addr *addr) +{ + return wapi_get_addr(sock, ifname, SIOCGIFADDR, addr); +} + +/**************************************************************************** + * Name: wapi_set_ip + * + * Description: + * Sets IP adress of the given network interface. + * + ****************************************************************************/ + +int wapi_set_ip(int sock, FAR const char *ifname, + FAR const struct in_addr *addr) +{ + return wapi_set_addr(sock, ifname, SIOCSIFADDR, addr); +} + +/**************************************************************************** + * Name: wapi_set_netmask + * + * Description: + * Sets netmask of the given network interface. + * + ****************************************************************************/ + +int wapi_get_netmask(int sock, FAR const char *ifname, + FAR struct in_addr *addr) +{ + return wapi_get_addr(sock, ifname, SIOCGIFNETMASK, addr); +} + +/**************************************************************************** + * Name: wapi_set_netmask + * + * Description: + * Sets netmask of the given network interface. + * + ****************************************************************************/ + +int wapi_set_netmask(int sock, FAR const char *ifname, + FAR const struct in_addr *addr) +{ + return wapi_set_addr(sock, ifname, SIOCSIFNETMASK, addr); +} + +/**************************************************************************** + * Name: wapi_add_route_gw + * + * Description: + * Adds gateway for the given target network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ROUTE +int wapi_add_route_gw(int sock, wapi_route_target_t targettype, + FAR const struct in_addr *target, + FAR const struct in_addr *netmask, + FAR const struct in_addr *gw) +{ + return wapi_act_route_gw(sock, SIOCADDRT, targettype, target, netmask, gw); +} +#endif + +/**************************************************************************** + * Name: wapi_del_route_gw + * + * Description: + * Deletes gateway for the given target network. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ROUTE +int wapi_del_route_gw(int sock, wapi_route_target_t targettype, + FAR const struct in_addr *target, + FAR const struct in_addr *netmask, + FAR const struct in_addr *gw) +{ + return wapi_act_route_gw(sock, SIOCDELRT, targettype, target, netmask, gw); +} +#endif diff --git a/wireless/wapi/src/util.c b/wireless/wapi/src/util.c new file mode 100644 index 000000000..28dd7b600 --- /dev/null +++ b/wireless/wapi/src/util.c @@ -0,0 +1,182 @@ +/**************************************************************************** + * apps/wireless/wapi/src/util.c + * + * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Adapted for Nuttx from WAPI: + * + * Copyright (c) 2010, Volkan YAZICI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "wireless/wapi.h" +#include "util.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The address family that we used to create the socket really does not + * matter. It should, however, be valid in the current configuration. + */ + +#if defined(CONFIG_NET_IPv4) +# define PF_INETX PF_INET +#elif defined(CONFIG_NET_IPv6) +# define PF_INETX PF_INET6 +#endif + +/* SOCK_DGRAM is the preferred socket type to use when we just want a + * socket for performing driver ioctls. However, we can't use SOCK_DRAM + * if UDP is disabled. + */ + +#ifdef CONFIG_NET_UDP +# define SOCK_WAPI SOCK_DGRAM +#else +# define SOCK_WAPI SOCK_STREAM +#endif + +/* Size of the command buffer */ + +#define WAPI_IOCTL_COMMAND_NAMEBUFSIZ 24 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +static char g_ioctl_command_namebuf[WAPI_IOCTL_COMMAND_NAMEBUFSIZ]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wapi_make_socket + * + * Description: + * Creates an AF_INET socket to be used in ioctl() calls. + * + * Returned Value: + * Non-negative on success. + * + ****************************************************************************/ + +int wapi_make_socket(void) +{ + return socket(PF_INETX, SOCK_WAPI, 0); +} + +/**************************************************************************** + * Name: wapi_ioctl_command_name + * + * Description: + * Return name string for IOCTL command + * + * Returned Value: + * Name string for IOCTL command + * + ****************************************************************************/ + +FAR const char *wapi_ioctl_command_name(int cmd) +{ + switch (cmd) + { + case SIOCADDRT: + return "SIOCADDRT"; + + case SIOCDELRT: + return "SIOCDELRT"; + + case SIOCGIFADDR: + return "SIOCGIFADDR"; + + case SIOCGIWAP: + return "SIOCGIWAP"; + + case SIOCGIWESSID: + return "SIOCGIWESSID"; + + case SIOCGIWFREQ: + return "SIOCGIWFREQ"; + + case SIOCGIWMODE: + return "SIOCGIWMODE"; + + case SIOCGIWRANGE: + return "SIOCGIWRANGE"; + + case SIOCGIWRATE: + return "SIOCGIWRATE"; + + case SIOCGIWSCAN: + return "SIOCGIWSCAN"; + + case SIOCGIWTXPOW: + return "SIOCGIWTXPOW"; + + case SIOCSIFADDR: + return "SIOCSIFADDR"; + + case SIOCSIWAP: + return "SIOCSIWAP"; + + case SIOCSIWESSID: + return "SIOCSIWESSID"; + + case SIOCSIWFREQ: + return "SIOCSIWFREQ"; + + case SIOCSIWMODE: + return "SIOCSIWMODE"; + + case SIOCSIWRATE: + return "SIOCSIWRATE"; + + case SIOCSIWSCAN: + return "SIOCSIWSCAN"; + + case SIOCSIWTXPOW: + return "SIOCSIWTXPOW"; + + default: + snprintf(g_ioctl_command_namebuf, WAPI_IOCTL_COMMAND_NAMEBUFSIZ, + "0x%x", cmd); + return g_ioctl_command_namebuf; + } +} diff --git a/wireless/wapi/src/util.h b/wireless/wapi/src/util.h new file mode 100644 index 000000000..e7c304f7f --- /dev/null +++ b/wireless/wapi/src/util.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * apps/wireless/wapi/src/util.h + * + * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Adapted for Nuttx from WAPI: + * + * Copyright (c) 2010, Volkan YAZICI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +#ifndef __APPS_WIRELESS_WAPI_SRC_UTIL_H +#define __APPS_WIRELESS_WAPI_SRC_UTIL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef DEBUG_WIRELESS_ERROR +# ifdef CONFIG_LIBC_STRERROR +# define WAPI_IOCTL_STRERROR(cmd) \ + fprintf( \ + stderr, "%s:%d:%s():ioctl(%s): %s\n", \ + __FILE__, __LINE__, __func__, \ + wapi_ioctl_command_name(cmd), strerror(errno)) + +# define WAPI_STRERROR(fmt, ...) \ + fprintf( \ + stderr, "%s:%d:%s():" fmt ": %s\n", \ + __FILE__, __LINE__, __func__, \ + ## __VA_ARGS__, strerror(errno)) +# else +# define WAPI_IOCTL_STRERROR(cmd) \ + fprintf( \ + stderr, "%s:%d:%s():ioctl(%s): %d\n", \ + __FILE__, __LINE__, __func__, \ + wapi_ioctl_command_name(cmd), errno) + +# define WAPI_STRERROR(fmt, ...) \ + fprintf( \ + stderr, "%s:%d:%s():" fmt ": %d\n", \ + __FILE__, __LINE__, __func__, \ + ## __VA_ARGS__, errno) +# endif + +# define WAPI_ERROR(fmt, ...) \ + fprintf( \ + stderr, "%s:%d:%s(): " fmt , \ + __FILE__, __LINE__, __func__, ## __VA_ARGS__) + +#else +# ifdef CONFIG_LIBC_STRERROR +# define WAPI_IOCTL_STRERROR(cmd) \ + fprintf( \ + stderr, "ioctl(%s): %s\n", \ + wapi_ioctl_command_name(cmd), strerror(errno)) + +# define WAPI_STRERROR(fmt, ...) \ + fprintf( \ + stderr, fmt ": %s\n", \ + ## __VA_ARGS__, strerror(errno)) +# else +# define WAPI_IOCTL_STRERROR(cmd) \ + fprintf( \ + stderr, "ioctl(%s): %d\n", \ + wapi_ioctl_command_name(cmd), errno) + +# define WAPI_STRERROR(fmt, ...) \ + fprintf( \ + stderr, fmt ": %d\n", \ + ## __VA_ARGS__, errno) +# endif + +# define WAPI_ERROR(fmt, ...) \ + fprintf( \ + stderr, fmt , \ + ## __VA_ARGS__) + +#endif + +#define WAPI_VALIDATE_PTR(ptr) \ + if (ptr == NULL) \ + { \ + WAPI_ERROR("Null pointer: %p\n", ptr); \ + return -EINVAL; \ + } + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +FAR const char *wapi_ioctl_command_name(int cmd); + +#endif /* __APPS_WIRELESS_WAPI_SRC_UTIL_H */ diff --git a/wireless/wapi/src/wapi.c b/wireless/wapi/src/wapi.c new file mode 100644 index 000000000..a5f53c2d2 --- /dev/null +++ b/wireless/wapi/src/wapi.c @@ -0,0 +1,863 @@ +/**************************************************************************** + * apps/wireless/wapi/src/wapi.c + * + * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Largely and original work, but highly influenced by sampled code provided + * with WAPI: + * + * Copyright (c) 2010, Volkan YAZICI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "wireless/wapi.h" +#include "util.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Describes one command */ + +struct wapi_command_s +{ + FAR const char *name; + uint8_t noptions; + CODE void *handler; +}; + +/* Generic form of a commnd handler */ + +typedef void (*cmd1_t)(int sock, FAR const char *arg1); +typedef void (*cmd2_t)(int sock, FAR const char *arg1, + FAR const char *arg2); +typedef void (*cmd3_t)(int sock, FAR const char *arg1, + FAR const char *arg2, FAR const char *arg3); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int wapi_str2int(FAR const char *str); +static double wapi_str2double(FAR const char *str); +static unsigned int wapi_str2ndx(FAR const char *name, FAR const char **list, + unsigned int listlen); + +static void wapi_show_cmd(int sock, FAR const char *ifname); +static void wapi_ip_cmd(int sock, FAR const char *ifname, + FAR const char *addrstr); +static void wapi_mask_cmd(int sock, FAR const char *ifname, + FAR const char *maskstr); +static void wapi_freq_cmd(int sock, FAR const char *ifname, + FAR const char *freqstr, FAR const char *flagstr); +static void wapi_essid_cmd(int sock, FAR const char *ifname, + FAR const char *essid, FAR const char *flagstr); +static void wapi_mode_cmd(int sock, FAR const char *ifname, + FAR const char *modestr); +static void wapi_ap_cmd(int sock, FAR const char *ifname, + FAR const char *macstr); +static void wapi_bitrate_cmd(int sock, FAR const char *ifname, + FAR const char *ratestr, FAR const char *flagstr); +static void wapi_txpower_cmd(int sock, FAR const char *ifname, + FAR const char *pwrstr, FAR const char *flagstr); +static void wapi_scan_cmd(int sock, FAR const char *ifname); + +static void wapi_showusage(FAR const char *progname, int exitcode); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct wapi_command_s g_wapi_commands[] = +{ + {"help", 0, (CODE void *)NULL}, + {"show", 1, (CODE void *)wapi_show_cmd}, + {"scan", 1, (CODE void *)wapi_scan_cmd}, + {"ip", 2, (CODE void *)wapi_ip_cmd}, + {"mask", 2, (CODE void *)wapi_mask_cmd}, + {"freq", 3, (CODE void *)wapi_freq_cmd}, + {"essid", 3, (CODE void *)wapi_essid_cmd}, + {"mode", 2, (CODE void *)wapi_mode_cmd}, + {"ap", 2, (CODE void *)wapi_ap_cmd}, + {"bitrate", 3, (CODE void *)wapi_bitrate_cmd}, + {"txpower", 3, (CODE void *)wapi_txpower_cmd}, +}; + +#define NCOMMANDS (sizeof(g_wapi_commands) / sizeof(struct wapi_command_s)) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wapi_str2int + * + * Description: + * Convert a string to an integer value + * + ****************************************************************************/ + +static int wapi_str2int(FAR const char *str) +{ + FAR char *endptr; + long value; + + value = strtol(str, &endptr, 0); + if (*endptr != '\0') + { + WAPI_ERROR("ERROR: Garbage after numeric argument\n"); + exit(EXIT_FAILURE); + } + + if (value > INT_MAX || value < INT_MIN) + { + WAPI_ERROR("ERROR: Integer value out of range\n"); + exit(EXIT_FAILURE); + } + + return (int)value; +} + +/**************************************************************************** + * Name: wapi_str2double + * + * Description: + * Convert a string to a double value + * + ****************************************************************************/ + +static double wapi_str2double(FAR const char *str) +{ + FAR char *endptr; + double value; + + value = strtod(str, &endptr); + if (*endptr != '\0') + { + WAPI_ERROR("ERROR: Garbage after numeric argument\n"); + exit(EXIT_FAILURE); + } + + return value; +} + +/**************************************************************************** + * Name: wapi_str2ndx + * + * Description: + * Return the index of a string in a list of strings + * + ****************************************************************************/ + +static unsigned int wapi_str2ndx(FAR const char *name, FAR const char **list, + unsigned int listlen) +{ + unsigned int ndx; + + for (ndx = 0; ndx < listlen; ndx++) + { + if (strcmp(name, list[ndx]) == 0) + { + return ndx; + } + } + + WAPI_ERROR("ERROR: Invalid option string: %s\n", name); + WAPI_ERROR(" Valid options include:\n"); + for (ndx = 0; ndx < listlen; ndx++) + { + WAPI_ERROR(" - %s\n", list[ndx]); + } + + exit(EXIT_FAILURE); +} + +/**************************************************************************** + * Name: wapi_show_cmd + * + * Description: + * Gets current configuration of the ifname using WAPI accessors and prints + * them in a pretty fashion with their corresponding return values. If a + * getter succeeds, we try to set that property with the same value to test + * the setters as well. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_show_cmd(int sock, FAR const char *ifname) +{ + struct in_addr addr; + + double freq; + wapi_freq_flag_t freq_flag; + + char essid[WAPI_ESSID_MAX_SIZE + 1]; + wapi_essid_flag_t essid_flag; + + wapi_mode_t mode; + + struct ether_addr ap; + + int bitrate; + wapi_bitrate_flag_t bitrate_flag; + + int txpower; + wapi_txpower_flag_t txpower_flag; + + int ret; + + printf("%s Configuration:\n", ifname); + + /* Get ip */ + + bzero(&addr, sizeof(struct in_addr)); + ret = wapi_get_ip(sock, ifname, &addr); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_ip() failed: %d\n", ret); + } + else + { + printf(" IP: %s\n", inet_ntoa(addr)); + } + + /* Get netmask */ + + bzero(&addr, sizeof(struct in_addr)); + ret = wapi_get_netmask(sock, ifname, &addr); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_netmask() failed: %d\n", ret); + } + else + { + printf(" NetMask: %s", inet_ntoa(addr)); + } + + /* Get frequency */ + + ret = wapi_get_freq(sock, ifname, &freq, &freq_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_freq() failed: %d\n", ret); + } + else + { + double tmpfreq; + int chan; + + printf("Frequency: %g\n", freq); + printf(" Flag: %s\n", g_wapi_freq_flags[freq_flag]); + + ret = wapi_freq2chan(sock, ifname, freq, &chan); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_freq2chan() failed: %d\n", ret); + } + else + { + printf(" Channel: %d\n", chan); + } + + ret = wapi_chan2freq(sock, ifname, chan, &tmpfreq); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_chan2freq() failed: %d\n", ret); + } + else + { + printf("Frequency: %g\n", tmpfreq); + } + } + + /* Get the ESSID */ + + ret = wapi_get_essid(sock, ifname, essid, &essid_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_essid() failed: %d\n", ret); + } + else + { + printf(" ESSID: %s\n", essid); + printf(" Flag: %s\n", g_wapi_essid_flags[essid_flag]); + } + + /* Get operating mode */ + + ret = wapi_get_mode(sock, ifname, &mode); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_mode() failed: %d\n", ret); + } + else + { + printf(" Mode: %s", g_wapi_modes[mode]); + } + + /* Get AP */ + + ret = wapi_get_ap(sock, ifname, &ap); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_ap() failed: %d\n", ret); + } + else + { + printf(" AP: %02x:%02x:%02x:%02x:%02x:%02x\n", + ap.ether_addr_octet[0], ap.ether_addr_octet[1], + ap.ether_addr_octet[2], ap.ether_addr_octet[3], + ap.ether_addr_octet[4], ap.ether_addr_octet[5]); + } + + /* Get bitrate */ + + ret = wapi_get_bitrate(sock, ifname, &bitrate, &bitrate_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_bitrate() failed: %d\n", ret); + } + else + { + printf(" BitRate: %d\n", bitrate); + printf(" Flag: %s\n", g_wapi_bitrate_flags[bitrate_flag]); + } + + /* Get txpower */ + + ret = wapi_get_txpower(sock, ifname, &txpower, &txpower_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_get_txpower() failed: %d\n", ret); + } + else + { + printf(" TxPower: %d\n", txpower); + printf(" Flag: %s\n", g_wapi_txpower_flags[txpower_flag]); + } +} + +/**************************************************************************** + * Name: wapi_ip_cmd + * + * Description: + * Set the IP address. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_ip_cmd(int sock, FAR const char *ifname, + FAR const char *addrstr) +{ + struct in_addr addr; + int ret; + + /* Format the request */ + + addr.s_addr = inet_addr(addrstr); + + /* Set the IP address */ + + ret = wapi_set_ip(sock, ifname, &addr); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_set_ip() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_mask_cmd + * + * Description: + * Set the network mask + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_mask_cmd(int sock, FAR const char *ifname, + FAR const char *maskstr) +{ + struct in_addr addr; + int ret; + + /* Format the request */ + + addr.s_addr = inet_addr(maskstr); + + /* Set the network mask */ + + ret = wapi_set_netmask(sock, ifname, &addr); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_set_netmask() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_freq_cmd + * + * Description: + * Set the frequency + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_freq_cmd(int sock, FAR const char *ifname, + FAR const char *freqstr, FAR const char *flagstr) +{ + double frequency; + wapi_freq_flag_t freq_flag; + int ret; + + /* Convert input strings to values */ + + frequency = wapi_str2double(freqstr); + freq_flag = (wapi_freq_flag_t)wapi_str2ndx(flagstr, g_wapi_freq_flags, + IW_FREQ_NFLAGS); + + /* Set the frequency */ + + ret = wapi_set_freq(sock, ifname, frequency, freq_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: \nwapi_set_freq() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_essid_cmd + * + * Description: + * Set the ESSID + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_essid_cmd(int sock, FAR const char *ifname, + FAR const char *essid, FAR const char *flagstr) +{ + wapi_essid_flag_t essid_flag; + int ret; + + /* Convert input strings to values */ + + essid_flag = (wapi_essid_flag_t)wapi_str2ndx(flagstr, g_wapi_essid_flags, 2); + + /* Set the ESSID */ + + ret = wapi_set_essid(sock, ifname, essid, essid_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_set_essid() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_mode_cmd + * + * Description: + * Set the operating mode + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_mode_cmd(int sock, FAR const char *ifname, + FAR const char *modestr) +{ + wapi_mode_t mode; + int ret; + + /* Convert input strings to values */ + + mode = (wapi_mode_t)wapi_str2ndx(modestr, g_wapi_modes, IW_MODE_NFLAGS); + + /* Set operating mode */ + + ret = wapi_set_mode(sock, ifname, mode); + if (ret < 0) + { + WAPI_ERROR("ERROR: \nwapi_set_mode() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_ap_cmd + * + * Description: + * Set the AP + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_ap_cmd(int sock, FAR const char *ifname, + FAR const char *macstr) +{ + struct ether_addr ap; + int ret; + + /* Convert input strings to values */ + + sscanf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", + &ap.ether_addr_octet[0], &ap.ether_addr_octet[1], + &ap.ether_addr_octet[2], &ap.ether_addr_octet[3], + &ap.ether_addr_octet[4], &ap.ether_addr_octet[5]); + + /* Set ap */ + + ret = wapi_set_ap(sock, ifname, &ap); + if (ret < 0) + { + WAPI_ERROR("ERROR: \nwapi_set_ap() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_bitrate_cmd + * + * Description: + * Set the bit rate + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_bitrate_cmd(int sock, FAR const char *ifname, + FAR const char *ratestr, FAR const char *flagstr) + +{ + wapi_bitrate_flag_t bitrate_flag; + int bitrate; + int ret; + + /* Convert input strings to values */ + + bitrate = wapi_str2int(ratestr); + bitrate_flag = (wapi_bitrate_flag_t) + wapi_str2ndx(flagstr, g_wapi_bitrate_flags, 2); + + /* Set bitrate */ + + ret = wapi_set_bitrate(sock, ifname, bitrate, bitrate_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: \nwapi_set_bitrate() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_txpower_cmd + * + * Description: + * Set the TX power + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_txpower_cmd(int sock, FAR const char *ifname, + FAR const char *pwrstr, FAR const char *flagstr) +{ + wapi_txpower_flag_t txpower_flag; + int txpower; + int ret; + + /* Convert input strings to values */ + + txpower = wapi_str2int(pwrstr); + txpower_flag = (wapi_txpower_flag_t) + wapi_str2ndx(flagstr, g_wapi_txpower_flags, IW_TXPOW_NFLAGS); + + /* Set txpower */ + + ret = wapi_set_txpower(sock, ifname, txpower, txpower_flag); + if (ret < 0) + { + WAPI_ERROR("ERROR: \nwapi_set_txpower() failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: wapi_scan_cmd + * + * Description: + * Scans available APs in the range using given ifname interface. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_scan_cmd(int sock, FAR const char *ifname) +{ + int sleepdur = 1; + int sleeptries = 5; + wapi_list_t list; + FAR wapi_scan_info_t *info; + int ret; + + /* Start scan */ + + ret = wapi_scan_init(sock, ifname); + WAPI_ERROR("ERROR: wapi_scan_init() failed: %d\n", ret); + + /* Wait for completion */ + + do + { + sleep(sleepdur); + ret = wapi_scan_stat(sock, ifname); + WAPI_ERROR("ERROR: wapi_scan_stat() failed: %d, sleeptries: %d\n", + ret, sleeptries); + } + while (--sleeptries > 0 && ret > 0); + + if (ret < 0) + { + return; + } + + /* Collect results */ + + bzero(&list, sizeof(wapi_list_t)); + ret = wapi_scan_coll(sock, ifname, &list); + if (ret < 0) + { + WAPI_ERROR("ERROR: wapi_scan_coll() failed: %d\n", ret); + } + + /* Print found aps */ + + for (info = list.head.scan; info; info = info->next) + { + printf(" %02x:%02x:%02x:%02x:%02x:%02x %s\n", + info->ap.ether_addr_octet[0], info->ap.ether_addr_octet[1], + info->ap.ether_addr_octet[2], info->ap.ether_addr_octet[3], + info->ap.ether_addr_octet[4], info->ap.ether_addr_octet[5], + (info->has_essid ? info->essid : "")); + } + + /* Free ap list */ + + info = list.head.scan; + while (info) + { + FAR wapi_scan_info_t *temp; + + temp = info->next; + free(info); + info = temp; + } +} + +/**************************************************************************** + * Name: wapi_showusage + * + * Description: + * Show program usage. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void wapi_showusage(FAR const char *progname, int exitcode) +{ + int i; + + fprintf(stderr, "Usage: %s show \n", progname); + fprintf(stderr, " %s scan \n", progname); + fprintf(stderr, " %s ip \n", progname); + fprintf(stderr, " %s mask \n", progname); + fprintf(stderr, " %s freq \n", progname); + fprintf(stderr, " %s essid \n", progname); + fprintf(stderr, " %s mode \n", progname); + fprintf(stderr, " %s ap \n", progname); + fprintf(stderr, " %s bitrate \n", progname); + fprintf(stderr, " %s txpower \n", progname); + fprintf(stderr, " %s help\n", progname); + + fprintf(stderr, "\nFrequency Flags:\n"); + for (i = 0; i < IW_FREQ_NFLAGS; i++) + { + fprintf(stderr, " %s\n", g_wapi_freq_flags[i]); + } + + fprintf(stderr, "\nESSID Flags:\n"); + for (i = 0; i < 2; i++) + { + fprintf(stderr, " %s\n", g_wapi_essid_flags[i]); + } + + fprintf(stderr, "\nOperating Modes:\n"); + for (i = 0; i < IW_MODE_NFLAGS; i++) + { + fprintf(stderr, " %s\n", g_wapi_modes[i]); + } + + fprintf(stderr, "\nBitrate Flags:\n"); + for (i = 0; i < 2; i++) + { + fprintf(stderr, " %s\n", g_wapi_bitrate_flags[i]); + } + + fprintf(stderr, "\nTX power Flags:\n"); + for (i = 0; i < IW_TXPOW_NFLAGS; i++) + { + fprintf(stderr, " %s\n", g_wapi_txpower_flags[i]); + } + + exit(exitcode); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +int wapi_main(int argc, char *argv[]) +#endif +{ + FAR const char *cmdname; + FAR const struct wapi_command_s *wapicmd; + int sock; + int i; + + /* Get the command */ + + if (argc < 2) + { + WAPI_ERROR("ERROR: Missing command\n"); + wapi_showusage(argv[0], EXIT_FAILURE); + } + + cmdname = argv[1]; + + /* Find the command in the g_wapi_command[] list */ + + wapicmd = NULL; + for (i = 0; i < NCOMMANDS; i++) + { + FAR const struct wapi_command_s *cmd = &g_wapi_commands[i]; + if (strcmp(cmdname, cmd->name) == 0) + { + wapicmd = cmd; + break; + } + } + + if (wapicmd == NULL) + { + WAPI_ERROR("ERROR: Unsupported command: %s\n", cmdname); + wapi_showusage(argv[0], EXIT_FAILURE); + } + + if (wapicmd->noptions + 2 < argc) + { + WAPI_ERROR("ERROR: Garbage at end of command ignored\n"); + } + else if (wapicmd->noptions + 2 > argc) + { + WAPI_ERROR("ERROR: Missing required command options: %s\n", + cmdname); + wapi_showusage(argv[0], EXIT_FAILURE); + } + + /* Special case the help command which has no arguments, no handler, + * and does not need a socket. + */ + + if (wapicmd->handler == NULL) + { + wapi_showusage(argv[0], EXIT_SUCCESS); + } + + /* Create a communication socket */ + + sock = wapi_make_socket(); + if (sock < 0) + { + WAPI_ERROR("ERROR: wapi_make_socket() failed: %d\n", sock); + return EXIT_FAILURE; + } + + /* Dispatch the command handling */ + + switch (wapicmd->noptions) + { + default: + case 0: + WAPI_ERROR("ERROR: Internal craziness\n"); + wapi_showusage(argv[0], EXIT_FAILURE); + + case 1: + ((cmd1_t)wapicmd->handler)(sock, argv[2]); + break; + + case 2: + ((cmd2_t)wapicmd->handler)(sock, argv[2], argv[3]); + break; + + case 3: + ((cmd3_t)wapicmd->handler)(sock, argv[2], argv[3], argv[4]); + break; + } + + /* Close communication socket */ + + close(sock); + return EXIT_SUCCESS; +} diff --git a/wireless/wapi/src/wireless.c b/wireless/wapi/src/wireless.c new file mode 100644 index 000000000..36bac9600 --- /dev/null +++ b/wireless/wapi/src/wireless.c @@ -0,0 +1,1109 @@ +/**************************************************************************** + * apps/wireless/wapi/src/wireless.c + * + * Copyright (C) 2011, 2017Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Adapted for Nuttx from WAPI: + * + * Copyright (c) 2010, Volkan YAZICI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "wireless/wapi.h" +#include "util.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Events & Streams */ + +struct wapi_event_stream_s +{ + FAR char *end; /* End of the stream */ + FAR char *current; /* Current event in stream of events */ + FAR char *value; /* Current value in event */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Frequency */ + +FAR const char *g_wapi_freq_flags[] = +{ + "WAPI_FREQ_AUTO", + "WAPI_FREQ_FIXED" +}; + +/* ESSID */ + +FAR const char *g_wapi_essid_flags[] = +{ + "WAPI_ESSID_ON", + "WAPI_ESSID_OFF" +}; + +/* Operating Mode */ + +FAR const char *g_wapi_modes[] = +{ + "WAPI_MODE_AUTO", + "WAPI_MODE_ADHOC", + "WAPI_MODE_MANAGED", + "WAPI_MODE_MASTER", + "WAPI_MODE_REPEAT", + "WAPI_MODE_SECOND", + "WAPI_MODE_MONITOR", + "WAPI_MODE_MESH" +}; + +/* Bit Rate */ + +FAR const char *g_wapi_bitrate_flags[] = +{ + "WAPI_BITRATE_AUTO", + "WAPI_BITRATE_FIXED" +}; + +/* Transmit Power */ + +FAR const char *g_wapi_txpower_flags[] = +{ + "WAPI_TXPOWER_DBM", + "WAPI_TXPOWER_MWATT", + "WAPI_TXPOWER_RELATIVE" +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wapi_freq2float + * + * Description: + * Converts internal representation of frequencies to a floating point. + * + ****************************************************************************/ + +static inline double wapi_freq2float(const struct iw_freq *freq) +{ + return ((double)freq->m) * pow(10, freq->e); +} + +/**************************************************************************** + * Name: wapi_float2freq + * + * Description: + * Converts a floating point the our internal representation of frequencies. + * + ****************************************************************************/ + +static inline void wapi_float2freq(double floatfreq, struct iw_freq *freq) +{ + freq->e = (short)floor(log10(floatfreq)); + if (freq->e > 8) + { + freq->m = ((long)(floor(floatfreq / pow(10, freq->e - 6)))) * 100; + freq->e -= 8; + } + else + { + freq->m = (long)floatfreq; + freq->e = 0; + } +} + +/**************************************************************************** + * Name: wapi_parse_mode + * + * Description: + * + ****************************************************************************/ + +static int wapi_parse_mode(int iw_mode, FAR wapi_mode_t *wapi_mode) +{ + switch (iw_mode) + { + case WAPI_MODE_AUTO: + case WAPI_MODE_ADHOC: + case WAPI_MODE_MANAGED: + case WAPI_MODE_MASTER: + case WAPI_MODE_REPEAT: + case WAPI_MODE_SECOND: + case WAPI_MODE_MONITOR: + *wapi_mode = iw_mode; + return 0; + + default: + WAPI_ERROR("ERROR: Unknown mode: %d\n", iw_mode); + return -1; + } +} + +/**************************************************************************** + * Name: wapi_make_ether + * + * Description: + * + ****************************************************************************/ + +static int wapi_make_ether(FAR struct ether_addr *addr, int byte) +{ + WAPI_VALIDATE_PTR(addr); + memset(addr, byte, sizeof(struct ether_addr)); + return 0; +} + +/**************************************************************************** + * Name: wapi_event_stream_init + * + * Description: + * Initialize a stream to access the events. + * + ****************************************************************************/ + +static void wapi_event_stream_init(FAR struct wapi_event_stream_s *stream, + FAR char *data, size_t len) +{ + memset(stream, 0, sizeof(struct wapi_event_stream_s)); + stream->current = data; + stream->end = &data[len]; +} + +/**************************************************************************** + * Name: wapi_event_stream_extract + * + * Description: + * Extract the next event from the stream. + * + ****************************************************************************/ + +static int wapi_event_stream_extract(FAR struct wapi_event_stream_s *stream, + FAR struct iw_event *iwe) +{ +#warning Missing logic +// return iw_extract_event_stream((struct stream_descr *)stream, iwe, 0); +return -ENOSYS; +} + +/**************************************************************************** + * Name: wapi_scan_event + * + * Description: + * + ****************************************************************************/ + +static int wapi_scan_event(FAR struct iw_event *event, FAR wapi_list_t *list) +{ + FAR wapi_scan_info_t *info; + + /* Get current "wapi_info_t". */ + + info = list->head.scan; + + /* Decode the event. */ + + switch (event->cmd) + { + case SIOCGIWAP: + { + wapi_scan_info_t *temp; + + /* Allocate a new cell. */ + + temp = malloc(sizeof(wapi_scan_info_t)); + if (!temp) + { + WAPI_STRERROR("malloc()"); + return -1; + } + + /* Reset it. */ + + bzero(temp, sizeof(wapi_scan_info_t)); + + /* Save cell identifier. */ + + memcpy(&temp->ap, &event->u.ap_addr.sa_data, sizeof(struct ether_addr)); + + /* Push it to the head of the list. */ + + temp->next = info; + list->head.scan = temp; + + break; + } + + case SIOCGIWFREQ: + info->has_freq = 1; + info->freq = wapi_freq2float(&(event->u.freq)); + break; + + case SIOCGIWMODE: + { + int ret = wapi_parse_mode(event->u.mode, &info->mode); + if (ret >= 0) + { + info->has_mode = 1; + break; + } + else + { + return ret; + } + } + + case SIOCGIWESSID: + info->has_essid = 1; + info->essid_flag = (event->u.data.flags) ? WAPI_ESSID_ON : WAPI_ESSID_OFF; + memset(info->essid, 0, (WAPI_ESSID_MAX_SIZE + 1)); + if ((event->u.essid.pointer) && (event->u.essid.length)) + { + memcpy(info->essid, event->u.essid.pointer, event->u.essid.length); + } + break; + + case SIOCGIWRATE: + /* Scan may return a list of bitrates. As we have space for only a single + * bitrate, we only keep the largest one. + */ + + if (!info->has_bitrate || event->u.bitrate.value > info->bitrate) + { + info->has_bitrate = 1; + info->bitrate = event->u.bitrate.value; + } + break; + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: wapi_get_freq + * + * Description: + * Gets the operating frequency of the device. + * + ****************************************************************************/ + +int wapi_get_freq(int sock, FAR const char *ifname, FAR double *freq, + FAR wapi_freq_flag_t *flag) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(freq); + WAPI_VALIDATE_PTR(flag); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWFREQ, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + /* Set flag. */ + + if (IW_FREQ_AUTO == (wrq.u.freq.flags & IW_FREQ_AUTO)) + { + *flag = WAPI_FREQ_AUTO; + } + else if (IW_FREQ_FIXED == (wrq.u.freq.flags & IW_FREQ_FIXED)) + { + *flag = WAPI_FREQ_FIXED; + } + else + { + WAPI_ERROR("ERROR: Unknown flag: %d\n", wrq.u.freq.flags); + return -1; + } + + /* Set freq. */ + + *freq = wapi_freq2float(&(wrq.u.freq)); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_freq + * + * Description: + * Sets the operating frequency of the device. + * + ****************************************************************************/ + +int wapi_set_freq(int sock, FAR const char *ifname, double freq, + wapi_freq_flag_t flag) +{ + struct iwreq wrq; + int ret; + + /* Set freq. */ + + wapi_float2freq(freq, &(wrq.u.freq)); + + /* Set flag. */ + + switch (flag) + { + case WAPI_FREQ_AUTO: + wrq.u.freq.flags = IW_FREQ_AUTO; + break; + + case WAPI_FREQ_FIXED: + wrq.u.freq.flags = IW_FREQ_FIXED; + break; + } + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCSIWFREQ, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWFREQ); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_freq2chan + * + * Description: + * Finds corresponding channel for the supplied freq. + * + * Returned Value: + * 0, on success; -2, if not found; otherwise, ioctl() return value. + * + ****************************************************************************/ + +int wapi_freq2chan(int sock, FAR const char *ifname, double freq, + FAR int *chan) +{ + struct iwreq wrq; + char buf[sizeof(struct iw_range) * 2]; + int ret; + + WAPI_VALIDATE_PTR(chan); + + /* Prepare request. */ + + bzero(buf, sizeof(buf)); + wrq.u.data.pointer = buf; + wrq.u.data.length = sizeof(buf); + wrq.u.data.flags = 0; + + /* Get range. */ + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWRANGE, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + struct iw_range *range = (struct iw_range *)buf; + int k; + + /* Compare the frequencies as double to ignore differences in encoding. + * Slower, but safer... + */ + + for (k = 0; k < range->num_frequency; k++) + { + if (freq == wapi_freq2float(&(range->freq[k]))) + { + *chan = range->freq[k].i; + return 0; + } + } + + /* Oops! Nothing found. */ + + ret = -2; + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWRANGE); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_chan2freq + * + * Description: + * Finds corresponding frequency for the supplied chan. + * + * Returned Value: + * 0, on success; -2, if not found; otherwise, ioctl() return value. + * + ****************************************************************************/ + +int wapi_chan2freq(int sock, FAR const char *ifname, int chan, + FAR double *freq) +{ + struct iwreq wrq; + char buf[sizeof(struct iw_range) * 2]; + int ret; + + WAPI_VALIDATE_PTR(freq); + + /* Prepare request. */ + + bzero(buf, sizeof(buf)); + wrq.u.data.pointer = buf; + wrq.u.data.length = sizeof(buf); + wrq.u.data.flags = 0; + + /* Get range. */ + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWRANGE, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + struct iw_range *range = (struct iw_range *)buf; + int k; + + for (k = 0; k < range->num_frequency; k++) + { + if (chan == range->freq[k].i) + { + *freq = wapi_freq2float(&(range->freq[k])); + return 0; + } + } + + /* Oops! Nothing found. */ + + ret = -2; + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWRANGE); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_get_essid + * + * Description: + * Gets ESSID of the device. + * + * Input Parameters: + * essid - Used to store the ESSID of the device. Buffer must have + * enough space to store WAPI_ESSID_MAX_SIZE+1 characters. + * + ****************************************************************************/ + +int wapi_get_essid(int sock, FAR const char *ifname, FAR char *essid, + FAR wapi_essid_flag_t *flag) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(essid); + WAPI_VALIDATE_PTR(flag); + + wrq.u.essid.pointer = essid; + wrq.u.essid.length = WAPI_ESSID_MAX_SIZE + 1; + wrq.u.essid.flags = 0; + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCGIWESSID, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCGIWESSID); + } + else + { + *flag = (wrq.u.essid.flags) ? WAPI_ESSID_ON : WAPI_ESSID_OFF; + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_essid + * + * Description: + * Sets ESSID of the device. + * + * essid At most WAPI_ESSID_MAX_SIZE characters are read. + * + ****************************************************************************/ + +int wapi_set_essid(int sock, FAR const char *ifname, FAR const char *essid, + wapi_essid_flag_t flag) +{ + char buf[WAPI_ESSID_MAX_SIZE + 1]; + struct iwreq wrq; + int ret; + + /* Prepare request. */ + + wrq.u.essid.pointer = buf; + wrq.u.essid.length = + snprintf(buf, ((WAPI_ESSID_MAX_SIZE + 1) * sizeof(char)), "%s", essid); + wrq.u.essid.flags = (flag == WAPI_ESSID_ON); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCSIWESSID, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWESSID); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_get_mode + * + * Description: + * Gets the operating mode of the device. + * + ****************************************************************************/ + +int wapi_get_mode(int sock, FAR const char *ifname, FAR wapi_mode_t *mode) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(mode); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWMODE, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + ret = wapi_parse_mode(wrq.u.mode, mode); + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWMODE); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_mode + * + * Description: + * Sets the operating mode of the device. + * + ****************************************************************************/ + +int wapi_set_mode(int sock, FAR const char *ifname, wapi_mode_t mode) +{ + struct iwreq wrq; + int ret; + + wrq.u.mode = mode; + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCSIWMODE, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWMODE); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_make_broad_ether + * + * Description: + * Creates an ethernet broadcast address. + * + ****************************************************************************/ + +int wapi_make_broad_ether(FAR struct ether_addr *sa) +{ + return wapi_make_ether(sa, 0xFF); +} + +/**************************************************************************** + * Name: wapi_make_null_ether + * + * Description: + * Creates an ethernet NULL address. + * + ****************************************************************************/ + +int wapi_make_null_ether(FAR struct ether_addr *sa) +{ + return wapi_make_ether(sa, 0x00); +} + +/**************************************************************************** + * Name: wapi_get_ap + * + * Description: + * Gets access point address of the device. + * + * Input Parameters: + * ap - Set the to MAC address of the device. (For "any", a broadcast + * ethernet address; for "off", a null ethernet address is used.) + * + ****************************************************************************/ + +int wapi_get_ap(int sock, FAR const char *ifname, FAR struct ether_addr *ap) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(ap); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWAP, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + memcpy(ap, wrq.u.ap_addr.sa_data, sizeof(struct ether_addr)); + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWAP); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_ap + * + * Description: + * Sets access point address of the device. + * + ****************************************************************************/ + +int wapi_set_ap(int sock, FAR const char *ifname, + FAR const struct ether_addr *ap) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(ap); + + wrq.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrq.u.ap_addr.sa_data, ap, sizeof(struct ether_addr)); + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + + ret = ioctl(sock, SIOCSIWAP, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWAP); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_get_bitrate + * + * Description: + * Gets bitrate of the device. + * + ****************************************************************************/ + +int wapi_get_bitrate(int sock, FAR const char *ifname, + FAR int *bitrate, FAR wapi_bitrate_flag_t *flag) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(bitrate); + WAPI_VALIDATE_PTR(flag); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWRATE, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + /* Check if enabled. */ + + if (wrq.u.bitrate.disabled) + { + WAPI_ERROR("ERROR: Bitrate is disabled\n"); + return -1; + } + + /* Get bitrate. */ + + *bitrate = wrq.u.bitrate.value; + *flag = wrq.u.bitrate.fixed ? WAPI_BITRATE_FIXED : WAPI_BITRATE_AUTO; + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWRATE); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_bitrate + * + * Description: + * Sets bitrate of the device. + * + ****************************************************************************/ + +int wapi_set_bitrate(int sock, FAR const char *ifname, int bitrate, + wapi_bitrate_flag_t flag) +{ + struct iwreq wrq; + int ret; + + wrq.u.bitrate.value = bitrate; + wrq.u.bitrate.fixed = (flag == WAPI_BITRATE_FIXED); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCSIWRATE, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWRATE); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_dbm2mwatt + * + * Description: + * Converts a value in dBm to a value in milliWatt. + * + ****************************************************************************/ + +int wapi_dbm2mwatt(int dbm) +{ + return floor(pow(10, (((double)dbm) / 10))); +} + +/**************************************************************************** + * Name: wapi_mwatt2dbm + * + * Description: + * Converts a value in milliWatt to a value in dBm. + * + ****************************************************************************/ + +int wapi_mwatt2dbm(int mwatt) +{ + return ceil(10 * log10(mwatt)); +} + +/**************************************************************************** + * Name: wapi_get_txpower + * + * Description: + * Gets txpower of the device. + * + ****************************************************************************/ + +int wapi_get_txpower(int sock, FAR const char *ifname, FAR int *power, + FAR wapi_txpower_flag_t *flag) +{ + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(power); + WAPI_VALIDATE_PTR(flag); + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWTXPOW, (unsigned long)((uintptr_t)&wrq))) >= 0) + { + /* Check if enabled. */ + + if (wrq.u.txpower.disabled) + { + return -1; + } + + /* Get flag. */ + + if (IW_TXPOW_DBM == (wrq.u.txpower.flags & IW_TXPOW_DBM)) + { + *flag = WAPI_TXPOWER_DBM; + } + else if (IW_TXPOW_MWATT == (wrq.u.txpower.flags & IW_TXPOW_MWATT)) + { + *flag = WAPI_TXPOWER_MWATT; + } + else if (IW_TXPOW_RELATIVE == (wrq.u.txpower.flags & IW_TXPOW_RELATIVE)) + { + *flag = WAPI_TXPOWER_RELATIVE; + } + else + { + WAPI_ERROR("ERROR: Unknown flag: %d\n", wrq.u.txpower.flags); + return -1; + } + + /* Get power. */ + + *power = wrq.u.txpower.value; + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWTXPOW); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_set_txpower + * + * Description: + * Sets txpower of the device. + * + ****************************************************************************/ + +int wapi_set_txpower(int sock, FAR const char *ifname, int power, + wapi_txpower_flag_t flag) +{ + struct iwreq wrq; + int ret; + + /* Construct the request. */ + + wrq.u.txpower.value = power; + switch (flag) + { + case WAPI_TXPOWER_DBM: + wrq.u.txpower.flags = IW_TXPOW_DBM; + break; + + case WAPI_TXPOWER_MWATT: + wrq.u.txpower.flags = IW_TXPOW_MWATT; + break; + + case WAPI_TXPOWER_RELATIVE: + wrq.u.txpower.flags = IW_TXPOW_RELATIVE; + break; + } + + /* Issue the set command. */ + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCSIWTXPOW, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWTXPOW); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_scan_init + * + * Description: + * Starts a scan on the given interface. Root privileges are required to start a + * scan. + * + ****************************************************************************/ + +int wapi_scan_init(int sock, const char *ifname) +{ + struct iwreq wrq; + int ret; + + wrq.u.data.pointer = NULL; + wrq.u.data.flags = 0; + wrq.u.data.length = 0; + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + ret = ioctl(sock, SIOCSIWSCAN, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCSIWSCAN); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_scan_stat + * + * Description: + * Checks the status of the scan process. + * + * Returned Value: + * Zero, if data is ready; 1, if data is not ready; negative on failure. + * + ****************************************************************************/ + +int wapi_scan_stat(int sock, FAR const char *ifname) +{ + struct iwreq wrq; + int ret; + char buf; + + wrq.u.data.pointer = &buf; + wrq.u.data.flags = 0; + wrq.u.data.length = 0; + + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + if ((ret = ioctl(sock, SIOCGIWSCAN, (unsigned long)((uintptr_t)&wrq))) < 0) + { + if (errno == E2BIG) + { + /* Data is ready, but not enough space, which is expected. */ + + return 0; + } + else if (errno == EAGAIN) + { + /* Data is not ready. */ + + return 1; + } + + printf("err[%d]: %s\n", errno, strerror(errno)); + } + else + { + WAPI_IOCTL_STRERROR(SIOCGIWSCAN); + } + + return ret; +} + +/**************************************************************************** + * Name: wapi_scan_coll + * + * Description: + * Collects the results of a scan process. + * + * Input Parameters: + * aps - Pushes collected wapi_scan_info_t into this list. + * + ****************************************************************************/ + +int wapi_scan_coll(int sock, FAR const char *ifname, FAR wapi_list_t *aps) +{ + FAR char *buf; + int buflen; + struct iwreq wrq; + int ret; + + WAPI_VALIDATE_PTR(aps); + + buflen = IW_SCAN_MAX_DATA; + buf = malloc(buflen * sizeof(char)); + if (!buf) + { + WAPI_STRERROR("malloc()"); + return -1; + } + +alloc: + /* Collect results. */ + + wrq.u.data.pointer = buf; + wrq.u.data.length = buflen; + wrq.u.data.flags = 0; + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + + ret = ioctl(sock, SIOCGIWSCAN, (unsigned long)((uintptr_t)&wrq)); + if (ret < 0 && errno == E2BIG) + { + FAR char *tmp; + + buflen *= 2; + tmp = realloc(buf, buflen); + if (!tmp) + { + WAPI_STRERROR("realloc()"); + free(buf); + return -1; + } + + buf = tmp; + goto alloc; + } + + /* There is still something wrong. It's either EAGAIN or some other ioctl() + * failure. We don't bother, let the user deal with it. + */ + + if (ret < 0) + { + WAPI_IOCTL_STRERROR(SIOCGIWSCAN); + free(buf); + return ret; + } + + /* We have the results, process them. */ + + if (wrq.u.data.length) + { + struct iw_event iwe; + struct wapi_event_stream_s stream; + + wapi_event_stream_init(&stream, buf, wrq.u.data.length); + do + { + /* Get the next event from the stream */ + + if ((ret = wapi_event_stream_extract(&stream, &iwe)) >= 0) + { + int eventret = wapi_scan_event(&iwe, aps); + if (eventret < 0) + { + ret = eventret; + } + } + else + { + WAPI_ERROR("ERROR: wapi_event_stream_extract() failed!\n"); + } + } + while (ret > 0); + } + + /* Free request buffer. */ + + free(buf); + return ret; +}