diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-09-26 11:53:18 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:54:18 -0400 |
commit | 58d4185e36913d4fc94afa4b4daccb3c9aa01957 (patch) | |
tree | 77d2e8e423652f5bbf2e29e8c0b3e0aeb7858b9f /net/mac80211 | |
parent | 628a140ba033ef201706a8c7e767c8a0c0f8326c (diff) |
[MAC80211]: improve radiotap injection
This improves radiotap injection by removing the shortcut over TX handlers
that led to BUGS when injecting frames without setting a rate and also
resulted in various other quirks. Now, TX handlers are run but some
information that was present in the radiotap header is used instead of
automatic settings.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Andy Green <andy@warmcat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/tx.c | 195 |
2 files changed, 105 insertions, 91 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d24b0574c436..0fe077747082 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -122,6 +122,7 @@ typedef enum { | |||
122 | #define IEEE80211_TXRXD_RXIN_SCAN BIT(4) | 122 | #define IEEE80211_TXRXD_RXIN_SCAN BIT(4) |
123 | /* frame is destined to interface currently processed (incl. multicast frames) */ | 123 | /* frame is destined to interface currently processed (incl. multicast frames) */ |
124 | #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) | 124 | #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) |
125 | #define IEEE80211_TXRXD_TX_INJECTED BIT(6) | ||
125 | struct ieee80211_txrx_data { | 126 | struct ieee80211_txrx_data { |
126 | struct sk_buff *skb; | 127 | struct sk_buff *skb; |
127 | struct net_device *dev; | 128 | struct net_device *dev; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 47416b0645db..1a531543bccb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -222,6 +222,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | |||
222 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 222 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
223 | u32 sta_flags; | 223 | u32 sta_flags; |
224 | 224 | ||
225 | if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) | ||
226 | return TXRX_CONTINUE; | ||
227 | |||
225 | if (unlikely(tx->local->sta_scanning != 0) && | 228 | if (unlikely(tx->local->sta_scanning != 0) && |
226 | ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || | 229 | ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || |
227 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) | 230 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) |
@@ -566,22 +569,27 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) | |||
566 | { | 569 | { |
567 | struct rate_control_extra extra; | 570 | struct rate_control_extra extra; |
568 | 571 | ||
569 | memset(&extra, 0, sizeof(extra)); | 572 | if (likely(!tx->u.tx.rate)) { |
570 | extra.mode = tx->u.tx.mode; | 573 | memset(&extra, 0, sizeof(extra)); |
571 | extra.ethertype = tx->ethertype; | 574 | extra.mode = tx->u.tx.mode; |
572 | 575 | extra.ethertype = tx->ethertype; | |
573 | tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, | 576 | |
574 | &extra); | 577 | tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, |
575 | if (unlikely(extra.probe != NULL)) { | 578 | tx->skb, &extra); |
576 | tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; | 579 | if (unlikely(extra.probe != NULL)) { |
577 | tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; | 580 | tx->u.tx.control->flags |= |
578 | tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; | 581 | IEEE80211_TXCTL_RATE_CTRL_PROBE; |
579 | tx->u.tx.rate = extra.probe; | 582 | tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; |
580 | } else { | 583 | tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; |
584 | tx->u.tx.rate = extra.probe; | ||
585 | } else | ||
586 | tx->u.tx.control->alt_retry_rate = -1; | ||
587 | |||
588 | if (!tx->u.tx.rate) | ||
589 | return TXRX_DROP; | ||
590 | } else | ||
581 | tx->u.tx.control->alt_retry_rate = -1; | 591 | tx->u.tx.control->alt_retry_rate = -1; |
582 | } | 592 | |
583 | if (!tx->u.tx.rate) | ||
584 | return TXRX_DROP; | ||
585 | if (tx->u.tx.mode->mode == MODE_IEEE80211G && | 593 | if (tx->u.tx.mode->mode == MODE_IEEE80211G && |
586 | (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && | 594 | (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && |
587 | (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { | 595 | (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { |
@@ -611,19 +619,24 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) | |||
611 | struct ieee80211_tx_control *control = tx->u.tx.control; | 619 | struct ieee80211_tx_control *control = tx->u.tx.control; |
612 | struct ieee80211_hw_mode *mode = tx->u.tx.mode; | 620 | struct ieee80211_hw_mode *mode = tx->u.tx.mode; |
613 | 621 | ||
614 | if (!is_multicast_ether_addr(hdr->addr1)) { | 622 | if (!control->retry_limit) { |
615 | if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && | 623 | if (!is_multicast_ether_addr(hdr->addr1)) { |
616 | tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { | 624 | if (tx->skb->len + FCS_LEN > tx->local->rts_threshold |
617 | control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; | 625 | && tx->local->rts_threshold < |
618 | control->flags |= IEEE80211_TXCTL_LONG_RETRY_LIMIT; | 626 | IEEE80211_MAX_RTS_THRESHOLD) { |
619 | control->retry_limit = | 627 | control->flags |= |
620 | tx->local->long_retry_limit; | 628 | IEEE80211_TXCTL_USE_RTS_CTS; |
629 | control->flags |= | ||
630 | IEEE80211_TXCTL_LONG_RETRY_LIMIT; | ||
631 | control->retry_limit = | ||
632 | tx->local->long_retry_limit; | ||
633 | } else { | ||
634 | control->retry_limit = | ||
635 | tx->local->short_retry_limit; | ||
636 | } | ||
621 | } else { | 637 | } else { |
622 | control->retry_limit = | 638 | control->retry_limit = 1; |
623 | tx->local->short_retry_limit; | ||
624 | } | 639 | } |
625 | } else { | ||
626 | control->retry_limit = 1; | ||
627 | } | 640 | } |
628 | 641 | ||
629 | if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { | 642 | if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { |
@@ -785,9 +798,8 @@ ieee80211_tx_handler ieee80211_tx_handlers[] = | |||
785 | * with Radiotap Header -- only called for monitor mode interface | 798 | * with Radiotap Header -- only called for monitor mode interface |
786 | */ | 799 | */ |
787 | static ieee80211_txrx_result | 800 | static ieee80211_txrx_result |
788 | __ieee80211_parse_tx_radiotap( | 801 | __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, |
789 | struct ieee80211_txrx_data *tx, | 802 | struct sk_buff *skb) |
790 | struct sk_buff *skb, struct ieee80211_tx_control *control) | ||
791 | { | 803 | { |
792 | /* | 804 | /* |
793 | * this is the moment to interpret and discard the radiotap header that | 805 | * this is the moment to interpret and discard the radiotap header that |
@@ -802,18 +814,11 @@ __ieee80211_parse_tx_radiotap( | |||
802 | (struct ieee80211_radiotap_header *) skb->data; | 814 | (struct ieee80211_radiotap_header *) skb->data; |
803 | struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; | 815 | struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; |
804 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | 816 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); |
817 | struct ieee80211_tx_control *control = tx->u.tx.control; | ||
805 | 818 | ||
806 | /* | 819 | control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; |
807 | * default control situation for all injected packets | 820 | tx->flags |= IEEE80211_TXRXD_TX_INJECTED; |
808 | * FIXME: this does not suit all usage cases, expand to allow control | 821 | tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; |
809 | */ | ||
810 | |||
811 | control->retry_limit = 1; /* no retry */ | ||
812 | control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | | ||
813 | IEEE80211_TXCTL_USE_CTS_PROTECT); | ||
814 | control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | | ||
815 | IEEE80211_TXCTL_NO_ACK; | ||
816 | control->antenna_sel_tx = 0; /* default to default antenna */ | ||
817 | 822 | ||
818 | /* | 823 | /* |
819 | * for every radiotap entry that is present | 824 | * for every radiotap entry that is present |
@@ -846,19 +851,10 @@ __ieee80211_parse_tx_radiotap( | |||
846 | for (i = 0; i < mode->num_rates; i++) { | 851 | for (i = 0; i < mode->num_rates; i++) { |
847 | struct ieee80211_rate *r = &mode->rates[i]; | 852 | struct ieee80211_rate *r = &mode->rates[i]; |
848 | 853 | ||
849 | if (r->rate > target_rate) | 854 | if (r->rate == target_rate) { |
850 | continue; | 855 | tx->u.tx.rate = r; |
851 | 856 | break; | |
852 | control->rate = r; | 857 | } |
853 | |||
854 | if (r->flags & IEEE80211_RATE_PREAMBLE2) | ||
855 | control->tx_rate = r->val2; | ||
856 | else | ||
857 | control->tx_rate = r->val; | ||
858 | |||
859 | /* end on exact match */ | ||
860 | if (r->rate == target_rate) | ||
861 | i = mode->num_rates; | ||
862 | } | 858 | } |
863 | break; | 859 | break; |
864 | 860 | ||
@@ -888,8 +884,19 @@ __ieee80211_parse_tx_radiotap( | |||
888 | 884 | ||
889 | skb_trim(skb, skb->len - FCS_LEN); | 885 | skb_trim(skb, skb->len - FCS_LEN); |
890 | } | 886 | } |
887 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) | ||
888 | control->flags &= | ||
889 | ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; | ||
890 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) | ||
891 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; | ||
891 | break; | 892 | break; |
892 | 893 | ||
894 | /* | ||
895 | * Please update the file | ||
896 | * Documentation/networking/mac80211-injection.txt | ||
897 | * when parsing new fields here. | ||
898 | */ | ||
899 | |||
893 | default: | 900 | default: |
894 | break; | 901 | break; |
895 | } | 902 | } |
@@ -908,14 +915,17 @@ __ieee80211_parse_tx_radiotap( | |||
908 | return TXRX_CONTINUE; | 915 | return TXRX_CONTINUE; |
909 | } | 916 | } |
910 | 917 | ||
911 | static ieee80211_txrx_result inline | 918 | /* |
919 | * initialises @tx | ||
920 | */ | ||
921 | static ieee80211_txrx_result | ||
912 | __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | 922 | __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, |
913 | struct sk_buff *skb, | 923 | struct sk_buff *skb, |
914 | struct net_device *dev, | 924 | struct net_device *dev, |
915 | struct ieee80211_tx_control *control) | 925 | struct ieee80211_tx_control *control) |
916 | { | 926 | { |
917 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 927 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
918 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 928 | struct ieee80211_hdr *hdr; |
919 | struct ieee80211_sub_if_data *sdata; | 929 | struct ieee80211_sub_if_data *sdata; |
920 | ieee80211_txrx_result res = TXRX_CONTINUE; | 930 | ieee80211_txrx_result res = TXRX_CONTINUE; |
921 | 931 | ||
@@ -926,33 +936,31 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
926 | tx->dev = dev; /* use original interface */ | 936 | tx->dev = dev; /* use original interface */ |
927 | tx->local = local; | 937 | tx->local = local; |
928 | tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 938 | tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
929 | 939 | tx->u.tx.control = control; | |
930 | /* | 940 | /* |
931 | * set defaults for things that can be set by | 941 | * Set this flag (used below to indicate "automatic fragmentation"), |
932 | * injected radiotap headers | 942 | * it will be cleared/left by radiotap as desired. |
933 | */ | 943 | */ |
934 | control->power_level = local->hw.conf.power_level; | 944 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; |
935 | control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; | ||
936 | 945 | ||
937 | /* process and remove the injection radiotap header */ | 946 | /* process and remove the injection radiotap header */ |
938 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 947 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
939 | if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { | 948 | if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { |
940 | if (__ieee80211_parse_tx_radiotap(tx, skb, control) == | 949 | if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) |
941 | TXRX_DROP) { | ||
942 | return TXRX_DROP; | 950 | return TXRX_DROP; |
943 | } | 951 | |
944 | /* | 952 | /* |
945 | * we removed the radiotap header after this point, | 953 | * __ieee80211_parse_tx_radiotap has now removed |
946 | * we filled control with what we could use | 954 | * the radiotap header that was present and pre-filled |
947 | * set to the actual ieee header now | 955 | * 'tx' with tx control information. |
948 | */ | 956 | */ |
949 | hdr = (struct ieee80211_hdr *) skb->data; | ||
950 | res = TXRX_QUEUED; /* indication it was monitor packet */ | ||
951 | } | 957 | } |
952 | 958 | ||
959 | hdr = (struct ieee80211_hdr *) skb->data; | ||
960 | |||
953 | tx->sta = sta_info_get(local, hdr->addr1); | 961 | tx->sta = sta_info_get(local, hdr->addr1); |
954 | tx->fc = le16_to_cpu(hdr->frame_control); | 962 | tx->fc = le16_to_cpu(hdr->frame_control); |
955 | tx->u.tx.control = control; | 963 | |
956 | if (is_multicast_ether_addr(hdr->addr1)) { | 964 | if (is_multicast_ether_addr(hdr->addr1)) { |
957 | tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; | 965 | tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; |
958 | control->flags |= IEEE80211_TXCTL_NO_ACK; | 966 | control->flags |= IEEE80211_TXCTL_NO_ACK; |
@@ -960,19 +968,23 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
960 | tx->flags |= IEEE80211_TXRXD_TXUNICAST; | 968 | tx->flags |= IEEE80211_TXRXD_TXUNICAST; |
961 | control->flags &= ~IEEE80211_TXCTL_NO_ACK; | 969 | control->flags &= ~IEEE80211_TXCTL_NO_ACK; |
962 | } | 970 | } |
963 | if (local->fragmentation_threshold < IEEE80211_MAX_FRAG_THRESHOLD && | 971 | |
964 | (tx->flags & IEEE80211_TXRXD_TXUNICAST) && | 972 | if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { |
965 | skb->len + FCS_LEN > local->fragmentation_threshold && | 973 | if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) && |
966 | !local->ops->set_frag_threshold) | 974 | skb->len + FCS_LEN > local->fragmentation_threshold && |
967 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; | 975 | !local->ops->set_frag_threshold) |
968 | else | 976 | tx->flags |= IEEE80211_TXRXD_FRAGMENTED; |
969 | tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; | 977 | else |
978 | tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; | ||
979 | } | ||
980 | |||
970 | if (!tx->sta) | 981 | if (!tx->sta) |
971 | control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; | 982 | control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; |
972 | else if (tx->sta->clear_dst_mask) { | 983 | else if (tx->sta->clear_dst_mask) { |
973 | control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; | 984 | control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; |
974 | tx->sta->clear_dst_mask = 0; | 985 | tx->sta->clear_dst_mask = 0; |
975 | } | 986 | } |
987 | |||
976 | hdrlen = ieee80211_get_hdrlen(tx->fc); | 988 | hdrlen = ieee80211_get_hdrlen(tx->fc); |
977 | if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { | 989 | if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { |
978 | u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; | 990 | u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; |
@@ -984,11 +996,14 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
984 | } | 996 | } |
985 | 997 | ||
986 | /* Device in tx->dev has a reference added; use dev_put(tx->dev) when | 998 | /* Device in tx->dev has a reference added; use dev_put(tx->dev) when |
987 | * finished with it. */ | 999 | * finished with it. |
988 | static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | 1000 | * |
989 | struct sk_buff *skb, | 1001 | * NB: @tx is uninitialised when passed in here |
990 | struct net_device *mdev, | 1002 | */ |
991 | struct ieee80211_tx_control *control) | 1003 | static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, |
1004 | struct sk_buff *skb, | ||
1005 | struct net_device *mdev, | ||
1006 | struct ieee80211_tx_control *control) | ||
992 | { | 1007 | { |
993 | struct ieee80211_tx_packet_data *pkt_data; | 1008 | struct ieee80211_tx_packet_data *pkt_data; |
994 | struct net_device *dev; | 1009 | struct net_device *dev; |
@@ -1001,6 +1016,7 @@ static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, | |||
1001 | } | 1016 | } |
1002 | if (unlikely(!dev)) | 1017 | if (unlikely(!dev)) |
1003 | return -ENODEV; | 1018 | return -ENODEV; |
1019 | /* initialises tx with control */ | ||
1004 | __ieee80211_tx_prepare(tx, skb, dev, control); | 1020 | __ieee80211_tx_prepare(tx, skb, dev, control); |
1005 | return 0; | 1021 | return 0; |
1006 | } | 1022 | } |
@@ -1081,6 +1097,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1081 | return 0; | 1097 | return 0; |
1082 | } | 1098 | } |
1083 | 1099 | ||
1100 | /* initialises tx */ | ||
1084 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); | 1101 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); |
1085 | 1102 | ||
1086 | if (res_prepare == TXRX_DROP) { | 1103 | if (res_prepare == TXRX_DROP) { |
@@ -1097,15 +1114,11 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1097 | sta = tx.sta; | 1114 | sta = tx.sta; |
1098 | tx.u.tx.mode = local->hw.conf.mode; | 1115 | tx.u.tx.mode = local->hw.conf.mode; |
1099 | 1116 | ||
1100 | if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ | 1117 | for (handler = local->tx_handlers; *handler != NULL; |
1101 | res = TXRX_CONTINUE; | 1118 | handler++) { |
1102 | } else { | 1119 | res = (*handler)(&tx); |
1103 | for (handler = local->tx_handlers; *handler != NULL; | 1120 | if (res != TXRX_CONTINUE) |
1104 | handler++) { | 1121 | break; |
1105 | res = (*handler)(&tx); | ||
1106 | if (res != TXRX_CONTINUE) | ||
1107 | break; | ||
1108 | } | ||
1109 | } | 1122 | } |
1110 | 1123 | ||
1111 | skb = tx.skb; /* handlers are allowed to change skb */ | 1124 | skb = tx.skb; /* handlers are allowed to change skb */ |
@@ -1857,7 +1870,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, | |||
1857 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1870 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
1858 | } | 1871 | } |
1859 | 1872 | ||
1860 | if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0) | 1873 | if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control)) |
1861 | break; | 1874 | break; |
1862 | dev_kfree_skb_any(skb); | 1875 | dev_kfree_skb_any(skb); |
1863 | } | 1876 | } |