1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * SNMP thread synchronization implementation.
4195972f6Sopenharmony_ci */
5195972f6Sopenharmony_ci
6195972f6Sopenharmony_ci/*
7195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
8195972f6Sopenharmony_ci * All rights reserved.
9195972f6Sopenharmony_ci *
10195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
11195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
12195972f6Sopenharmony_ci *
13195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
14195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
15195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
16195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
17195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
18195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
19195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
20195972f6Sopenharmony_ci *
21195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30195972f6Sopenharmony_ci * OF SUCH DAMAGE.
31195972f6Sopenharmony_ci *
32195972f6Sopenharmony_ci * Author: Dirk Ziegelmeier <dziegel@gmx.de>
33195972f6Sopenharmony_ci */
34195972f6Sopenharmony_ci
35195972f6Sopenharmony_ci#include "lwip/apps/snmp_opts.h"
36195972f6Sopenharmony_ci
37195972f6Sopenharmony_ci#if LWIP_SNMP && (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
38195972f6Sopenharmony_ci
39195972f6Sopenharmony_ci#include "lwip/apps/snmp_threadsync.h"
40195972f6Sopenharmony_ci#include "lwip/apps/snmp_core.h"
41195972f6Sopenharmony_ci#include "lwip/sys.h"
42195972f6Sopenharmony_ci#include <string.h>
43195972f6Sopenharmony_ci
44195972f6Sopenharmony_cistatic void
45195972f6Sopenharmony_cicall_synced_function(struct threadsync_data *call_data, snmp_threadsync_called_fn fn)
46195972f6Sopenharmony_ci{
47195972f6Sopenharmony_ci  sys_mutex_lock(&call_data->threadsync_node->instance->sem_usage_mutex);
48195972f6Sopenharmony_ci  call_data->threadsync_node->instance->sync_fn(fn, call_data);
49195972f6Sopenharmony_ci  sys_sem_wait(&call_data->threadsync_node->instance->sem);
50195972f6Sopenharmony_ci  sys_mutex_unlock(&call_data->threadsync_node->instance->sem_usage_mutex);
51195972f6Sopenharmony_ci}
52195972f6Sopenharmony_ci
53195972f6Sopenharmony_cistatic void
54195972f6Sopenharmony_cithreadsync_get_value_synced(void *ctx)
55195972f6Sopenharmony_ci{
56195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)ctx;
57195972f6Sopenharmony_ci
58195972f6Sopenharmony_ci  if (call_data->proxy_instance.get_value != NULL) {
59195972f6Sopenharmony_ci    call_data->retval.s16 = call_data->proxy_instance.get_value(&call_data->proxy_instance, call_data->arg1.value);
60195972f6Sopenharmony_ci  } else {
61195972f6Sopenharmony_ci    call_data->retval.s16 = -1;
62195972f6Sopenharmony_ci  }
63195972f6Sopenharmony_ci
64195972f6Sopenharmony_ci  sys_sem_signal(&call_data->threadsync_node->instance->sem);
65195972f6Sopenharmony_ci}
66195972f6Sopenharmony_ci
67195972f6Sopenharmony_cistatic s16_t
68195972f6Sopenharmony_cithreadsync_get_value(struct snmp_node_instance *instance, void *value)
69195972f6Sopenharmony_ci{
70195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
71195972f6Sopenharmony_ci
72195972f6Sopenharmony_ci  call_data->arg1.value = value;
73195972f6Sopenharmony_ci  call_synced_function(call_data, threadsync_get_value_synced);
74195972f6Sopenharmony_ci
75195972f6Sopenharmony_ci  return call_data->retval.s16;
76195972f6Sopenharmony_ci}
77195972f6Sopenharmony_ci
78195972f6Sopenharmony_cistatic void
79195972f6Sopenharmony_cithreadsync_set_test_synced(void *ctx)
80195972f6Sopenharmony_ci{
81195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)ctx;
82195972f6Sopenharmony_ci
83195972f6Sopenharmony_ci  if (call_data->proxy_instance.set_test != NULL) {
84195972f6Sopenharmony_ci    call_data->retval.err = call_data->proxy_instance.set_test(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
85195972f6Sopenharmony_ci  } else {
86195972f6Sopenharmony_ci    call_data->retval.err = SNMP_ERR_NOTWRITABLE;
87195972f6Sopenharmony_ci  }
88195972f6Sopenharmony_ci
89195972f6Sopenharmony_ci  sys_sem_signal(&call_data->threadsync_node->instance->sem);
90195972f6Sopenharmony_ci}
91195972f6Sopenharmony_ci
92195972f6Sopenharmony_cistatic snmp_err_t
93195972f6Sopenharmony_cithreadsync_set_test(struct snmp_node_instance *instance, u16_t len, void *value)
94195972f6Sopenharmony_ci{
95195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
96195972f6Sopenharmony_ci
97195972f6Sopenharmony_ci  call_data->arg1.value = value;
98195972f6Sopenharmony_ci  call_data->arg2.len = len;
99195972f6Sopenharmony_ci  call_synced_function(call_data, threadsync_set_test_synced);
100195972f6Sopenharmony_ci
101195972f6Sopenharmony_ci  return call_data->retval.err;
102195972f6Sopenharmony_ci}
103195972f6Sopenharmony_ci
104195972f6Sopenharmony_cistatic void
105195972f6Sopenharmony_cithreadsync_set_value_synced(void *ctx)
106195972f6Sopenharmony_ci{
107195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)ctx;
108195972f6Sopenharmony_ci
109195972f6Sopenharmony_ci  if (call_data->proxy_instance.set_value != NULL) {
110195972f6Sopenharmony_ci    call_data->retval.err = call_data->proxy_instance.set_value(&call_data->proxy_instance, call_data->arg2.len, call_data->arg1.value);
111195972f6Sopenharmony_ci  } else {
112195972f6Sopenharmony_ci    call_data->retval.err = SNMP_ERR_NOTWRITABLE;
113195972f6Sopenharmony_ci  }
114195972f6Sopenharmony_ci
115195972f6Sopenharmony_ci  sys_sem_signal(&call_data->threadsync_node->instance->sem);
116195972f6Sopenharmony_ci}
117195972f6Sopenharmony_ci
118195972f6Sopenharmony_cistatic snmp_err_t
119195972f6Sopenharmony_cithreadsync_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
120195972f6Sopenharmony_ci{
121195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
122195972f6Sopenharmony_ci
123195972f6Sopenharmony_ci  call_data->arg1.value = value;
124195972f6Sopenharmony_ci  call_data->arg2.len = len;
125195972f6Sopenharmony_ci  call_synced_function(call_data, threadsync_set_value_synced);
126195972f6Sopenharmony_ci
127195972f6Sopenharmony_ci  return call_data->retval.err;
128195972f6Sopenharmony_ci}
129195972f6Sopenharmony_ci
130195972f6Sopenharmony_cistatic void
131195972f6Sopenharmony_cithreadsync_release_instance_synced(void *ctx)
132195972f6Sopenharmony_ci{
133195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)ctx;
134195972f6Sopenharmony_ci
135195972f6Sopenharmony_ci  call_data->proxy_instance.release_instance(&call_data->proxy_instance);
136195972f6Sopenharmony_ci
137195972f6Sopenharmony_ci  sys_sem_signal(&call_data->threadsync_node->instance->sem);
138195972f6Sopenharmony_ci}
139195972f6Sopenharmony_ci
140195972f6Sopenharmony_cistatic void
141195972f6Sopenharmony_cithreadsync_release_instance(struct snmp_node_instance *instance)
142195972f6Sopenharmony_ci{
143195972f6Sopenharmony_ci  struct threadsync_data *call_data = (struct threadsync_data *)instance->reference.ptr;
144195972f6Sopenharmony_ci
145195972f6Sopenharmony_ci  if (call_data->proxy_instance.release_instance != NULL) {
146195972f6Sopenharmony_ci    call_synced_function(call_data, threadsync_release_instance_synced);
147195972f6Sopenharmony_ci  }
148195972f6Sopenharmony_ci}
149195972f6Sopenharmony_ci
150195972f6Sopenharmony_cistatic void
151195972f6Sopenharmony_ciget_instance_synced(void *ctx)
152195972f6Sopenharmony_ci{
153195972f6Sopenharmony_ci  struct threadsync_data *call_data   = (struct threadsync_data *)ctx;
154195972f6Sopenharmony_ci  const struct snmp_leaf_node *leaf   = (const struct snmp_leaf_node *)(const void *)call_data->proxy_instance.node;
155195972f6Sopenharmony_ci
156195972f6Sopenharmony_ci  call_data->retval.err = leaf->get_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
157195972f6Sopenharmony_ci
158195972f6Sopenharmony_ci  sys_sem_signal(&call_data->threadsync_node->instance->sem);
159195972f6Sopenharmony_ci}
160195972f6Sopenharmony_ci
161195972f6Sopenharmony_cistatic void
162195972f6Sopenharmony_ciget_next_instance_synced(void *ctx)
163195972f6Sopenharmony_ci{
164195972f6Sopenharmony_ci  struct threadsync_data *call_data   = (struct threadsync_data *)ctx;
165195972f6Sopenharmony_ci  const struct snmp_leaf_node *leaf   = (const struct snmp_leaf_node *)(const void *)call_data->proxy_instance.node;
166195972f6Sopenharmony_ci
167195972f6Sopenharmony_ci  call_data->retval.err = leaf->get_next_instance(call_data->arg1.root_oid, call_data->arg2.root_oid_len, &call_data->proxy_instance);
168195972f6Sopenharmony_ci
169195972f6Sopenharmony_ci  sys_sem_signal(&call_data->threadsync_node->instance->sem);
170195972f6Sopenharmony_ci}
171195972f6Sopenharmony_ci
172195972f6Sopenharmony_cistatic snmp_err_t
173195972f6Sopenharmony_cido_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance, snmp_threadsync_called_fn fn)
174195972f6Sopenharmony_ci{
175195972f6Sopenharmony_ci  const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node *)(const void *)instance->node;
176195972f6Sopenharmony_ci  struct threadsync_data *call_data = &threadsync_node->instance->data;
177195972f6Sopenharmony_ci
178195972f6Sopenharmony_ci  if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) {
179195972f6Sopenharmony_ci    LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID"));
180195972f6Sopenharmony_ci    return SNMP_ERR_NOSUCHINSTANCE;
181195972f6Sopenharmony_ci  }
182195972f6Sopenharmony_ci
183195972f6Sopenharmony_ci  memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance));
184195972f6Sopenharmony_ci
185195972f6Sopenharmony_ci  instance->reference.ptr = call_data;
186195972f6Sopenharmony_ci  snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len);
187195972f6Sopenharmony_ci
188195972f6Sopenharmony_ci  call_data->proxy_instance.node = &threadsync_node->target->node;
189195972f6Sopenharmony_ci  call_data->threadsync_node     = threadsync_node;
190195972f6Sopenharmony_ci
191195972f6Sopenharmony_ci  call_data->arg1.root_oid       = root_oid;
192195972f6Sopenharmony_ci  call_data->arg2.root_oid_len   = root_oid_len;
193195972f6Sopenharmony_ci  call_synced_function(call_data, fn);
194195972f6Sopenharmony_ci
195195972f6Sopenharmony_ci  if (call_data->retval.err == SNMP_ERR_NOERROR) {
196195972f6Sopenharmony_ci    instance->access           = call_data->proxy_instance.access;
197195972f6Sopenharmony_ci    instance->asn1_type        = call_data->proxy_instance.asn1_type;
198195972f6Sopenharmony_ci    instance->release_instance = threadsync_release_instance;
199195972f6Sopenharmony_ci    instance->get_value        = (call_data->proxy_instance.get_value != NULL) ? threadsync_get_value : NULL;
200195972f6Sopenharmony_ci    instance->set_value        = (call_data->proxy_instance.set_value != NULL) ? threadsync_set_value : NULL;
201195972f6Sopenharmony_ci    instance->set_test         = (call_data->proxy_instance.set_test != NULL) ?  threadsync_set_test  : NULL;
202195972f6Sopenharmony_ci    snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
203195972f6Sopenharmony_ci  }
204195972f6Sopenharmony_ci
205195972f6Sopenharmony_ci  return call_data->retval.err;
206195972f6Sopenharmony_ci}
207195972f6Sopenharmony_ci
208195972f6Sopenharmony_cisnmp_err_t
209195972f6Sopenharmony_cisnmp_threadsync_get_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
210195972f6Sopenharmony_ci{
211195972f6Sopenharmony_ci  return do_sync(root_oid, root_oid_len, instance, get_instance_synced);
212195972f6Sopenharmony_ci}
213195972f6Sopenharmony_ci
214195972f6Sopenharmony_cisnmp_err_t
215195972f6Sopenharmony_cisnmp_threadsync_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance *instance)
216195972f6Sopenharmony_ci{
217195972f6Sopenharmony_ci  return do_sync(root_oid, root_oid_len, instance, get_next_instance_synced);
218195972f6Sopenharmony_ci}
219195972f6Sopenharmony_ci
220195972f6Sopenharmony_ci/** Initializes thread synchronization instance */
221195972f6Sopenharmony_civoid snmp_threadsync_init(struct snmp_threadsync_instance *instance, snmp_threadsync_synchronizer_fn sync_fn)
222195972f6Sopenharmony_ci{
223195972f6Sopenharmony_ci  err_t err = sys_mutex_new(&instance->sem_usage_mutex);
224195972f6Sopenharmony_ci  LWIP_ASSERT("Failed to set up mutex", err == ERR_OK);
225195972f6Sopenharmony_ci  err = sys_sem_new(&instance->sem, 0);
226195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */
227195972f6Sopenharmony_ci  LWIP_ASSERT("Failed to set up semaphore", err == ERR_OK);
228195972f6Sopenharmony_ci  instance->sync_fn = sync_fn;
229195972f6Sopenharmony_ci}
230195972f6Sopenharmony_ci
231195972f6Sopenharmony_ci#endif /* LWIP_SNMP */
232