18a1b9b6aSSam Leffler /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4b032f27cSSam Leffler * Copyright (c) 2004-2008 Sam Leffler, Errno Consulting
58a1b9b6aSSam Leffler * All rights reserved.
68a1b9b6aSSam Leffler *
78a1b9b6aSSam Leffler * Redistribution and use in source and binary forms, with or without
88a1b9b6aSSam Leffler * modification, are permitted provided that the following conditions
98a1b9b6aSSam Leffler * are met:
108a1b9b6aSSam Leffler * 1. Redistributions of source code must retain the above copyright
118a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer.
128a1b9b6aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright
138a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer in the
148a1b9b6aSSam Leffler * documentation and/or other materials provided with the distribution.
158a1b9b6aSSam Leffler *
168a1b9b6aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
178a1b9b6aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
188a1b9b6aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
198a1b9b6aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
208a1b9b6aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
218a1b9b6aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
228a1b9b6aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
238a1b9b6aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
248a1b9b6aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
258a1b9b6aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
268a1b9b6aSSam Leffler */
278a1b9b6aSSam Leffler
288a1b9b6aSSam Leffler #include <sys/cdefs.h>
298a1b9b6aSSam Leffler /*
308a1b9b6aSSam Leffler * IEEE 802.11 MAC ACL support.
318a1b9b6aSSam Leffler *
32b032f27cSSam Leffler * When this module is loaded the sender address of each auth mgt
338a1b9b6aSSam Leffler * frame is passed to the iac_check method and the module indicates
348a1b9b6aSSam Leffler * if the frame should be accepted or rejected. If the policy is
358a1b9b6aSSam Leffler * set to ACL_POLICY_OPEN then all frames are accepted w/o checking
368a1b9b6aSSam Leffler * the address. Otherwise, the address is looked up in the database
378a1b9b6aSSam Leffler * and if found the frame is either accepted (ACL_POLICY_ALLOW)
388a1b9b6aSSam Leffler * or rejected (ACL_POLICY_DENT).
398a1b9b6aSSam Leffler */
40b032f27cSSam Leffler #include "opt_wlan.h"
41b032f27cSSam Leffler
428a1b9b6aSSam Leffler #include <sys/param.h>
438a1b9b6aSSam Leffler #include <sys/kernel.h>
448a1b9b6aSSam Leffler #include <sys/systm.h>
458ec07310SGleb Smirnoff #include <sys/malloc.h>
468a1b9b6aSSam Leffler #include <sys/mbuf.h>
478a1b9b6aSSam Leffler #include <sys/module.h>
488a1b9b6aSSam Leffler #include <sys/queue.h>
498a1b9b6aSSam Leffler
508a1b9b6aSSam Leffler #include <sys/socket.h>
518a1b9b6aSSam Leffler
528a1b9b6aSSam Leffler #include <net/if.h>
538a1b9b6aSSam Leffler #include <net/if_media.h>
548a1b9b6aSSam Leffler #include <net/ethernet.h>
558a1b9b6aSSam Leffler #include <net/route.h>
568a1b9b6aSSam Leffler
578a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h>
588a1b9b6aSSam Leffler
598a1b9b6aSSam Leffler enum {
608a1b9b6aSSam Leffler ACL_POLICY_OPEN = 0, /* open, don't check ACL's */
618a1b9b6aSSam Leffler ACL_POLICY_ALLOW = 1, /* allow traffic from MAC */
628a1b9b6aSSam Leffler ACL_POLICY_DENY = 2, /* deny traffic from MAC */
63b032f27cSSam Leffler /*
64b032f27cSSam Leffler * NB: ACL_POLICY_RADIUS must be the same value as
65b032f27cSSam Leffler * IEEE80211_MACCMD_POLICY_RADIUS because of the way
66b032f27cSSam Leffler * acl_getpolicy() works.
67b032f27cSSam Leffler */
68b032f27cSSam Leffler ACL_POLICY_RADIUS = 7, /* defer to RADIUS ACL server */
698a1b9b6aSSam Leffler };
708a1b9b6aSSam Leffler
718a1b9b6aSSam Leffler #define ACL_HASHSIZE 32
728a1b9b6aSSam Leffler
738a1b9b6aSSam Leffler struct acl {
748a1b9b6aSSam Leffler TAILQ_ENTRY(acl) acl_list;
758a1b9b6aSSam Leffler LIST_ENTRY(acl) acl_hash;
7668e8e04eSSam Leffler uint8_t acl_macaddr[IEEE80211_ADDR_LEN];
778a1b9b6aSSam Leffler };
788a1b9b6aSSam Leffler struct aclstate {
798a1b9b6aSSam Leffler acl_lock_t as_lock;
808a1b9b6aSSam Leffler int as_policy;
81db9ff08bSKevin Lo uint32_t as_nacls;
828a1b9b6aSSam Leffler TAILQ_HEAD(, acl) as_list; /* list of all ACL's */
838a1b9b6aSSam Leffler LIST_HEAD(, acl) as_hash[ACL_HASHSIZE];
84b032f27cSSam Leffler struct ieee80211vap *as_vap;
858a1b9b6aSSam Leffler };
868a1b9b6aSSam Leffler
878a1b9b6aSSam Leffler /* simple hash is enough for variation of macaddr */
888a1b9b6aSSam Leffler #define ACL_HASH(addr) \
8968e8e04eSSam Leffler (((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE)
908a1b9b6aSSam Leffler
91d745c852SEd Schouten static MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl");
928a1b9b6aSSam Leffler
93b032f27cSSam Leffler static int acl_free_all(struct ieee80211vap *);
94b032f27cSSam Leffler
95b032f27cSSam Leffler /* number of references from net80211 layer */
96b032f27cSSam Leffler static int nrefs = 0;
978a1b9b6aSSam Leffler
988a1b9b6aSSam Leffler static int
acl_attach(struct ieee80211vap * vap)99b032f27cSSam Leffler acl_attach(struct ieee80211vap *vap)
1008a1b9b6aSSam Leffler {
1018a1b9b6aSSam Leffler struct aclstate *as;
1028a1b9b6aSSam Leffler
103b9b53389SAdrian Chadd as = (struct aclstate *) IEEE80211_MALLOC(sizeof(struct aclstate),
104b9b53389SAdrian Chadd M_80211_ACL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1058a1b9b6aSSam Leffler if (as == NULL)
1068a1b9b6aSSam Leffler return 0;
1078a1b9b6aSSam Leffler ACL_LOCK_INIT(as, "acl");
1088a1b9b6aSSam Leffler TAILQ_INIT(&as->as_list);
1098a1b9b6aSSam Leffler as->as_policy = ACL_POLICY_OPEN;
110b032f27cSSam Leffler as->as_vap = vap;
111b032f27cSSam Leffler vap->iv_as = as;
112b032f27cSSam Leffler nrefs++; /* NB: we assume caller locking */
1138a1b9b6aSSam Leffler return 1;
1148a1b9b6aSSam Leffler }
1158a1b9b6aSSam Leffler
1168a1b9b6aSSam Leffler static void
acl_detach(struct ieee80211vap * vap)117b032f27cSSam Leffler acl_detach(struct ieee80211vap *vap)
1188a1b9b6aSSam Leffler {
119b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
1208a1b9b6aSSam Leffler
121b032f27cSSam Leffler KASSERT(nrefs > 0, ("imbalanced attach/detach"));
122b032f27cSSam Leffler nrefs--; /* NB: we assume caller locking */
123b032f27cSSam Leffler
124b032f27cSSam Leffler acl_free_all(vap);
125b032f27cSSam Leffler vap->iv_as = NULL;
1268a1b9b6aSSam Leffler ACL_LOCK_DESTROY(as);
127b9b53389SAdrian Chadd IEEE80211_FREE(as, M_80211_ACL);
1288a1b9b6aSSam Leffler }
1298a1b9b6aSSam Leffler
13068f5ddcdSSam Leffler static __inline struct acl *
_find_acl(struct aclstate * as,const uint8_t * macaddr)13168e8e04eSSam Leffler _find_acl(struct aclstate *as, const uint8_t *macaddr)
1328a1b9b6aSSam Leffler {
1338a1b9b6aSSam Leffler struct acl *acl;
1348a1b9b6aSSam Leffler int hash;
1358a1b9b6aSSam Leffler
1368a1b9b6aSSam Leffler hash = ACL_HASH(macaddr);
1378a1b9b6aSSam Leffler LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
1388a1b9b6aSSam Leffler if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
1398a1b9b6aSSam Leffler return acl;
1408a1b9b6aSSam Leffler }
1418a1b9b6aSSam Leffler return NULL;
1428a1b9b6aSSam Leffler }
1438a1b9b6aSSam Leffler
1448a1b9b6aSSam Leffler static void
_acl_free(struct aclstate * as,struct acl * acl)1458a1b9b6aSSam Leffler _acl_free(struct aclstate *as, struct acl *acl)
1468a1b9b6aSSam Leffler {
1478a1b9b6aSSam Leffler ACL_LOCK_ASSERT(as);
1488a1b9b6aSSam Leffler
1498a1b9b6aSSam Leffler TAILQ_REMOVE(&as->as_list, acl, acl_list);
1508a1b9b6aSSam Leffler LIST_REMOVE(acl, acl_hash);
151b9b53389SAdrian Chadd IEEE80211_FREE(acl, M_80211_ACL);
152188757f5SSam Leffler as->as_nacls--;
1538a1b9b6aSSam Leffler }
1548a1b9b6aSSam Leffler
1558a1b9b6aSSam Leffler static int
acl_check(struct ieee80211vap * vap,const struct ieee80211_frame * wh)1565a8801b0SBernhard Schmidt acl_check(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
1578a1b9b6aSSam Leffler {
158b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
1598a1b9b6aSSam Leffler
1608a1b9b6aSSam Leffler switch (as->as_policy) {
1618a1b9b6aSSam Leffler case ACL_POLICY_OPEN:
162b032f27cSSam Leffler case ACL_POLICY_RADIUS:
1638a1b9b6aSSam Leffler return 1;
1648a1b9b6aSSam Leffler case ACL_POLICY_ALLOW:
1655a8801b0SBernhard Schmidt return _find_acl(as, wh->i_addr2) != NULL;
1668a1b9b6aSSam Leffler case ACL_POLICY_DENY:
1675a8801b0SBernhard Schmidt return _find_acl(as, wh->i_addr2) == NULL;
1688a1b9b6aSSam Leffler }
1698a1b9b6aSSam Leffler return 0; /* should not happen */
1708a1b9b6aSSam Leffler }
1718a1b9b6aSSam Leffler
1728a1b9b6aSSam Leffler static int
acl_add(struct ieee80211vap * vap,const uint8_t mac[IEEE80211_ADDR_LEN])173b032f27cSSam Leffler acl_add(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1748a1b9b6aSSam Leffler {
175b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
1768a1b9b6aSSam Leffler struct acl *acl, *new;
1778a1b9b6aSSam Leffler int hash;
1788a1b9b6aSSam Leffler
179b9b53389SAdrian Chadd new = (struct acl *) IEEE80211_MALLOC(sizeof(struct acl),
180b9b53389SAdrian Chadd M_80211_ACL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1818a1b9b6aSSam Leffler if (new == NULL) {
182b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
1838a1b9b6aSSam Leffler "ACL: add %s failed, no memory\n", ether_sprintf(mac));
1848a1b9b6aSSam Leffler /* XXX statistic */
1858a1b9b6aSSam Leffler return ENOMEM;
1868a1b9b6aSSam Leffler }
1878a1b9b6aSSam Leffler
1888a1b9b6aSSam Leffler ACL_LOCK(as);
1898a1b9b6aSSam Leffler hash = ACL_HASH(mac);
1908a1b9b6aSSam Leffler LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
1918a1b9b6aSSam Leffler if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
1928a1b9b6aSSam Leffler ACL_UNLOCK(as);
193b9b53389SAdrian Chadd IEEE80211_FREE(new, M_80211_ACL);
194b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
1958a1b9b6aSSam Leffler "ACL: add %s failed, already present\n",
1968a1b9b6aSSam Leffler ether_sprintf(mac));
1978a1b9b6aSSam Leffler return EEXIST;
1988a1b9b6aSSam Leffler }
1998a1b9b6aSSam Leffler }
2008a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
2018a1b9b6aSSam Leffler TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
2028a1b9b6aSSam Leffler LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
203188757f5SSam Leffler as->as_nacls++;
2048a1b9b6aSSam Leffler ACL_UNLOCK(as);
2058a1b9b6aSSam Leffler
206b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2078a1b9b6aSSam Leffler "ACL: add %s\n", ether_sprintf(mac));
2088a1b9b6aSSam Leffler return 0;
2098a1b9b6aSSam Leffler }
2108a1b9b6aSSam Leffler
2118a1b9b6aSSam Leffler static int
acl_remove(struct ieee80211vap * vap,const uint8_t mac[IEEE80211_ADDR_LEN])212b032f27cSSam Leffler acl_remove(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
2138a1b9b6aSSam Leffler {
214b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
2158a1b9b6aSSam Leffler struct acl *acl;
2168a1b9b6aSSam Leffler
2178a1b9b6aSSam Leffler ACL_LOCK(as);
2188a1b9b6aSSam Leffler acl = _find_acl(as, mac);
2198a1b9b6aSSam Leffler if (acl != NULL)
2208a1b9b6aSSam Leffler _acl_free(as, acl);
2218a1b9b6aSSam Leffler ACL_UNLOCK(as);
2228a1b9b6aSSam Leffler
223b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2248a1b9b6aSSam Leffler "ACL: remove %s%s\n", ether_sprintf(mac),
2258a1b9b6aSSam Leffler acl == NULL ? ", not present" : "");
2268a1b9b6aSSam Leffler
2278a1b9b6aSSam Leffler return (acl == NULL ? ENOENT : 0);
2288a1b9b6aSSam Leffler }
2298a1b9b6aSSam Leffler
2308a1b9b6aSSam Leffler static int
acl_free_all(struct ieee80211vap * vap)231b032f27cSSam Leffler acl_free_all(struct ieee80211vap *vap)
2328a1b9b6aSSam Leffler {
233b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
2348a1b9b6aSSam Leffler struct acl *acl;
2358a1b9b6aSSam Leffler
236b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
2378a1b9b6aSSam Leffler
2388a1b9b6aSSam Leffler ACL_LOCK(as);
2398a1b9b6aSSam Leffler while ((acl = TAILQ_FIRST(&as->as_list)) != NULL)
2408a1b9b6aSSam Leffler _acl_free(as, acl);
2418a1b9b6aSSam Leffler ACL_UNLOCK(as);
2428a1b9b6aSSam Leffler
2438a1b9b6aSSam Leffler return 0;
2448a1b9b6aSSam Leffler }
2458a1b9b6aSSam Leffler
2468a1b9b6aSSam Leffler static int
acl_setpolicy(struct ieee80211vap * vap,int policy)247b032f27cSSam Leffler acl_setpolicy(struct ieee80211vap *vap, int policy)
2488a1b9b6aSSam Leffler {
249b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
2508a1b9b6aSSam Leffler
251b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2528a1b9b6aSSam Leffler "ACL: set policy to %u\n", policy);
2538a1b9b6aSSam Leffler
2548a1b9b6aSSam Leffler switch (policy) {
2558a1b9b6aSSam Leffler case IEEE80211_MACCMD_POLICY_OPEN:
2568a1b9b6aSSam Leffler as->as_policy = ACL_POLICY_OPEN;
2578a1b9b6aSSam Leffler break;
2588a1b9b6aSSam Leffler case IEEE80211_MACCMD_POLICY_ALLOW:
2598a1b9b6aSSam Leffler as->as_policy = ACL_POLICY_ALLOW;
2608a1b9b6aSSam Leffler break;
2618a1b9b6aSSam Leffler case IEEE80211_MACCMD_POLICY_DENY:
2628a1b9b6aSSam Leffler as->as_policy = ACL_POLICY_DENY;
2638a1b9b6aSSam Leffler break;
264b032f27cSSam Leffler case IEEE80211_MACCMD_POLICY_RADIUS:
265b032f27cSSam Leffler as->as_policy = ACL_POLICY_RADIUS;
266b032f27cSSam Leffler break;
2678a1b9b6aSSam Leffler default:
2688a1b9b6aSSam Leffler return EINVAL;
2698a1b9b6aSSam Leffler }
2708a1b9b6aSSam Leffler return 0;
2718a1b9b6aSSam Leffler }
2728a1b9b6aSSam Leffler
2738a1b9b6aSSam Leffler static int
acl_getpolicy(struct ieee80211vap * vap)274b032f27cSSam Leffler acl_getpolicy(struct ieee80211vap *vap)
2758a1b9b6aSSam Leffler {
276b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
2778a1b9b6aSSam Leffler
2788a1b9b6aSSam Leffler return as->as_policy;
2798a1b9b6aSSam Leffler }
2808a1b9b6aSSam Leffler
281188757f5SSam Leffler static int
acl_setioctl(struct ieee80211vap * vap,struct ieee80211req * ireq)282b032f27cSSam Leffler acl_setioctl(struct ieee80211vap *vap, struct ieee80211req *ireq)
283188757f5SSam Leffler {
284188757f5SSam Leffler
285188757f5SSam Leffler return EINVAL;
286188757f5SSam Leffler }
287188757f5SSam Leffler
288188757f5SSam Leffler static int
acl_getioctl(struct ieee80211vap * vap,struct ieee80211req * ireq)289b032f27cSSam Leffler acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq)
290188757f5SSam Leffler {
291b032f27cSSam Leffler struct aclstate *as = vap->iv_as;
292188757f5SSam Leffler struct acl *acl;
293188757f5SSam Leffler struct ieee80211req_maclist *ap;
294db9ff08bSKevin Lo int error;
295db9ff08bSKevin Lo uint32_t i, space;
296188757f5SSam Leffler
297188757f5SSam Leffler switch (ireq->i_val) {
298188757f5SSam Leffler case IEEE80211_MACCMD_POLICY:
299188757f5SSam Leffler ireq->i_val = as->as_policy;
300188757f5SSam Leffler return 0;
301188757f5SSam Leffler case IEEE80211_MACCMD_LIST:
302188757f5SSam Leffler space = as->as_nacls * IEEE80211_ADDR_LEN;
303188757f5SSam Leffler if (ireq->i_len == 0) {
304188757f5SSam Leffler ireq->i_len = space; /* return required space */
305188757f5SSam Leffler return 0; /* NB: must not error */
306188757f5SSam Leffler }
307b9b53389SAdrian Chadd ap = (struct ieee80211req_maclist *) IEEE80211_MALLOC(space,
308b9b53389SAdrian Chadd M_TEMP, IEEE80211_M_NOWAIT);
309188757f5SSam Leffler if (ap == NULL)
310188757f5SSam Leffler return ENOMEM;
311188757f5SSam Leffler i = 0;
312188757f5SSam Leffler ACL_LOCK(as);
313188757f5SSam Leffler TAILQ_FOREACH(acl, &as->as_list, acl_list) {
314188757f5SSam Leffler IEEE80211_ADDR_COPY(ap[i].ml_macaddr, acl->acl_macaddr);
315188757f5SSam Leffler i++;
316188757f5SSam Leffler }
317188757f5SSam Leffler ACL_UNLOCK(as);
318188757f5SSam Leffler if (ireq->i_len >= space) {
319188757f5SSam Leffler error = copyout(ap, ireq->i_data, space);
320188757f5SSam Leffler ireq->i_len = space;
321188757f5SSam Leffler } else
322188757f5SSam Leffler error = copyout(ap, ireq->i_data, ireq->i_len);
323b9b53389SAdrian Chadd IEEE80211_FREE(ap, M_TEMP);
324188757f5SSam Leffler return error;
325188757f5SSam Leffler }
326188757f5SSam Leffler return EINVAL;
327188757f5SSam Leffler }
328188757f5SSam Leffler
3298a1b9b6aSSam Leffler static const struct ieee80211_aclator mac = {
3308a1b9b6aSSam Leffler .iac_name = "mac",
3318a1b9b6aSSam Leffler .iac_attach = acl_attach,
3328a1b9b6aSSam Leffler .iac_detach = acl_detach,
3338a1b9b6aSSam Leffler .iac_check = acl_check,
3348a1b9b6aSSam Leffler .iac_add = acl_add,
3358a1b9b6aSSam Leffler .iac_remove = acl_remove,
3368a1b9b6aSSam Leffler .iac_flush = acl_free_all,
3378a1b9b6aSSam Leffler .iac_setpolicy = acl_setpolicy,
3388a1b9b6aSSam Leffler .iac_getpolicy = acl_getpolicy,
339188757f5SSam Leffler .iac_setioctl = acl_setioctl,
340188757f5SSam Leffler .iac_getioctl = acl_getioctl,
3418a1b9b6aSSam Leffler };
342b032f27cSSam Leffler IEEE80211_ACL_MODULE(wlan_acl, mac, 1);
343