s1g.c 5.6 KB

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