s1g.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * S1G handling
  4. * Copyright(c) 2020 Adapt-IP
  5. * Copyright (C) 2023 Intel Corporation
  6. */
  7. #include <linux/ieee80211.h>
  8. #include <net/mac80211.h>
  9. #include "ieee80211_i.h"
  10. #include "driver-ops.h"
  11. void ieee80211_s1g_sta_rate_init(struct sta_info *sta)
  12. {
  13. /* avoid indicating legacy bitrates for S1G STAs */
  14. sta->deflink.tx_stats.last_rate.flags |= IEEE80211_TX_RC_S1G_MCS;
  15. sta->deflink.rx_stats.last_rate =
  16. STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G);
  17. }
  18. bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb)
  19. {
  20. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
  21. if (likely(!ieee80211_is_action(mgmt->frame_control)))
  22. return false;
  23. if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G))
  24. return false;
  25. return mgmt->u.action.u.s1g.action_code == WLAN_S1G_TWT_SETUP;
  26. }
  27. static void
  28. ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da,
  29. const u8 *bssid, struct ieee80211_twt_setup *twt)
  30. {
  31. int len = IEEE80211_MIN_ACTION_SIZE + 4 + twt->length;
  32. struct ieee80211_local *local = sdata->local;
  33. struct ieee80211_mgmt *mgmt;
  34. struct sk_buff *skb;
  35. skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
  36. if (!skb)
  37. return;
  38. skb_reserve(skb, local->hw.extra_tx_headroom);
  39. mgmt = skb_put_zero(skb, len);
  40. mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  41. IEEE80211_STYPE_ACTION);
  42. memcpy(mgmt->da, da, ETH_ALEN);
  43. memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
  44. memcpy(mgmt->bssid, bssid, ETH_ALEN);
  45. mgmt->u.action.category = WLAN_CATEGORY_S1G;
  46. mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_SETUP;
  47. memcpy(mgmt->u.action.u.s1g.variable, twt, 3 + twt->length);
  48. IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
  49. IEEE80211_TX_INTFL_MLME_CONN_TX |
  50. IEEE80211_TX_CTL_REQ_TX_STATUS;
  51. ieee80211_tx_skb(sdata, skb);
  52. }
  53. static void
  54. ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata,
  55. const u8 *da, const u8 *bssid, u8 flowid)
  56. {
  57. struct ieee80211_local *local = sdata->local;
  58. struct ieee80211_mgmt *mgmt;
  59. struct sk_buff *skb;
  60. u8 *id;
  61. skb = dev_alloc_skb(local->hw.extra_tx_headroom +
  62. IEEE80211_MIN_ACTION_SIZE + 2);
  63. if (!skb)
  64. return;
  65. skb_reserve(skb, local->hw.extra_tx_headroom);
  66. mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE + 2);
  67. mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  68. IEEE80211_STYPE_ACTION);
  69. memcpy(mgmt->da, da, ETH_ALEN);
  70. memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
  71. memcpy(mgmt->bssid, bssid, ETH_ALEN);
  72. mgmt->u.action.category = WLAN_CATEGORY_S1G;
  73. mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_TEARDOWN;
  74. id = (u8 *)mgmt->u.action.u.s1g.variable;
  75. *id = flowid;
  76. IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
  77. IEEE80211_TX_CTL_REQ_TX_STATUS;
  78. ieee80211_tx_skb(sdata, skb);
  79. }
  80. static void
  81. ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
  82. struct sta_info *sta, struct sk_buff *skb)
  83. {
  84. struct ieee80211_mgmt *mgmt = (void *)skb->data;
  85. struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
  86. struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
  87. twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST);
  88. /* broadcast TWT not supported yet */
  89. if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) {
  90. twt_agrt->req_type &=
  91. ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD);
  92. twt_agrt->req_type |=
  93. le16_encode_bits(TWT_SETUP_CMD_REJECT,
  94. IEEE80211_TWT_REQTYPE_SETUP_CMD);
  95. goto out;
  96. }
  97. /* TWT Information not supported yet */
  98. twt->control |= IEEE80211_TWT_CONTROL_RX_DISABLED;
  99. drv_add_twt_setup(sdata->local, sdata, &sta->sta, twt);
  100. out:
  101. ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, twt);
  102. }
  103. static void
  104. ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data *sdata,
  105. struct sta_info *sta, struct sk_buff *skb)
  106. {
  107. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
  108. drv_twt_teardown_request(sdata->local, sdata, &sta->sta,
  109. mgmt->u.action.u.s1g.variable[0]);
  110. }
  111. static void
  112. ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata,
  113. struct sta_info *sta, struct sk_buff *skb)
  114. {
  115. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
  116. struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
  117. struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
  118. u8 flowid = le16_get_bits(twt_agrt->req_type,
  119. IEEE80211_TWT_REQTYPE_FLOWID);
  120. drv_twt_teardown_request(sdata->local, sdata, &sta->sta, flowid);
  121. ieee80211_s1g_send_twt_teardown(sdata, mgmt->sa, sdata->vif.addr,
  122. flowid);
  123. }
  124. void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
  125. struct sk_buff *skb)
  126. {
  127. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
  128. struct ieee80211_local *local = sdata->local;
  129. struct sta_info *sta;
  130. lockdep_assert_wiphy(local->hw.wiphy);
  131. sta = sta_info_get_bss(sdata, mgmt->sa);
  132. if (!sta)
  133. return;
  134. switch (mgmt->u.action.u.s1g.action_code) {
  135. case WLAN_S1G_TWT_SETUP:
  136. ieee80211_s1g_rx_twt_setup(sdata, sta, skb);
  137. break;
  138. case WLAN_S1G_TWT_TEARDOWN:
  139. ieee80211_s1g_rx_twt_teardown(sdata, sta, skb);
  140. break;
  141. default:
  142. break;
  143. }
  144. }
  145. void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
  146. struct sk_buff *skb)
  147. {
  148. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
  149. struct ieee80211_local *local = sdata->local;
  150. struct sta_info *sta;
  151. lockdep_assert_wiphy(local->hw.wiphy);
  152. sta = sta_info_get_bss(sdata, mgmt->da);
  153. if (!sta)
  154. return;
  155. switch (mgmt->u.action.u.s1g.action_code) {
  156. case WLAN_S1G_TWT_SETUP:
  157. /* process failed twt setup frames */
  158. ieee80211_s1g_tx_twt_setup_fail(sdata, sta, skb);
  159. break;
  160. default:
  161. break;
  162. }
  163. }