diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/wireless/util.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 230 |
1 files changed, 186 insertions, 44 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 0c8a1e8b7690..4d7b83fbc32f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -29,29 +29,37 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | |||
29 | } | 29 | } |
30 | EXPORT_SYMBOL(ieee80211_get_response_rate); | 30 | EXPORT_SYMBOL(ieee80211_get_response_rate); |
31 | 31 | ||
32 | int ieee80211_channel_to_frequency(int chan) | 32 | int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) |
33 | { | 33 | { |
34 | if (chan < 14) | 34 | /* see 802.11 17.3.8.3.2 and Annex J |
35 | return 2407 + chan * 5; | 35 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ |
36 | 36 | if (band == IEEE80211_BAND_5GHZ) { | |
37 | if (chan == 14) | 37 | if (chan >= 182 && chan <= 196) |
38 | return 2484; | 38 | return 4000 + chan * 5; |
39 | 39 | else | |
40 | /* FIXME: 802.11j 17.3.8.3.2 */ | 40 | return 5000 + chan * 5; |
41 | return (chan + 1000) * 5; | 41 | } else { /* IEEE80211_BAND_2GHZ */ |
42 | if (chan == 14) | ||
43 | return 2484; | ||
44 | else if (chan < 14) | ||
45 | return 2407 + chan * 5; | ||
46 | else | ||
47 | return 0; /* not supported */ | ||
48 | } | ||
42 | } | 49 | } |
43 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 50 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
44 | 51 | ||
45 | int ieee80211_frequency_to_channel(int freq) | 52 | int ieee80211_frequency_to_channel(int freq) |
46 | { | 53 | { |
54 | /* see 802.11 17.3.8.3.2 and Annex J */ | ||
47 | if (freq == 2484) | 55 | if (freq == 2484) |
48 | return 14; | 56 | return 14; |
49 | 57 | else if (freq < 2484) | |
50 | if (freq < 2484) | ||
51 | return (freq - 2407) / 5; | 58 | return (freq - 2407) / 5; |
52 | 59 | else if (freq >= 4910 && freq <= 4980) | |
53 | /* FIXME: 802.11j 17.3.8.3.2 */ | 60 | return (freq - 4000) / 5; |
54 | return freq/5 - 1000; | 61 | else |
62 | return (freq - 5000) / 5; | ||
55 | } | 63 | } |
56 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 64 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
57 | 65 | ||
@@ -144,21 +152,30 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
144 | 152 | ||
145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 153 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
146 | struct key_params *params, int key_idx, | 154 | struct key_params *params, int key_idx, |
147 | const u8 *mac_addr) | 155 | bool pairwise, const u8 *mac_addr) |
148 | { | 156 | { |
149 | int i; | 157 | int i; |
150 | 158 | ||
151 | if (key_idx > 5) | 159 | if (key_idx > 5) |
152 | return -EINVAL; | 160 | return -EINVAL; |
153 | 161 | ||
162 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
163 | return -EINVAL; | ||
164 | |||
165 | if (pairwise && !mac_addr) | ||
166 | return -EINVAL; | ||
167 | |||
154 | /* | 168 | /* |
155 | * Disallow pairwise keys with non-zero index unless it's WEP | 169 | * Disallow pairwise keys with non-zero index unless it's WEP |
156 | * (because current deployments use pairwise WEP keys with | 170 | * or a vendor specific cipher (because current deployments use |
157 | * non-zero indizes but 802.11i clearly specifies to use zero) | 171 | * pairwise WEP keys with non-zero indices and for vendor specific |
172 | * ciphers this should be validated in the driver or hardware level | ||
173 | * - but 802.11i clearly specifies to use zero) | ||
158 | */ | 174 | */ |
159 | if (mac_addr && key_idx && | 175 | if (pairwise && key_idx && |
160 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | 176 | ((params->cipher == WLAN_CIPHER_SUITE_TKIP) || |
161 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 177 | (params->cipher == WLAN_CIPHER_SUITE_CCMP) || |
178 | (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC))) | ||
162 | return -EINVAL; | 179 | return -EINVAL; |
163 | 180 | ||
164 | switch (params->cipher) { | 181 | switch (params->cipher) { |
@@ -183,7 +200,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
183 | return -EINVAL; | 200 | return -EINVAL; |
184 | break; | 201 | break; |
185 | default: | 202 | default: |
186 | return -EINVAL; | 203 | /* |
204 | * We don't know anything about this algorithm, | ||
205 | * allow using it -- but the driver must check | ||
206 | * all parameters! We still check below whether | ||
207 | * or not the driver supports this algorithm, | ||
208 | * of course. | ||
209 | */ | ||
210 | break; | ||
187 | } | 211 | } |
188 | 212 | ||
189 | if (params->seq) { | 213 | if (params->seq) { |
@@ -221,7 +245,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) = | |||
221 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | 245 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
222 | EXPORT_SYMBOL(bridge_tunnel_header); | 246 | EXPORT_SYMBOL(bridge_tunnel_header); |
223 | 247 | ||
224 | unsigned int ieee80211_hdrlen(__le16 fc) | 248 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) |
225 | { | 249 | { |
226 | unsigned int hdrlen = 24; | 250 | unsigned int hdrlen = 24; |
227 | 251 | ||
@@ -319,7 +343,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
319 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | 343 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { |
320 | case cpu_to_le16(IEEE80211_FCTL_TODS): | 344 | case cpu_to_le16(IEEE80211_FCTL_TODS): |
321 | if (unlikely(iftype != NL80211_IFTYPE_AP && | 345 | if (unlikely(iftype != NL80211_IFTYPE_AP && |
322 | iftype != NL80211_IFTYPE_AP_VLAN)) | 346 | iftype != NL80211_IFTYPE_AP_VLAN && |
347 | iftype != NL80211_IFTYPE_P2P_GO)) | ||
323 | return -1; | 348 | return -1; |
324 | break; | 349 | break; |
325 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 350 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): |
@@ -347,7 +372,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
347 | break; | 372 | break; |
348 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 373 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
349 | if ((iftype != NL80211_IFTYPE_STATION && | 374 | if ((iftype != NL80211_IFTYPE_STATION && |
350 | iftype != NL80211_IFTYPE_MESH_POINT) || | 375 | iftype != NL80211_IFTYPE_P2P_CLIENT && |
376 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
351 | (is_multicast_ether_addr(dst) && | 377 | (is_multicast_ether_addr(dst) && |
352 | !compare_ether_addr(src, addr))) | 378 | !compare_ether_addr(src, addr))) |
353 | return -1; | 379 | return -1; |
@@ -424,6 +450,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
424 | switch (iftype) { | 450 | switch (iftype) { |
425 | case NL80211_IFTYPE_AP: | 451 | case NL80211_IFTYPE_AP: |
426 | case NL80211_IFTYPE_AP_VLAN: | 452 | case NL80211_IFTYPE_AP_VLAN: |
453 | case NL80211_IFTYPE_P2P_GO: | ||
427 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 454 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
428 | /* DA BSSID SA */ | 455 | /* DA BSSID SA */ |
429 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 456 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -432,6 +459,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
432 | hdrlen = 24; | 459 | hdrlen = 24; |
433 | break; | 460 | break; |
434 | case NL80211_IFTYPE_STATION: | 461 | case NL80211_IFTYPE_STATION: |
462 | case NL80211_IFTYPE_P2P_CLIENT: | ||
435 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 463 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
436 | /* BSSID SA DA */ | 464 | /* BSSID SA DA */ |
437 | memcpy(hdr.addr1, bssid, ETH_ALEN); | 465 | memcpy(hdr.addr1, bssid, ETH_ALEN); |
@@ -485,7 +513,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
485 | skb_orphan(skb); | 513 | skb_orphan(skb); |
486 | 514 | ||
487 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { | 515 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { |
488 | printk(KERN_ERR "failed to reallocate Tx buffer\n"); | 516 | pr_err("failed to reallocate Tx buffer\n"); |
489 | return -ENOMEM; | 517 | return -ENOMEM; |
490 | } | 518 | } |
491 | skb->truesize += head_need; | 519 | skb->truesize += head_need; |
@@ -516,7 +544,8 @@ EXPORT_SYMBOL(ieee80211_data_from_8023); | |||
516 | 544 | ||
517 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | 545 | void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, |
518 | const u8 *addr, enum nl80211_iftype iftype, | 546 | const u8 *addr, enum nl80211_iftype iftype, |
519 | const unsigned int extra_headroom) | 547 | const unsigned int extra_headroom, |
548 | bool has_80211_header) | ||
520 | { | 549 | { |
521 | struct sk_buff *frame = NULL; | 550 | struct sk_buff *frame = NULL; |
522 | u16 ethertype; | 551 | u16 ethertype; |
@@ -525,14 +554,18 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | |||
525 | int remaining, err; | 554 | int remaining, err; |
526 | u8 dst[ETH_ALEN], src[ETH_ALEN]; | 555 | u8 dst[ETH_ALEN], src[ETH_ALEN]; |
527 | 556 | ||
528 | err = ieee80211_data_to_8023(skb, addr, iftype); | 557 | if (has_80211_header) { |
529 | if (err) | 558 | err = ieee80211_data_to_8023(skb, addr, iftype); |
530 | goto out; | 559 | if (err) |
560 | goto out; | ||
531 | 561 | ||
532 | /* skip the wrapping header */ | 562 | /* skip the wrapping header */ |
533 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); | 563 | eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); |
534 | if (!eth) | 564 | if (!eth) |
535 | goto out; | 565 | goto out; |
566 | } else { | ||
567 | eth = (struct ethhdr *) skb->data; | ||
568 | } | ||
536 | 569 | ||
537 | while (skb != frame) { | 570 | while (skb != frame) { |
538 | u8 padding; | 571 | u8 padding; |
@@ -666,22 +699,20 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
666 | for (i = 0; i < 6; i++) { | 699 | for (i = 0; i < 6; i++) { |
667 | if (!wdev->connect_keys->params[i].cipher) | 700 | if (!wdev->connect_keys->params[i].cipher) |
668 | continue; | 701 | continue; |
669 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | 702 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, |
670 | &wdev->connect_keys->params[i])) { | 703 | &wdev->connect_keys->params[i])) { |
671 | printk(KERN_ERR "%s: failed to set key %d\n", | 704 | netdev_err(dev, "failed to set key %d\n", i); |
672 | dev->name, i); | ||
673 | continue; | 705 | continue; |
674 | } | 706 | } |
675 | if (wdev->connect_keys->def == i) | 707 | if (wdev->connect_keys->def == i) |
676 | if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { | 708 | if (rdev->ops->set_default_key(wdev->wiphy, dev, |
677 | printk(KERN_ERR "%s: failed to set defkey %d\n", | 709 | i, true, true)) { |
678 | dev->name, i); | 710 | netdev_err(dev, "failed to set defkey %d\n", i); |
679 | continue; | 711 | continue; |
680 | } | 712 | } |
681 | if (wdev->connect_keys->defmgmt == i) | 713 | if (wdev->connect_keys->defmgmt == i) |
682 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) | 714 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) |
683 | printk(KERN_ERR "%s: failed to set mgtdef %d\n", | 715 | netdev_err(dev, "failed to set mgtdef %d\n", i); |
684 | dev->name, i); | ||
685 | } | 716 | } |
686 | 717 | ||
687 | kfree(wdev->connect_keys); | 718 | kfree(wdev->connect_keys); |
@@ -715,7 +746,7 @@ static void cfg80211_process_wdev_events(struct wireless_dev *wdev) | |||
715 | NULL); | 746 | NULL); |
716 | break; | 747 | break; |
717 | case EVENT_ROAMED: | 748 | case EVENT_ROAMED: |
718 | __cfg80211_roamed(wdev, ev->rm.bssid, | 749 | __cfg80211_roamed(wdev, ev->rm.channel, ev->rm.bssid, |
719 | ev->rm.req_ie, ev->rm.req_ie_len, | 750 | ev->rm.req_ie, ev->rm.req_ie_len, |
720 | ev->rm.resp_ie, ev->rm.resp_ie_len); | 751 | ev->rm.resp_ie, ev->rm.resp_ie_len); |
721 | break; | 752 | break; |
@@ -771,17 +802,26 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
771 | 802 | ||
772 | /* if it's part of a bridge, reject changing type to station/ibss */ | 803 | /* if it's part of a bridge, reject changing type to station/ibss */ |
773 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && | 804 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && |
774 | (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION)) | 805 | (ntype == NL80211_IFTYPE_ADHOC || |
806 | ntype == NL80211_IFTYPE_STATION || | ||
807 | ntype == NL80211_IFTYPE_P2P_CLIENT)) | ||
775 | return -EBUSY; | 808 | return -EBUSY; |
776 | 809 | ||
777 | if (ntype != otype) { | 810 | if (ntype != otype) { |
811 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | ||
812 | ntype); | ||
813 | if (err) | ||
814 | return err; | ||
815 | |||
778 | dev->ieee80211_ptr->use_4addr = false; | 816 | dev->ieee80211_ptr->use_4addr = false; |
817 | dev->ieee80211_ptr->mesh_id_up_len = 0; | ||
779 | 818 | ||
780 | switch (otype) { | 819 | switch (otype) { |
781 | case NL80211_IFTYPE_ADHOC: | 820 | case NL80211_IFTYPE_ADHOC: |
782 | cfg80211_leave_ibss(rdev, dev, false); | 821 | cfg80211_leave_ibss(rdev, dev, false); |
783 | break; | 822 | break; |
784 | case NL80211_IFTYPE_STATION: | 823 | case NL80211_IFTYPE_STATION: |
824 | case NL80211_IFTYPE_P2P_CLIENT: | ||
785 | cfg80211_disconnect(rdev, dev, | 825 | cfg80211_disconnect(rdev, dev, |
786 | WLAN_REASON_DEAUTH_LEAVING, true); | 826 | WLAN_REASON_DEAUTH_LEAVING, true); |
787 | break; | 827 | break; |
@@ -810,9 +850,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
810 | if (dev->ieee80211_ptr->use_4addr) | 850 | if (dev->ieee80211_ptr->use_4addr) |
811 | break; | 851 | break; |
812 | /* fall through */ | 852 | /* fall through */ |
853 | case NL80211_IFTYPE_P2P_CLIENT: | ||
813 | case NL80211_IFTYPE_ADHOC: | 854 | case NL80211_IFTYPE_ADHOC: |
814 | dev->priv_flags |= IFF_DONT_BRIDGE; | 855 | dev->priv_flags |= IFF_DONT_BRIDGE; |
815 | break; | 856 | break; |
857 | case NL80211_IFTYPE_P2P_GO: | ||
816 | case NL80211_IFTYPE_AP: | 858 | case NL80211_IFTYPE_AP: |
817 | case NL80211_IFTYPE_AP_VLAN: | 859 | case NL80211_IFTYPE_AP_VLAN: |
818 | case NL80211_IFTYPE_WDS: | 860 | case NL80211_IFTYPE_WDS: |
@@ -823,7 +865,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
823 | /* monitor can't bridge anyway */ | 865 | /* monitor can't bridge anyway */ |
824 | break; | 866 | break; |
825 | case NL80211_IFTYPE_UNSPECIFIED: | 867 | case NL80211_IFTYPE_UNSPECIFIED: |
826 | case __NL80211_IFTYPE_AFTER_LAST: | 868 | case NUM_NL80211_IFTYPES: |
827 | /* not happening */ | 869 | /* not happening */ |
828 | break; | 870 | break; |
829 | } | 871 | } |
@@ -864,3 +906,103 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate) | |||
864 | /* do NOT round down here */ | 906 | /* do NOT round down here */ |
865 | return (bitrate + 50000) / 100000; | 907 | return (bitrate + 50000) / 100000; |
866 | } | 908 | } |
909 | |||
910 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | ||
911 | u32 beacon_int) | ||
912 | { | ||
913 | struct wireless_dev *wdev; | ||
914 | int res = 0; | ||
915 | |||
916 | if (!beacon_int) | ||
917 | return -EINVAL; | ||
918 | |||
919 | mutex_lock(&rdev->devlist_mtx); | ||
920 | |||
921 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | ||
922 | if (!wdev->beacon_interval) | ||
923 | continue; | ||
924 | if (wdev->beacon_interval != beacon_int) { | ||
925 | res = -EINVAL; | ||
926 | break; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | mutex_unlock(&rdev->devlist_mtx); | ||
931 | |||
932 | return res; | ||
933 | } | ||
934 | |||
935 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
936 | struct wireless_dev *wdev, | ||
937 | enum nl80211_iftype iftype) | ||
938 | { | ||
939 | struct wireless_dev *wdev_iter; | ||
940 | int num[NUM_NL80211_IFTYPES]; | ||
941 | int total = 1; | ||
942 | int i, j; | ||
943 | |||
944 | ASSERT_RTNL(); | ||
945 | |||
946 | /* Always allow software iftypes */ | ||
947 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | ||
948 | return 0; | ||
949 | |||
950 | /* | ||
951 | * Drivers will gradually all set this flag, until all | ||
952 | * have it we only enforce for those that set it. | ||
953 | */ | ||
954 | if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS)) | ||
955 | return 0; | ||
956 | |||
957 | memset(num, 0, sizeof(num)); | ||
958 | |||
959 | num[iftype] = 1; | ||
960 | |||
961 | mutex_lock(&rdev->devlist_mtx); | ||
962 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | ||
963 | if (wdev_iter == wdev) | ||
964 | continue; | ||
965 | if (!netif_running(wdev_iter->netdev)) | ||
966 | continue; | ||
967 | |||
968 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | ||
969 | continue; | ||
970 | |||
971 | num[wdev_iter->iftype]++; | ||
972 | total++; | ||
973 | } | ||
974 | mutex_unlock(&rdev->devlist_mtx); | ||
975 | |||
976 | for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { | ||
977 | const struct ieee80211_iface_combination *c; | ||
978 | struct ieee80211_iface_limit *limits; | ||
979 | |||
980 | c = &rdev->wiphy.iface_combinations[i]; | ||
981 | |||
982 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | ||
983 | GFP_KERNEL); | ||
984 | if (!limits) | ||
985 | return -ENOMEM; | ||
986 | if (total > c->max_interfaces) | ||
987 | goto cont; | ||
988 | |||
989 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | ||
990 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | ||
991 | continue; | ||
992 | for (j = 0; j < c->n_limits; j++) { | ||
993 | if (!(limits[j].types & iftype)) | ||
994 | continue; | ||
995 | if (limits[j].max < num[iftype]) | ||
996 | goto cont; | ||
997 | limits[j].max -= num[iftype]; | ||
998 | } | ||
999 | } | ||
1000 | /* yay, it fits */ | ||
1001 | kfree(limits); | ||
1002 | return 0; | ||
1003 | cont: | ||
1004 | kfree(limits); | ||
1005 | } | ||
1006 | |||
1007 | return -EBUSY; | ||
1008 | } | ||