]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/mac80211/ieee80211_sta.c
mac80211: adding 802.11n configuration flows
[linux-2.6-omap-h63xx.git] / net / mac80211 / ieee80211_sta.c
index 16afd24d4f6b2bb392914e9fac06434ed205b54f..87830c04a1caf4d1904da04efa169162b9060d9c 100644 (file)
 
 #define ERP_INFO_USE_PROTECTION BIT(1)
 
+/* mgmt header + 1 byte action code */
+#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
+
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+
 static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
                                     u8 *ssid, size_t ssid_len);
 static struct ieee80211_sta_bss *
@@ -90,7 +97,8 @@ struct ieee802_11_elems {
        u8 *ext_supp_rates;
        u8 *wmm_info;
        u8 *wmm_param;
-
+       u8 *ht_cap_elem;
+       u8 *ht_info_elem;
        /* length of them, respectively */
        u8 ssid_len;
        u8 supp_rates_len;
@@ -106,6 +114,8 @@ struct ieee802_11_elems {
        u8 ext_supp_rates_len;
        u8 wmm_info_len;
        u8 wmm_param_len;
+       u8 ht_cap_elem_len;
+       u8 ht_info_elem_len;
 };
 
 static void ieee802_11_parse_elems(u8 *start, size_t len,
@@ -190,6 +200,14 @@ static void ieee802_11_parse_elems(u8 *start, size_t len,
                        elems->ext_supp_rates = pos;
                        elems->ext_supp_rates_len = elen;
                        break;
+               case WLAN_EID_HT_CAPABILITY:
+                       elems->ht_cap_elem = pos;
+                       elems->ht_cap_elem_len = elen;
+                       break;
+               case WLAN_EID_HT_EXTRA_INFO:
+                       elems->ht_info_elem = pos;
+                       elems->ht_info_elem_len = elen;
+                       break;
                default:
                        break;
                }
@@ -332,6 +350,51 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
                ieee80211_erp_info_change_notify(dev, changes);
 }
 
+int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
+                                  struct ieee80211_ht_info *ht_info)
+{
+
+       if (ht_info == NULL)
+               return -EINVAL;
+
+       memset(ht_info, 0, sizeof(*ht_info));
+
+       if (ht_cap_ie) {
+               u8 ampdu_info = ht_cap_ie->ampdu_params_info;
+
+               ht_info->ht_supported = 1;
+               ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
+               ht_info->ampdu_factor =
+                       ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
+               ht_info->ampdu_density =
+                       (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
+               memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
+       } else
+               ht_info->ht_supported = 0;
+
+       return 0;
+}
+
+int ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                       struct ieee80211_ht_addt_info *ht_add_info_ie,
+                       struct ieee80211_ht_bss_info *bss_info)
+{
+       if (bss_info == NULL)
+               return -EINVAL;
+
+       memset(bss_info, 0, sizeof(*bss_info));
+
+       if (ht_add_info_ie) {
+               u16 op_mode;
+               op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
+
+               bss_info->primary_channel = ht_add_info_ie->control_chan;
+               bss_info->bss_cap = ht_add_info_ie->ht_param;
+               bss_info->bss_op_mode = (u8)(op_mode & 0xff);
+       }
+
+       return 0;
+}
 
 static void ieee80211_sta_send_associnfo(struct net_device *dev,
                                         struct ieee80211_if_sta *ifsta)
@@ -630,6 +693,19 @@ static void ieee80211_send_assoc(struct net_device *dev,
                *pos++ = 1; /* WME ver */
                *pos++ = 0;
        }
+       /* wmm support is a must to HT */
+       if (wmm && mode->ht_info.ht_supported) {
+               __le16 tmp = cpu_to_le16(mode->ht_info.cap);
+               pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
+               *pos++ = WLAN_EID_HT_CAPABILITY;
+               *pos++ = sizeof(struct ieee80211_ht_cap);
+               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+               memcpy(pos, &tmp, sizeof(u16));
+               pos += sizeof(u16);
+               *pos++ = (mode->ht_info.ampdu_factor |
+                               (mode->ht_info.ampdu_density << 2));
+               memcpy(pos, mode->ht_info.supp_mcs_set, 16);
+       }
 
        kfree(ifsta->assocreq_ies);
        ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
