xref: /freebsd/sys/compat/linuxkpi/common/src/linux_80211.h (revision 6b4cac814e32f3b307720d6b880939fb1f21f3ac)
1*6b4cac81SBjoern A. Zeeb /*-
2*6b4cac81SBjoern A. Zeeb  * Copyright (c) 2020-2021 The FreeBSD Foundation
3*6b4cac81SBjoern A. Zeeb  * Copyright (c) 2020-2021 Bjoern A. Zeeb
4*6b4cac81SBjoern A. Zeeb  *
5*6b4cac81SBjoern A. Zeeb  * This software was developed by Björn Zeeb under sponsorship from
6*6b4cac81SBjoern A. Zeeb  * the FreeBSD Foundation.
7*6b4cac81SBjoern A. Zeeb  *
8*6b4cac81SBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
9*6b4cac81SBjoern A. Zeeb  * modification, are permitted provided that the following conditions
10*6b4cac81SBjoern A. Zeeb  * are met:
11*6b4cac81SBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
12*6b4cac81SBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
13*6b4cac81SBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
14*6b4cac81SBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
15*6b4cac81SBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
16*6b4cac81SBjoern A. Zeeb  *
17*6b4cac81SBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*6b4cac81SBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*6b4cac81SBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*6b4cac81SBjoern A. Zeeb  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*6b4cac81SBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*6b4cac81SBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*6b4cac81SBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*6b4cac81SBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*6b4cac81SBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*6b4cac81SBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*6b4cac81SBjoern A. Zeeb  * SUCH DAMAGE.
28*6b4cac81SBjoern A. Zeeb  */
29*6b4cac81SBjoern A. Zeeb 
30*6b4cac81SBjoern A. Zeeb /*
31*6b4cac81SBjoern A. Zeeb  * Public functions are called linuxkpi_*().
32*6b4cac81SBjoern A. Zeeb  * Internal (static) functions are called lkpi_*().
33*6b4cac81SBjoern A. Zeeb  *
34*6b4cac81SBjoern A. Zeeb  * The internal structures holding metadata over public structures are also
35*6b4cac81SBjoern A. Zeeb  * called lkpi_xxx (usually with a member at the end called xxx).
36*6b4cac81SBjoern A. Zeeb  * Note: we do not replicate the structure names but the general variable names
37*6b4cac81SBjoern A. Zeeb  * for these (e.g., struct hw -> struct lkpi_hw, struct sta -> struct lkpi_sta).
38*6b4cac81SBjoern A. Zeeb  * There are macros to access one from the other.
39*6b4cac81SBjoern A. Zeeb  * We call the internal versions lxxx (e.g., hw -> lhw, sta -> lsta).
40*6b4cac81SBjoern A. Zeeb  */
41*6b4cac81SBjoern A. Zeeb 
42*6b4cac81SBjoern A. Zeeb #ifndef _LKPI_SRC_LINUX_80211_H
43*6b4cac81SBjoern A. Zeeb #define _LKPI_SRC_LINUX_80211_H
44*6b4cac81SBjoern A. Zeeb 
45*6b4cac81SBjoern A. Zeeb struct lkpi_radiotap_tx_hdr {
46*6b4cac81SBjoern A. Zeeb 	struct ieee80211_radiotap_header wt_ihdr;
47*6b4cac81SBjoern A. Zeeb 	uint8_t		wt_flags;
48*6b4cac81SBjoern A. Zeeb 	uint8_t		wt_rate;
49*6b4cac81SBjoern A. Zeeb 	uint16_t	wt_chan_freq;
50*6b4cac81SBjoern A. Zeeb 	uint16_t	wt_chan_flags;
51*6b4cac81SBjoern A. Zeeb } __packed;
52*6b4cac81SBjoern A. Zeeb #define	LKPI_RTAP_TX_FLAGS_PRESENT					\
53*6b4cac81SBjoern A. Zeeb 	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
54*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_RATE) |				\
55*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_CHANNEL))
56*6b4cac81SBjoern A. Zeeb 
57*6b4cac81SBjoern A. Zeeb struct lkpi_radiotap_rx_hdr {
58*6b4cac81SBjoern A. Zeeb 	struct ieee80211_radiotap_header wr_ihdr;
59*6b4cac81SBjoern A. Zeeb 	uint64_t	wr_tsft;
60*6b4cac81SBjoern A. Zeeb 	uint8_t		wr_flags;
61*6b4cac81SBjoern A. Zeeb 	uint8_t		wr_rate;
62*6b4cac81SBjoern A. Zeeb 	uint16_t	wr_chan_freq;
63*6b4cac81SBjoern A. Zeeb 	uint16_t	wr_chan_flags;
64*6b4cac81SBjoern A. Zeeb 	int8_t		wr_dbm_antsignal;
65*6b4cac81SBjoern A. Zeeb 	int8_t		wr_dbm_antnoise;
66*6b4cac81SBjoern A. Zeeb } __packed __aligned(8);
67*6b4cac81SBjoern A. Zeeb #define	LKPI_RTAP_RX_FLAGS_PRESENT					\
68*6b4cac81SBjoern A. Zeeb 	((1 << IEEE80211_RADIOTAP_TSFT) |				\
69*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_FLAGS) |				\
70*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_RATE) |				\
71*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_CHANNEL) |				\
72*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |			\
73*6b4cac81SBjoern A. Zeeb 	 (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE))
74*6b4cac81SBjoern A. Zeeb 
75*6b4cac81SBjoern A. Zeeb struct lkpi_txq {
76*6b4cac81SBjoern A. Zeeb 	bool			seen_dequeue;
77*6b4cac81SBjoern A. Zeeb 	struct sk_buff_head	skbq;
78*6b4cac81SBjoern A. Zeeb 
79*6b4cac81SBjoern A. Zeeb 	/* Must be last! */
80*6b4cac81SBjoern A. Zeeb 	struct ieee80211_txq	txq __aligned(CACHE_LINE_SIZE);
81*6b4cac81SBjoern A. Zeeb };
82*6b4cac81SBjoern A. Zeeb #define	TXQ_TO_LTXQ(_txq)	container_of(_txq, struct lkpi_txq, txq)
83*6b4cac81SBjoern A. Zeeb 
84*6b4cac81SBjoern A. Zeeb 
85*6b4cac81SBjoern A. Zeeb struct lkpi_sta {
86*6b4cac81SBjoern A. Zeeb         TAILQ_ENTRY(lkpi_sta)	lsta_entry;
87*6b4cac81SBjoern A. Zeeb 	struct ieee80211_node	*ni;
88*6b4cac81SBjoern A. Zeeb 
89*6b4cac81SBjoern A. Zeeb 	/* Deferred TX path. */
90*6b4cac81SBjoern A. Zeeb 	/* Eventually we might want to migrate this into net80211 entirely. */
91*6b4cac81SBjoern A. Zeeb 	/* XXX-BZ can we use sta->txq[] instead directly? */
92*6b4cac81SBjoern A. Zeeb 	struct task		txq_task;
93*6b4cac81SBjoern A. Zeeb 	struct mbufq		txq;
94*6b4cac81SBjoern A. Zeeb 	struct mtx		txq_mtx;
95*6b4cac81SBjoern A. Zeeb 
96*6b4cac81SBjoern A. Zeeb 	struct ieee80211_key_conf *kc;
97*6b4cac81SBjoern A. Zeeb 	enum ieee80211_sta_state state;
98*6b4cac81SBjoern A. Zeeb 	bool			added_to_drv;			/* Driver knows; i.e. we called ...(). */
99*6b4cac81SBjoern A. Zeeb 	bool			in_mgd;
100*6b4cac81SBjoern A. Zeeb 
101*6b4cac81SBjoern A. Zeeb 	/* Must be last! */
102*6b4cac81SBjoern A. Zeeb 	struct ieee80211_sta	sta __aligned(CACHE_LINE_SIZE);
103*6b4cac81SBjoern A. Zeeb };
104*6b4cac81SBjoern A. Zeeb #define	STA_TO_LSTA(_sta)	container_of(_sta, struct lkpi_sta, sta)
105*6b4cac81SBjoern A. Zeeb #define	LSTA_TO_STA(_lsta)	(&(_lsta)->sta)
106*6b4cac81SBjoern A. Zeeb 
107*6b4cac81SBjoern A. Zeeb struct lkpi_vif {
108*6b4cac81SBjoern A. Zeeb         TAILQ_ENTRY(lkpi_vif)	lvif_entry;
109*6b4cac81SBjoern A. Zeeb 	struct ieee80211vap	iv_vap;
110*6b4cac81SBjoern A. Zeeb 
111*6b4cac81SBjoern A. Zeeb 	struct mtx		mtx;
112*6b4cac81SBjoern A. Zeeb 	struct wireless_dev	wdev;
113*6b4cac81SBjoern A. Zeeb 
114*6b4cac81SBjoern A. Zeeb 	/* Other local stuff. */
115*6b4cac81SBjoern A. Zeeb 	int			(*iv_newstate)(struct ieee80211vap *,
116*6b4cac81SBjoern A. Zeeb 				    enum ieee80211_state, int);
117*6b4cac81SBjoern A. Zeeb 	TAILQ_HEAD(, lkpi_sta)	lsta_head;
118*6b4cac81SBjoern A. Zeeb 	bool			added_to_drv;			/* Driver knows; i.e. we called add_interface(). */
119*6b4cac81SBjoern A. Zeeb 
120*6b4cac81SBjoern A. Zeeb 	/* Must be last! */
121*6b4cac81SBjoern A. Zeeb 	struct ieee80211_vif	vif __aligned(CACHE_LINE_SIZE);
122*6b4cac81SBjoern A. Zeeb };
123*6b4cac81SBjoern A. Zeeb #define	VAP_TO_LVIF(_vap)	container_of(_vap, struct lkpi_vif, iv_vap)
124*6b4cac81SBjoern A. Zeeb #define	LVIF_TO_VAP(_lvif)	(&(_lvif)->iv_vap)
125*6b4cac81SBjoern A. Zeeb #define	VIF_TO_LVIF(_vif)	container_of(_vif, struct lkpi_vif, vif)
126*6b4cac81SBjoern A. Zeeb #define	LVIF_TO_VIF(_lvif)	(&(_lvif)->vif)
127*6b4cac81SBjoern A. Zeeb 
128*6b4cac81SBjoern A. Zeeb 
129*6b4cac81SBjoern A. Zeeb struct lkpi_hw {	/* name it mac80211_sc? */
130*6b4cac81SBjoern A. Zeeb 	const struct ieee80211_ops	*ops;
131*6b4cac81SBjoern A. Zeeb 	struct ieee80211_scan_request	*hw_req;
132*6b4cac81SBjoern A. Zeeb 	struct workqueue_struct		*workq;
133*6b4cac81SBjoern A. Zeeb 
134*6b4cac81SBjoern A. Zeeb 	/* FreeBSD specific compat. */
135*6b4cac81SBjoern A. Zeeb 	/* Linux device is in hw.wiphy->dev after SET_IEEE80211_DEV(). */
136*6b4cac81SBjoern A. Zeeb 	struct ieee80211com		*ic;
137*6b4cac81SBjoern A. Zeeb 	struct lkpi_radiotap_tx_hdr	rtap_tx;
138*6b4cac81SBjoern A. Zeeb 	struct lkpi_radiotap_rx_hdr	rtap_rx;
139*6b4cac81SBjoern A. Zeeb 
140*6b4cac81SBjoern A. Zeeb 	TAILQ_HEAD(, lkpi_vif)		lvif_head;
141*6b4cac81SBjoern A. Zeeb 
142*6b4cac81SBjoern A. Zeeb 	struct mtx			mtx;
143*6b4cac81SBjoern A. Zeeb 
144*6b4cac81SBjoern A. Zeeb 	/* Node functions we overload to sync state. */
145*6b4cac81SBjoern A. Zeeb 	struct ieee80211_node *	(*ic_node_alloc)(struct ieee80211vap *,
146*6b4cac81SBjoern A. Zeeb 				    const uint8_t [IEEE80211_ADDR_LEN]);
147*6b4cac81SBjoern A. Zeeb 	int			(*ic_node_init)(struct ieee80211_node *);
148*6b4cac81SBjoern A. Zeeb 	void			(*ic_node_cleanup)(struct ieee80211_node *);
149*6b4cac81SBjoern A. Zeeb 	void			(*ic_node_free)(struct ieee80211_node *);
150*6b4cac81SBjoern A. Zeeb 
151*6b4cac81SBjoern A. Zeeb #define	LKPI_MAC80211_DRV_STARTED	0x00000001
152*6b4cac81SBjoern A. Zeeb 	uint32_t			sc_flags;
153*6b4cac81SBjoern A. Zeeb #define	LKPI_SCAN_RUNNING		0x00000001
154*6b4cac81SBjoern A. Zeeb 	uint32_t			scan_flags;
155*6b4cac81SBjoern A. Zeeb 	bool				update_mc;
156*6b4cac81SBjoern A. Zeeb 
157*6b4cac81SBjoern A. Zeeb 	/* Must be last! */
158*6b4cac81SBjoern A. Zeeb 	struct ieee80211_hw		hw __aligned(CACHE_LINE_SIZE);
159*6b4cac81SBjoern A. Zeeb };
160*6b4cac81SBjoern A. Zeeb #define	LHW_TO_HW(_lhw)		(&(_lhw)->hw)
161*6b4cac81SBjoern A. Zeeb #define	HW_TO_LHW(_hw)		container_of(_hw, struct lkpi_hw, hw)
162*6b4cac81SBjoern A. Zeeb 
163*6b4cac81SBjoern A. Zeeb struct lkpi_wiphy {
164*6b4cac81SBjoern A. Zeeb 	const struct cfg80211_ops	*ops;
165*6b4cac81SBjoern A. Zeeb 
166*6b4cac81SBjoern A. Zeeb 	/* Must be last! */
167*6b4cac81SBjoern A. Zeeb 	struct wiphy			wiphy __aligned(CACHE_LINE_SIZE);
168*6b4cac81SBjoern A. Zeeb };
169*6b4cac81SBjoern A. Zeeb #define	WIPHY_TO_LWIPHY(_wiphy)	container_of(_wiphy, struct lkpi_wiphy, wiphy)
170*6b4cac81SBjoern A. Zeeb #define	LWIPHY_TO_WIPHY(_lwiphy)	(&(_lwiphy)->wiphy)
171*6b4cac81SBjoern A. Zeeb 
172*6b4cac81SBjoern A. Zeeb 
173*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LHW_LOCK(_lhw)	mtx_lock(&(_lhw)->mtx)
174*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LHW_UNLOCK(_lhw)	mtx_unlock(&(_lhw)->mtx)
175*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LHW_LOCK_ASSERT(_lhw) \
176*6b4cac81SBjoern A. Zeeb     mtx_assert(&(_lhw)->mtx, MA_OWNED)
177*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LHW_UNLOCK_ASSERT(_lhw) \
178*6b4cac81SBjoern A. Zeeb     mtx_assert(&(_lhw)->mtx, MA_NOTOWNED)
179*6b4cac81SBjoern A. Zeeb 
180*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LVIF_LOCK(_lvif)	mtx_lock(&(_lvif)->mtx)
181*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LVIF_UNLOCK(_lvif)	mtx_unlock(&(_lvif)->mtx)
182*6b4cac81SBjoern A. Zeeb 
183*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LSTA_LOCK(_lsta)	mtx_lock(&(_lsta)->txq_mtx)
184*6b4cac81SBjoern A. Zeeb #define	LKPI_80211_LSTA_UNLOCK(_lsta)	mtx_unlock(&(_lsta)->txq_mtx)
185*6b4cac81SBjoern A. Zeeb 
186*6b4cac81SBjoern A. Zeeb 
187*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_start(struct ieee80211_hw *);
188*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_stop(struct ieee80211_hw *);
189*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *, uint32_t);
190*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *, uint32_t);
191*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_add_interface(struct ieee80211_hw *, struct ieee80211_vif *);
192*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_remove_interface(struct ieee80211_hw *, struct ieee80211_vif *);
193*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_hw_scan(struct ieee80211_hw *, struct ieee80211_vif *,
194*6b4cac81SBjoern A. Zeeb     struct ieee80211_scan_request *);
195*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *, struct ieee80211_vif *);
196*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *, struct ieee80211_vif *);
197*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *, struct ieee80211_vif *,
198*6b4cac81SBjoern A. Zeeb     const u8 *);
199*6b4cac81SBjoern A. Zeeb u64 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *,
200*6b4cac81SBjoern A. Zeeb     struct netdev_hw_addr_list *);
201*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_configure_filter(struct ieee80211_hw *, unsigned int,
202*6b4cac81SBjoern A. Zeeb     unsigned int *, u64);
203*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_sta_state(struct ieee80211_hw *, struct ieee80211_vif *,
204*6b4cac81SBjoern A. Zeeb     struct ieee80211_sta *, enum ieee80211_sta_state);
205*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_config(struct ieee80211_hw *, uint32_t);
206*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *, struct ieee80211_vif *,
207*6b4cac81SBjoern A. Zeeb     struct ieee80211_chanctx_conf *);
208*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *, struct ieee80211_vif *,
209*6b4cac81SBjoern A. Zeeb     struct ieee80211_chanctx_conf **);
210*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_add_chanctx(struct ieee80211_hw *, struct ieee80211_chanctx_conf *);
211*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_change_chanctx(struct ieee80211_hw *,
212*6b4cac81SBjoern A. Zeeb     struct ieee80211_chanctx_conf *, uint32_t);
213*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *,
214*6b4cac81SBjoern A. Zeeb     struct ieee80211_chanctx_conf *);
215*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *, struct ieee80211_vif *,
216*6b4cac81SBjoern A. Zeeb     struct ieee80211_bss_conf *, uint32_t);
217*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_conf_tx(struct ieee80211_hw *, struct ieee80211_vif *,
218*6b4cac81SBjoern A. Zeeb     uint16_t, const struct ieee80211_tx_queue_params *);
219*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_flush(struct ieee80211_hw *, struct ieee80211_vif *,
220*6b4cac81SBjoern A. Zeeb     uint32_t, bool);
221*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *, struct ieee80211_vif *,
222*6b4cac81SBjoern A. Zeeb     struct ieee80211_prep_tx_info *);
223*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *, struct ieee80211_vif *,
224*6b4cac81SBjoern A. Zeeb     struct ieee80211_prep_tx_info *);
225*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_tx(struct ieee80211_hw *, struct ieee80211_tx_control *,
226*6b4cac81SBjoern A. Zeeb     struct sk_buff *);
227*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *, struct ieee80211_txq *);
228*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *);
229*6b4cac81SBjoern A. Zeeb void lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *,
230*6b4cac81SBjoern A. Zeeb     struct ieee80211_vif *, struct ieee80211_sta *);
231*6b4cac81SBjoern A. Zeeb int lkpi_80211_mo_set_key(struct ieee80211_hw *, enum set_key_cmd,
232*6b4cac81SBjoern A. Zeeb     struct ieee80211_vif *, struct ieee80211_sta *,
233*6b4cac81SBjoern A. Zeeb     struct ieee80211_key_conf *);
234*6b4cac81SBjoern A. Zeeb 
235*6b4cac81SBjoern A. Zeeb #endif	/* _LKPI_SRC_LINUX_80211_H */
236