@@ -808,12 +884,8 @@ static void ieee80211_associated(struct net_device *dev,
                sta_info_put(sta);
        }
        if (disassoc) {
-               union iwreq_data wrqu;
-               memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
-               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-               wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-               mod_timer(&ifsta->timer, jiffies +
-                                     IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+               ifsta->state = IEEE80211_DISABLED;
+               ieee80211_set_associated(dev, ifsta, 0);
        } else {
                mod_timer(&ifsta->timer, jiffies +
                                      IEEE80211_MONITORING_INTERVAL);
@@ -922,6 +994,91 @@ static void ieee80211_auth_challenge(struct net_device *dev,
                            elems.challenge_len + 2, 1);
 }
 
+static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
+                                       u8 dialog_token, u16 status, u16 policy,
+                                       u16 buf_size, u16 timeout)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       u16 capab;
+
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer "
+                      "for addba resp frame\n", dev->name);
+               return;
+       }
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+       memset(mgmt, 0, 24);
+       memcpy(mgmt->da, da, ETH_ALEN);
+       memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+       if (sdata->type == IEEE80211_IF_TYPE_AP)
+               memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+       else
+               memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+       mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+                                          IEEE80211_STYPE_ACTION);
+
+       skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
+       mgmt->u.action.category = WLAN_CATEGORY_BACK;
+       mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
+       mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
+
+       capab = (u16)(policy << 1);     /* bit 1 aggregation policy */
+       capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
+       capab |= (u16)(buf_size << 6);  /* bit 15:6 max size of aggregation */
+
+       mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+       mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+       mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+
+       ieee80211_sta_tx(dev, skb, 0);
+
+       return;
+}
+
+static void ieee80211_sta_process_addba_request(struct net_device *dev,
+                                               struct ieee80211_mgmt *mgmt,
+                                               size_t len)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct sta_info *sta;
+       u16 capab, tid, timeout, ba_policy, buf_size, status;
+       u8 dialog_token;
+
+       sta = sta_info_get(local, mgmt->sa);
+       if (!sta)
+               return;
+
+       /* extract session parameters from addba request frame */
+       dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+       timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+
+       capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+       ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
+       tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+       buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+
+       /* TODO - currently aggregation is declined (A-MPDU add BA request
+       * acceptance is not obligatory by 802.11n draft), but here is
+       * the entry point for dealing with it */
+#ifdef MAC80211_HT_DEBUG
+       if (net_ratelimit())
+               printk(KERN_DEBUG "Add Block Ack request arrived,"
+                                  " currently denying it\n");
+#endif /* MAC80211_HT_DEBUG */
+
+       status = WLAN_STATUS_REQUEST_DECLINED;
+
+       ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
+                               status, 1, buf_size, timeout);
+       sta_info_put(sta);
+}
 
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
                                   struct ieee80211_if_sta *ifsta,
@@ -1280,6 +1437,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
        }
        sta->supp_rates = rates;
 
+       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+           local->ops->conf_ht) {
+               struct ieee80211_ht_bss_info bss_info;
+
+               ieee80211_ht_cap_ie_to_ht_info(
+                               (struct ieee80211_ht_cap *)
+                               elems.ht_cap_elem, &sta->ht_info);
+               ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                               (struct ieee80211_ht_addt_info *)
+                               elems.ht_info_elem, &bss_info);
+               ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info);
+       }
+
        rate_control_rate_init(sta, local);
 
        if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
@@ -1384,6 +1554,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
        kfree(bss->wpa_ie);
        kfree(bss->rsn_ie);
        kfree(bss->wmm_ie);
+       kfree(bss->ht_ie);
        kfree(bss);
 }
 
@@ -1487,8 +1658,18 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                u32 supp_rates, prev_rates;
                int i, j;
 
-               mode = local->sta_scanning ?
+               mode = local->sta_sw_scanning ?
                       local->scan_hw_mode : local->oper_hw_mode;
+
+               if (local->sta_hw_scanning) {
+                       /* search for the correct mode matches the beacon */
+                       list_for_each_entry(mode, &local->modes_list, list)
+                               if (mode->mode == rx_status->phymode)
+                                       break;
+
+                       if (mode == NULL)
+                               mode = local->oper_hw_mode;
+               }
                rates = mode->rates;
                num_rates = mode->num_rates;
 
@@ -1631,7 +1812,22 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                bss->wmm_ie = NULL;
                bss->wmm_ie_len = 0;
        }
-
+       if (elems.ht_cap_elem &&
+           (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
+            memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
+               kfree(bss->ht_ie);
+               bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
+               if (bss->ht_ie) {
+                       memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
+                              elems.ht_cap_elem_len + 2);
+                       bss->ht_ie_len = elems.ht_cap_elem_len + 2;
+               } else
+                       bss->ht_ie_len = 0;
+       } else if (!elems.ht_cap_elem && bss->ht_ie) {
+               kfree(bss->ht_ie);
+               bss->ht_ie = NULL;
+               bss->ht_ie_len = 0;
+       }
 
        bss->hw_mode = rx_status->phymode;
        bss->freq = rx_status->freq;
@@ -1676,6 +1872,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
        struct ieee80211_if_sta *ifsta;
        size_t baselen;
        struct ieee802_11_elems elems;
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_conf *conf = &local->hw.conf;
 
        ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
 
@@ -1698,6 +1896,23 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
        if (elems.erp_info && elems.erp_info_len >= 1)
                ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
 
+       if (elems.ht_cap_elem && elems.ht_info_elem &&
+           elems.wmm_param && local->ops->conf_ht &&
+           conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+               struct ieee80211_ht_bss_info bss_info;
+
+               ieee80211_ht_addt_info_ie_to_ht_bss_info(
+                               (struct ieee80211_ht_addt_info *)
+                               elems.ht_info_elem, &bss_info);
+               /* check if AP changed bss inforamation */
+               if ((conf->ht_bss_conf.primary_channel !=
+                    bss_info.primary_channel) ||
+                   (conf->ht_bss_conf.bss_cap != bss_info.bss_cap) ||
+                   (conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode))
+                       ieee80211_hw_config_ht(local, 1, &conf->ht_conf,
+                                               &bss_info);
+       }
+
        if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                         elems.wmm_param_len);
@@ -1779,6 +1994,34 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
        ieee80211_sta_tx(dev, skb, 0);
 }
 
+void ieee80211_rx_mgmt_action(struct net_device *dev,
+                            struct ieee80211_if_sta *ifsta,
+                            struct ieee80211_mgmt *mgmt,
+                            size_t len)
+{
+       if (len < IEEE80211_MIN_ACTION_SIZE)
+               return;
+
+       switch (mgmt->u.action.category) {
+       case WLAN_CATEGORY_BACK:
+               switch (mgmt->u.action.u.addba_req.action_code) {
+               case WLAN_ACTION_ADDBA_REQ:
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.addba_req)))
+                               break;
+                       ieee80211_sta_process_addba_request(dev, mgmt, len);
+                       break;
+               default:
+                       if (net_ratelimit())
+                          printk(KERN_DEBUG "%s: received unsupported BACK\n",
+                                       dev->name);
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
 
 void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
                           struct ieee80211_rx_status *rx_status)
@@ -1808,6 +2051,7 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
        case IEEE80211_STYPE_REASSOC_RESP:
        case IEEE80211_STYPE_DEAUTH:
        case IEEE80211_STYPE_DISASSOC:
+       case IEEE80211_STYPE_ACTION:
                skb_queue_tail(&ifsta->skb_queue, skb);
                queue_work(local->hw.workqueue, &ifsta->work);
                return;
@@ -1865,37 +2109,48 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
        case IEEE80211_STYPE_DISASSOC:
                ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
                break;
+       case IEEE80211_STYPE_ACTION:
+               ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
+               break;
        }
 
        kfree_skb(skb);
 }
 
 
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-                          struct ieee80211_rx_status *rx_status)
+ieee80211_txrx_result
+ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_mgmt *mgmt;
        u16 fc;
 
-       if (skb->len < 24) {
-               dev_kfree_skb(skb);
-               return;
-       }
+       if (skb->len < 2)
+               return TXRX_DROP;
 
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
+       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+               return TXRX_CONTINUE;
+
+       if (skb->len < 24)
+               return TXRX_DROP;
+
        if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
                if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
                        ieee80211_rx_mgmt_probe_resp(dev, mgmt,
                                                     skb->len, rx_status);
+                       dev_kfree_skb(skb);
+                       return TXRX_QUEUED;
                } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
                        ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
                                                 rx_status);
+                       dev_kfree_skb(skb);
+                       return TXRX_QUEUED;
                }
        }
-
-       dev_kfree_skb(skb);
+       return TXRX_CONTINUE;
 }
 
 
@@ -1985,7 +2240,7 @@ void ieee80211_sta_work(struct work_struct *work)
        if (!netif_running(dev))
                return;
 
-       if (local->sta_scanning)
+       if (local->sta_sw_scanning || local->sta_hw_scanning)
                return;
 
        if (sdata->type != IEEE80211_IF_TYPE_STA &&
@@ -2643,9 +2898,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
        union iwreq_data wrqu;
 
        local->last_scan_completed = jiffies;
-       wmb();
-       local->sta_scanning = 0;
+       memset(&wrqu, 0, sizeof(wrqu));
+       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 
+       if (local->sta_hw_scanning) {
+               local->sta_hw_scanning = 0;
+               goto done;
+       }
+
+       local->sta_sw_scanning = 0;
        if (ieee80211_hw_config(local))
                printk(KERN_DEBUG "%s: failed to restore operational "
                       "channel after scan\n", dev->name);
@@ -2661,9 +2922,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
        netif_tx_unlock_bh(local->mdev);
 
-       memset(&wrqu, 0, sizeof(wrqu));
-       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 
@@ -2681,6 +2939,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
        }
        rcu_read_unlock();
 
+done:
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -2703,7 +2962,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
        int skip;
        unsigned long next_delay = 0;
 
-       if (!local->sta_scanning)
+       if (!local->sta_sw_scanning)
                return;
 
        switch (local->scan_state) {
@@ -2766,7 +3025,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
                break;
        }
 
-       if (local->sta_scanning)
+       if (local->sta_sw_scanning)
                queue_delayed_work(local->hw.workqueue, &local->scan_work,
                                   next_delay);
 }
@@ -2798,7 +3057,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
          * ResultCode: SUCCESS, INVALID_PARAMETERS
         */
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning || local->sta_hw_scanning) {
                if (local->scan_dev == dev)
                        return 0;
                return -EBUSY;
@@ -2806,15 +3065,15 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 
        if (local->ops->hw_scan) {
                int rc = local->ops->hw_scan(local_to_hw(local),
-                                           ssid, ssid_len);
+                                            ssid, ssid_len);
                if (!rc) {
-                       local->sta_scanning = 1;
+                       local->sta_hw_scanning = 1;
                        local->scan_dev = dev;
                }
                return rc;
        }
 
-       local->sta_scanning = 1;
+       local->sta_sw_scanning = 1;
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
@@ -2869,7 +3128,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
        if (sdata->type != IEEE80211_IF_TYPE_STA)
                return ieee80211_sta_start_scan(dev, ssid, ssid_len);
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning || local->sta_hw_scanning) {
                if (local->scan_dev == dev)
                        return 0;
                return -EBUSY;
@@ -2898,15 +3157,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
        if (!(local->enabled_modes & (1 << bss->hw_mode)))
                return current_ev;
 
-       if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY &&
-           !bss->wpa_ie && !bss->rsn_ie)
-               return current_ev;
-
-       if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID &&
-           (local->scan_ssid_len != bss->ssid_len ||
-            memcmp(local->scan_ssid, bss->ssid, bss->ssid_len) != 0))
-               return current_ev;
-
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = SIOCGIWAP;
        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
@@ -3013,9 +3263,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
        do {
                char *buf;
 
-               if (!(local->scan_flags & IEEE80211_SCAN_EXTRA_INFO))
-                       break;
-
                buf = kmalloc(100, GFP_ATOMIC);
                if (!buf)
                        break;