diff options
Diffstat (limited to 'net')
37 files changed, 722 insertions, 709 deletions
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index d8b02603cbe5..d996547f7a62 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -542,90 +542,4 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) return 1; } -/* Incoming 802.11 strucure is converted to a TXB - * a block of 802.11 fragment packets (stored as skbs) */ -int ieee80211_tx_frame(struct ieee80211_device *ieee, - struct ieee80211_hdr *frame, int hdr_len, int total_len, - int encrypt_mpdu) -{ - struct ieee80211_txb *txb = NULL; - unsigned long flags; - struct net_device_stats *stats = &ieee->stats; - struct sk_buff *skb_frag; - int priority = -1; - int fraglen = total_len; - int headroom = ieee->tx_headroom; - struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; - - spin_lock_irqsave(&ieee->lock, flags); - - if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt)) - encrypt_mpdu = 0; - - /* If there is no driver handler to take the TXB, dont' bother - * creating it... */ - if (!ieee->hard_start_xmit) { - printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); - goto success; - } - - if (unlikely(total_len < 24)) { - printk(KERN_WARNING "%s: skb too small (%d).\n", - ieee->dev->name, total_len); - goto success; - } - - if (encrypt_mpdu) { - frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - fraglen += crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_mpdu_postfix_len; - headroom += crypt->ops->extra_mpdu_prefix_len; - } - - /* When we allocate the TXB we allocate enough space for the reserve - * and full fragment bytes (bytes_per_frag doesn't include prefix, - * postfix, header, FCS, etc.) */ - txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC); - if (unlikely(!txb)) { - printk(KERN_WARNING "%s: Could not allocate TXB\n", - ieee->dev->name); - goto failed; - } - txb->encrypted = 0; - txb->payload_size = fraglen; - - skb_frag = txb->fragments[0]; - - memcpy(skb_put(skb_frag, total_len), frame, total_len); - - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - skb_put(skb_frag, 4); - - /* To avoid overcomplicating things, we do the corner-case frame - * encryption in software. The only real situation where encryption is - * needed here is during software-based shared key authentication. */ - if (encrypt_mpdu) - ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); - - success: - spin_unlock_irqrestore(&ieee->lock, flags); - - if (txb) { - if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) { - stats->tx_packets++; - stats->tx_bytes += txb->payload_size; - return 0; - } - ieee80211_txb_free(txb); - } - return 0; - - failed: - spin_unlock_irqrestore(&ieee->lock, flags); - stats->tx_errors++; - return 1; -} - -EXPORT_SYMBOL(ieee80211_tx_frame); EXPORT_SYMBOL(ieee80211_txb_free); diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index 623489afa62c..822606b615ca 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -744,98 +744,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return 0; } -int ieee80211_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211_device *ieee = netdev_priv(dev); - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&ieee->lock, flags); - - switch (wrqu->param.flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - break; /* FIXME */ - case IW_AUTH_DROP_UNENCRYPTED: - ieee->drop_unencrypted = !!wrqu->param.value; - break; - case IW_AUTH_80211_AUTH_ALG: - break; /* FIXME */ - case IW_AUTH_WPA_ENABLED: - ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ieee->ieee802_1x = !!wrqu->param.value; - break; - case IW_AUTH_PRIVACY_INVOKED: - ieee->privacy_invoked = !!wrqu->param.value; - break; - default: - err = -EOPNOTSUPP; - break; - } - spin_unlock_irqrestore(&ieee->lock, flags); - return err; -} - -int ieee80211_wx_get_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211_device *ieee = netdev_priv(dev); - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&ieee->lock, flags); - - switch (wrqu->param.flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_TKIP_COUNTERMEASURES: /* FIXME */ - case IW_AUTH_80211_AUTH_ALG: /* FIXME */ - /* - * Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - err = -EOPNOTSUPP; - break; - case IW_AUTH_DROP_UNENCRYPTED: - wrqu->param.value = ieee->drop_unencrypted; - break; - case IW_AUTH_WPA_ENABLED: - wrqu->param.value = ieee->wpa_enabled; - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - wrqu->param.value = ieee->ieee802_1x; - break; - default: - err = -EOPNOTSUPP; - break; - } - spin_unlock_irqrestore(&ieee->lock, flags); - return err; -} - EXPORT_SYMBOL(ieee80211_wx_set_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_scan); EXPORT_SYMBOL(ieee80211_wx_set_encode); EXPORT_SYMBOL(ieee80211_wx_get_encode); - -EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth); -EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth); diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 59f1691f62c8..4d4c2dfcf9a0 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -134,7 +134,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, } -struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]) +struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) { struct crypto_cipher *tfm; diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h index 885f19030b29..8cd0f14aab4d 100644 --- a/net/mac80211/aes_ccm.h +++ b/net/mac80211/aes_ccm.h @@ -14,7 +14,7 @@ #define AES_BLOCK_LEN 16 -struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]); +struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]); void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *b_0, u8 *aad, u8 *data, size_t data_len, u8 *cdata, u8 *mic); diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 1cccbfd781f6..d20d90eead1f 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -197,45 +197,6 @@ DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u", DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u", local->tx_status_drop); -static ssize_t stats_wme_rx_queue_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[NUM_RX_DATA_QUEUES*15], *p = buf; - int i; - - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, - "%u\n", local->wme_rx_queue[i]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations stats_wme_rx_queue_ops = { - .read = stats_wme_rx_queue_read, - .open = mac80211_open_file_generic, -}; - -static ssize_t stats_wme_tx_queue_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - char buf[NUM_TX_DATA_QUEUES*15], *p = buf; - int i; - - for (i = 0; i < NUM_TX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, - "%u\n", local->wme_tx_queue[i]); - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations stats_wme_tx_queue_ops = { - .read = stats_wme_tx_queue_read, - .open = mac80211_open_file_generic, -}; #endif DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); @@ -303,8 +264,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_STATS_ADD(rx_expand_skb_head2); DEBUGFS_STATS_ADD(rx_handlers_fragments); DEBUGFS_STATS_ADD(tx_status_drop); - DEBUGFS_STATS_ADD(wme_tx_queue); - DEBUGFS_STATS_ADD(wme_rx_queue); #endif DEBUGFS_STATS_ADD(dot11ACKFailureCount); DEBUGFS_STATS_ADD(dot11RTSFailureCount); @@ -356,8 +315,6 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_STATS_DEL(rx_expand_skb_head2); DEBUGFS_STATS_DEL(rx_handlers_fragments); DEBUGFS_STATS_DEL(tx_status_drop); - DEBUGFS_STATS_DEL(wme_tx_queue); - DEBUGFS_STATS_DEL(wme_rx_queue); #endif DEBUGFS_STATS_DEL(dot11ACKFailureCount); DEBUGFS_STATS_DEL(dot11RTSFailureCount); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e3326d046944..3ae5493d728b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -528,7 +528,7 @@ void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata, add_files(sdata); } -static int netdev_notify(struct notifier_block * nb, +static int netdev_notify(struct notifier_block *nb, unsigned long state, void *ndev) { diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6d47a1d31b37..676a93202ff9 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -123,36 +123,6 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, } STA_OPS(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS -static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[15*NUM_RX_DATA_QUEUES], *p = buf; - int i; - struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_RX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%u ", - sta->wme_rx_queue[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -} -STA_OPS(wme_rx_queue); - -static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[15*NUM_TX_DATA_QUEUES], *p = buf; - int i; - struct sta_info *sta = file->private_data; - for (i = 0; i < NUM_TX_DATA_QUEUES; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%u ", - sta->wme_tx_queue[i]); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); - return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -} -STA_OPS(wme_tx_queue); -#endif - static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -293,10 +263,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(num_ps_buf_frames); DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_ADD(wme_rx_queue); - DEBUGFS_ADD(wme_tx_queue); -#endif DEBUGFS_ADD(agg_status); } @@ -306,10 +272,6 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(num_ps_buf_frames); DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - DEBUGFS_DEL(wme_rx_queue); - DEBUGFS_DEL(wme_tx_queue); -#endif DEBUGFS_DEL(agg_status); debugfs_remove(sta->debugfs.dir); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c7314bf4bec2..d82ed20a344c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -610,8 +610,8 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[NUM_TX_DATA_QUEUES_AMPDU]; - struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU]; + unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; + struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ @@ -705,8 +705,6 @@ struct ieee80211_local { unsigned int rx_expand_skb_head2; unsigned int rx_handlers_fragments; unsigned int tx_status_drop; - unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; - unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #define I802_DEBUG_INC(c) (c)++ #else /* CONFIG_MAC80211_DEBUG_COUNTERS */ #define I802_DEBUG_INC(c) do { } while (0) @@ -764,8 +762,6 @@ struct ieee80211_local { struct dentry *rx_expand_skb_head2; struct dentry *rx_handlers_fragments; struct dentry *tx_status_drop; - struct dentry *wme_tx_queue; - struct dentry *wme_rx_queue; #endif struct dentry *dot11ACKFailureCount; struct dentry *dot11RTSFailureCount; @@ -919,9 +915,9 @@ ieee80211_rx_result ieee80211_sta_rx_scan( void ieee80211_rx_bss_list_init(struct net_device *dev); void ieee80211_rx_bss_list_deinit(struct net_device *dev); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); -struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, - struct sk_buff *skb, u8 *bssid, - u8 *addr); +struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, + struct sk_buff *skb, u8 *bssid, + u8 *addr); int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, @@ -940,7 +936,6 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, u16 tid, u16 initiator, u16 reason); -void sta_rx_agg_session_timer_expired(unsigned long data); void sta_addba_resp_timer_expired(unsigned long data); void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr); u64 ieee80211_sta_get_rates(struct ieee80211_local *local, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 06e88a5a036d..4a8062f8b1cc 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -33,9 +33,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) { int i; - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) __skb_queue_purge(&sdata->fragments[i].skb_list); - } } /* Must be called with rtnl lock held. */ diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 150d66dbda9d..88b211af7c1f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -323,6 +323,13 @@ void ieee80211_key_link(struct ieee80211_key *key, */ if (sta->flags & WLAN_STA_WME) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; + + /* + * This key is for a specific sta interface, + * inform the driver that it should try to store + * this key as pairwise key. + */ + key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; } else { if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { struct sta_info *ap; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 915afadb0602..eb347eca30b5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -385,8 +385,8 @@ static int ieee80211_open(struct net_device *dev) * yet be effective. Trigger execution of ieee80211_sta_work * to fix this. */ - if(sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; queue_work(local->hw.workqueue, &ifsta->work); } @@ -1482,7 +1482,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, return; } - rthdr = (struct ieee80211_tx_status_rtap_hdr*) + rthdr = (struct ieee80211_tx_status_rtap_hdr *) skb_push(skb, sizeof(*rthdr)); memset(rthdr, 0, sizeof(*rthdr)); @@ -1745,6 +1745,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_wep; } + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; + ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4adba09e80ca..5d7719f44bea 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -87,6 +87,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); +static void sta_rx_agg_session_timer_expired(unsigned long data); void ieee802_11_parse_elems(u8 *start, size_t len, @@ -256,19 +257,8 @@ static void ieee80211_sta_def_wmm_params(struct net_device *dev, qparam.cw_max = 1023; qparam.txop = 0; - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - local->ops->conf_tx(local_to_hw(local), - i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - - if (ibss) { - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - IEEE80211_TX_QUEUE_BEACON, &qparam); - } + for (i = 0; i < local_to_hw(local)->queues; i++) + local->ops->conf_tx(local_to_hw(local), i, &qparam); } } @@ -305,29 +295,25 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, switch (aci) { case 1: - queue = IEEE80211_TX_QUEUE_DATA3; - if (acm) { + queue = 3; + if (acm) local->wmm_acm |= BIT(0) | BIT(3); - } break; case 2: - queue = IEEE80211_TX_QUEUE_DATA1; - if (acm) { + queue = 1; + if (acm) local->wmm_acm |= BIT(4) | BIT(5); - } break; case 3: - queue = IEEE80211_TX_QUEUE_DATA0; - if (acm) { + queue = 0; + if (acm) local->wmm_acm |= BIT(6) | BIT(7); - } break; case 0: default: - queue = IEEE80211_TX_QUEUE_DATA2; - if (acm) { + queue = 2; + if (acm) local->wmm_acm |= BIT(1) | BIT(2); - } break; } @@ -727,9 +713,8 @@ static void ieee80211_send_assoc(struct net_device *dev, if (bss) { if (bss->capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_ie) { + if (bss->wmm_ie) wmm = 1; - } ieee80211_rx_bss_put(dev, bss); } @@ -1134,8 +1119,8 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, struct ieee80211_mgmt *mgmt; u16 capab; - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.addba_resp)); + 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); @@ -1183,9 +1168,7 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, struct ieee80211_mgmt *mgmt; u16 capab; - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.addba_req)); - + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " @@ -1447,8 +1430,7 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, struct ieee80211_mgmt *mgmt; u16 params; - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.delba)); + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); if (!skb) { printk(KERN_ERR "%s: failed to allocate buffer " @@ -1652,7 +1634,7 @@ timer_expired_exit: * resetting it after each frame that arrives from the originator. * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. */ -void sta_rx_agg_session_timer_expired(unsigned long data) +static void sta_rx_agg_session_timer_expired(unsigned long data) { /* not an elegant detour, but there is no choice as the timer passes * only one argument, and verious sta_info are needed here, so init @@ -1841,9 +1823,8 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, " (reason=%d)\n", dev->name, print_mac(mac, mgmt->sa), reason_code); - if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { + if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); - } if (ifsta->state == IEEE80211_AUTHENTICATE || ifsta->state == IEEE80211_ASSOCIATE || @@ -3553,10 +3534,12 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, bss->beacon_int = local->hw.conf.beacon_int; bss->last_update = jiffies; bss->capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) { + + if (sdata->default_key) bss->capability |= WLAN_CAPABILITY_PRIVACY; - } else + else sdata->drop_unencrypted = 0; + bss->supp_rates_len = sband->n_bitrates; pos = bss->supp_rates; for (i = 0; i < sband->n_bitrates; i++) { @@ -4239,6 +4222,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; + kfree(ifsta->extra_ie); if (len == 0) { ifsta->extra_ie = NULL; @@ -4256,9 +4240,9 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) } -struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, - struct sk_buff *skb, u8 *bssid, - u8 *addr) +struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, + struct sk_buff *skb, u8 *bssid, + u8 *addr) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1958bfb361c6..9b5a3cbec265 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -275,11 +275,6 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) } } - I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); - /* only a debug counter, sta might not be assigned properly yet */ - if (rx->sta) - I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - rx->queue = tid; /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7d4fe4a52929..631943e8af8b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -257,7 +257,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ - sta->tid_to_tx_q[i] = local->hw.queues; + sta->tid_to_tx_q[i] = local->hw.queues + local->hw.ampdu_queues; /* rx */ sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; sta->ampdu_mlme.tid_rx[i] = NULL; diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index b7c2ee763d9d..1fa0bb4dba3c 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -13,8 +13,8 @@ #include <linux/crypto.h> #include "key.h" -u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, - u8 iv0, u8 iv1, u8 iv2); +u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, + u8 iv0, u8 iv1, u8 iv2); void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, u16 *phase1key); void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index affcecd78c10..3cbae42ec504 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -337,7 +337,7 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 363779c50658..e587172115b8 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -26,7 +26,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); -u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); +u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index dc1598b86004..c87baf4ce979 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -19,16 +19,22 @@ #include "wme.h" /* maximum number of hardware queues we support. */ -#define TC_80211_MAX_QUEUES 16 +#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) +/* current number of hardware queues we support. */ +#define QD_NUM(hw) ((hw)->queues + (hw)->ampdu_queues) +/* + * Default mapping in classifier to work with default + * queue setup. + */ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; struct ieee80211_sched_data { - unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)]; + unsigned long qdisc_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; struct tcf_proto *filter_list; - struct Qdisc *queues[TC_80211_MAX_QUEUES]; - struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; + struct Qdisc *queues[QD_MAX_QUEUES]; + struct sk_buff_head requeued[QD_MAX_QUEUES]; }; static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0}; @@ -95,7 +101,7 @@ static inline int wme_downgrade_ac(struct sk_buff *skb) /* positive return value indicates which queue to use * negative return value indicates to drop the frame */ -static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) +static int classify80211(struct sk_buff *skb, struct Qdisc *qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -106,7 +112,7 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { /* management frames go on AC_VO queue, but are sent * without QoS control fields */ - return IEEE80211_TX_QUEUE_DATA0; + return 0; } if (0 /* injected */) { @@ -141,14 +147,15 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; struct ieee80211_sched_data *q = qdisc_priv(qd); struct ieee80211_tx_packet_data *pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; - int err, queue; struct sta_info *sta; + int err, queue; u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { @@ -158,7 +165,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) tid = skb->priority & QOS_CONTROL_TAG1D_MASK; if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; - if ((ampdu_queue < local->hw.queues) && + if ((ampdu_queue < QD_NUM(hw)) && test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; pkt_data->flags |= IEEE80211_TXPD_AMPDU; @@ -174,6 +181,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) queue = classify80211(skb, qd); + if (unlikely(queue >= local->hw.queues)) + queue = local->hw.queues - 1; + /* now we know the 1d priority, fill in the QoS header if there is one */ if (WLAN_FC_IS_QOS_DATA(fc)) { @@ -193,8 +203,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) sta = sta_info_get(local, hdr->addr1); if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; - if ((ampdu_queue < local->hw.queues) && - test_bit(ampdu_queue, q->qdisc_pool)) { + if ((ampdu_queue < QD_NUM(hw)) && + test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; pkt_data->flags |= IEEE80211_TXPD_AMPDU; } else { @@ -205,17 +215,6 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) rcu_read_unlock(); } - if (unlikely(queue >= local->hw.queues)) { -#if 0 - if (net_ratelimit()) { - printk(KERN_DEBUG "%s - queue=%d (hw does not " - "support) -> %d\n", - __func__, queue, local->hw.queues - 1); - } -#endif - queue = local->hw.queues - 1; - } - if (unlikely(queue < 0)) { kfree_skb(skb); err = NET_XMIT_DROP; @@ -270,7 +269,7 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) int queue; /* check all the h/w queues in numeric/priority order */ - for (queue = 0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ if ((test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue])) || @@ -308,7 +307,7 @@ static void wme_qdiscop_reset(struct Qdisc* qd) /* QUESTION: should we have some hardware flush functionality here? */ - for (queue = 0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { skb_queue_purge(&q->requeued[queue]); qdisc_reset(q->queues[queue]); } @@ -326,7 +325,7 @@ static void wme_qdiscop_destroy(struct Qdisc* qd) tcf_destroy_chain(q->filter_list); q->filter_list = NULL; - for (queue=0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { skb_queue_purge(&q->requeued[queue]); qdisc_destroy(q->queues[queue]); q->queues[queue] = &noop_qdisc; @@ -337,17 +336,6 @@ static void wme_qdiscop_destroy(struct Qdisc* qd) /* called whenever parameters are updated on existing qdisc */ static int wme_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt) { -/* struct ieee80211_sched_data *q = qdisc_priv(qd); -*/ - /* check our options block is the right size */ - /* copy any options to our local structure */ -/* Ignore options block for now - always use static mapping - struct tc_ieee80211_qopt *qopt = nla_data(opt); - - if (opt->nla_len < nla_attr_size(sizeof(*qopt))) - return -EINVAL; - memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue)); -*/ return 0; } @@ -358,7 +346,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) struct ieee80211_sched_data *q = qdisc_priv(qd); struct net_device *dev = qd->dev; struct ieee80211_local *local; - int queues; + struct ieee80211_hw *hw; int err = 0, i; /* check that device is a mac80211 device */ @@ -366,29 +354,26 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) return -EINVAL; - /* check this device is an ieee80211 master type device */ - if (dev->type != ARPHRD_IEEE80211) + local = wdev_priv(dev->ieee80211_ptr); + hw = &local->hw; + + /* only allow on master dev */ + if (dev != local->mdev) return -EINVAL; - /* check that there is no qdisc currently attached to device - * this ensures that we will be the root qdisc. (I can't find a better - * way to test this explicitly) */ - if (dev->qdisc_sleeping != &noop_qdisc) + /* ensure that we are root qdisc */ + if (qd->parent != TC_H_ROOT) return -EINVAL; if (qd->flags & TCQ_F_INGRESS) return -EINVAL; - local = wdev_priv(dev->ieee80211_ptr); - queues = local->hw.queues; - /* if options were passed in, set them */ - if (opt) { + if (opt) err = wme_qdiscop_tune(qd, opt); - } /* create child queues */ - for (i = 0; i < queues; i++) { + for (i = 0; i < QD_NUM(hw); i++) { skb_queue_head_init(&q->requeued[i]); q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops, qd->handle); @@ -399,8 +384,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) } } - /* reserve all legacy QoS queues */ - for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) + /* non-aggregation queues: reserve/mark as used */ + for (i = 0; i < local->hw.queues; i++) set_bit(i, q->qdisc_pool); return err; @@ -408,16 +393,6 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb) { -/* struct ieee80211_sched_data *q = qdisc_priv(qd); - unsigned char *p = skb->tail; - struct tc_ieee80211_qopt opt; - - memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1); - NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); -*/ return skb->len; -/* -nla_put_failure: - skb_trim(skb, p - skb->data);*/ return -1; } @@ -430,7 +405,7 @@ static int wme_classop_graft(struct Qdisc *qd, unsigned long arg, struct ieee80211_hw *hw = &local->hw; unsigned long queue = arg - 1; - if (queue >= hw->queues) + if (queue >= QD_NUM(hw)) return -EINVAL; if (!new) @@ -454,7 +429,7 @@ wme_classop_leaf(struct Qdisc *qd, unsigned long arg) struct ieee80211_hw *hw = &local->hw; unsigned long queue = arg - 1; - if (queue >= hw->queues) + if (queue >= QD_NUM(hw)) return NULL; return q->queues[queue]; @@ -467,7 +442,7 @@ static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid) struct ieee80211_hw *hw = &local->hw; unsigned long queue = TC_H_MIN(classid); - if (queue - 1 >= hw->queues) + if (queue - 1 >= QD_NUM(hw)) return 0; return queue; @@ -493,7 +468,7 @@ static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent, struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; - if (cl - 1 > hw->queues) + if (cl - 1 > QD_NUM(hw)) return -ENOENT; /* TODO: put code to program hardware queue parameters here, @@ -510,7 +485,7 @@ static int wme_classop_delete(struct Qdisc *qd, unsigned long cl) struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; - if (cl - 1 > hw->queues) + if (cl - 1 > QD_NUM(hw)) return -ENOENT; return 0; } @@ -523,7 +498,7 @@ static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl, struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; - if (cl - 1 > hw->queues) + if (cl - 1 > QD_NUM(hw)) return -ENOENT; tcm->tcm_handle = TC_H_MIN(cl); tcm->tcm_parent = qd->handle; @@ -541,7 +516,7 @@ static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg) if (arg->stop) return; - for (queue = 0; queue < hw->queues; queue++) { + for (queue = 0; queue < QD_NUM(hw); queue++) { if (arg->count < arg->skip) { arg->count++; continue; @@ -658,10 +633,13 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, DECLARE_MAC_BUF(mac); /* prepare the filter and save it for the SW queue - * matching the recieved HW queue */ + * matching the received HW queue */ + + if (!local->hw.ampdu_queues) + return -EPERM; /* try to get a Qdisc from the pool */ - for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) + for (i = local->hw.queues; i < QD_NUM(&local->hw); i++) if (!test_and_set_bit(i, q->qdisc_pool)) { ieee80211_stop_queue(local_to_hw(local), i); sta->tid_to_tx_q[tid] = i; @@ -690,13 +668,14 @@ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, struct sta_info *sta, u16 tid, u8 requeue) { + struct ieee80211_hw *hw = &local->hw; struct ieee80211_sched_data *q = qdisc_priv(local->mdev->qdisc_sleeping); int agg_queue = sta->tid_to_tx_q[tid]; /* return the qdisc to the pool */ clear_bit(agg_queue, q->qdisc_pool); - sta->tid_to_tx_q[tid] = local->hw.queues; + sta->tid_to_tx_q[tid] = QD_NUM(hw); if (requeue) ieee80211_requeue(local, agg_queue); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 45709ada8fee..42f3654e1c5e 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -228,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, 0x7f), (u8) key->u.tkip.iv16); - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return 0; } @@ -256,7 +256,7 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return TX_CONTINUE; } @@ -478,7 +478,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->control->key_idx = key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return 0; } @@ -505,7 +505,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ - tx->control->key_idx = tx->key->conf.hw_key_idx; + tx->control->hw_key = &tx->key->conf; return TX_CONTINUE; } diff --git a/net/sctp/associola.c b/net/sctp/associola.c index b4cd2b71953f..7b79d1e781a8 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -136,6 +136,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a /* Set association default SACK delay */ asoc->sackdelay = msecs_to_jiffies(sp->sackdelay); + asoc->sackfreq = sp->sackfreq; /* Set the association default flags controlling * Heartbeat, SACK delay, and Path MTU Discovery. @@ -261,6 +262,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a * already received one packet.] */ asoc->peer.sack_needed = 1; + asoc->peer.sack_cnt = 0; /* Assume that the peer will tell us if he recognizes ASCONF * as part of INIT exchange. @@ -615,6 +617,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, * association configured value. */ peer->sackdelay = asoc->sackdelay; + peer->sackfreq = asoc->sackfreq; /* Enable/disable heartbeat, SACK delay, and path MTU discovery * based on association setting. diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 0aba759cb9b7..5dd89831eceb 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -383,3 +383,144 @@ void sctp_assocs_proc_exit(void) { remove_proc_entry("assocs", proc_net_sctp); } + +static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos >= sctp_assoc_hashsize) + return NULL; + + if (*pos < 0) + *pos = 0; + + if (*pos == 0) + seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX " + "REM_ADDR_RTX START\n"); + + return (void *)pos; +} + +static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + if (++*pos >= sctp_assoc_hashsize) + return NULL; + + return pos; +} + +static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) +{ + return; +} + +static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) +{ + struct sctp_hashbucket *head; + struct sctp_ep_common *epb; + struct sctp_association *assoc; + struct hlist_node *node; + struct sctp_transport *tsp; + int hash = *(loff_t *)v; + + if (hash >= sctp_assoc_hashsize) + return -ENOMEM; + + head = &sctp_assoc_hashtable[hash]; + sctp_local_bh_disable(); + read_lock(&head->lock); + sctp_for_each_hentry(epb, node, &head->chain) { + assoc = sctp_assoc(epb); + list_for_each_entry(tsp, &assoc->peer.transport_addr_list, + transports) { + /* + * The remote address (ADDR) + */ + tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr); + seq_printf(seq, " "); + + /* + * The association ID (ASSOC_ID) + */ + seq_printf(seq, "%d ", tsp->asoc->assoc_id); + + /* + * If the Heartbeat is active (HB_ACT) + * Note: 1 = Active, 0 = Inactive + */ + seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer)); + + /* + * Retransmit time out (RTO) + */ + seq_printf(seq, "%lu ", tsp->rto); + + /* + * Maximum path retransmit count (PATH_MAX_RTX) + */ + seq_printf(seq, "%d ", tsp->pathmaxrxt); + + /* + * remote address retransmit count (REM_ADDR_RTX) + * Note: We don't have a way to tally this at the moment + * so lets just leave it as zero for the moment + */ + seq_printf(seq, "0 "); + + /* + * remote address start time (START). This is also not + * currently implemented, but we can record it with a + * jiffies marker in a subsequent patch + */ + seq_printf(seq, "0"); + + seq_printf(seq, "\n"); + } + } + + read_unlock(&head->lock); + sctp_local_bh_enable(); + + return 0; + +} + +static const struct seq_operations sctp_remaddr_ops = { + .start = sctp_remaddr_seq_start, + .next = sctp_remaddr_seq_next, + .stop = sctp_remaddr_seq_stop, + .show = sctp_remaddr_seq_show, +}; + +/* Cleanup the proc fs entry for 'remaddr' object. */ +void sctp_remaddr_proc_exit(void) +{ + remove_proc_entry("remaddr", proc_net_sctp); +} + +static int sctp_remaddr_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &sctp_remaddr_ops); +} + +static const struct file_operations sctp_remaddr_seq_fops = { + .open = sctp_remaddr_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int __init sctp_remaddr_proc_init(void) +{ + struct proc_dir_entry *p; + + p = create_proc_entry("remaddr", S_IRUGO, proc_net_sctp); + if (!p) + return -ENOMEM; + p->proc_fops = &sctp_remaddr_seq_fops; + + return 0; +} + +void sctp_assoc_proc_exit(void) +{ + remove_proc_entry("remaddr", proc_net_sctp); +} diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 0ec234b762c2..b8bd9e014498 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -113,6 +113,8 @@ static __init int sctp_proc_init(void) goto out_nomem; if (sctp_assocs_proc_init()) goto out_nomem; + if (sctp_remaddr_proc_init()) + goto out_nomem; return 0; @@ -129,6 +131,7 @@ static void sctp_proc_exit(void) sctp_snmp_proc_exit(); sctp_eps_proc_exit(); sctp_assocs_proc_exit(); + sctp_remaddr_proc_exit(); if (proc_net_sctp) { proc_net_sctp = NULL; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 23a9f1a95b7d..b083312c725a 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -190,20 +190,28 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, * unacknowledged DATA chunk. ... */ if (!asoc->peer.sack_needed) { - /* We will need a SACK for the next packet. */ - asoc->peer.sack_needed = 1; + asoc->peer.sack_cnt++; /* Set the SACK delay timeout based on the * SACK delay for the last transport * data was received from, or the default * for the association. */ - if (trans) + if (trans) { + /* We will need a SACK for the next packet. */ + if (asoc->peer.sack_cnt >= trans->sackfreq - 1) + asoc->peer.sack_needed = 1; + asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = trans->sackdelay; - else + } else { + /* We will need a SACK for the next packet. */ + if (asoc->peer.sack_cnt >= asoc->sackfreq - 1) + asoc->peer.sack_needed = 1; + asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; + } /* Restart the SACK timer. */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, @@ -216,6 +224,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, goto nomem; asoc->peer.sack_needed = 0; + asoc->peer.sack_cnt = 0; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack)); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e7e3baf7009e..81600eea05d2 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -956,7 +956,8 @@ out: */ static int __sctp_connect(struct sock* sk, struct sockaddr *kaddrs, - int addrs_size) + int addrs_size, + sctp_assoc_t *assoc_id) { struct sctp_sock *sp; struct sctp_endpoint *ep; @@ -1111,6 +1112,8 @@ static int __sctp_connect(struct sock* sk, timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); + if (!err && assoc_id) + *assoc_id = asoc->assoc_id; /* Don't free association on exit. */ asoc = NULL; @@ -1128,7 +1131,8 @@ out_free: /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt() * * API 8.9 - * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt); + * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, + * sctp_assoc_t *asoc); * * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. * If the sd is an IPv6 socket, the addresses passed can either be IPv4 @@ -1144,8 +1148,10 @@ out_free: * representation is termed a "packed array" of addresses). The caller * specifies the number of addresses in the array with addrcnt. * - * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns - * -1, and sets errno to the appropriate error code. + * On success, sctp_connectx() returns 0. It also sets the assoc_id to + * the association id of the new association. On failure, sctp_connectx() + * returns -1, and sets errno to the appropriate error code. The assoc_id + * is not touched by the kernel. * * For SCTP, the port given in each socket address must be the same, or * sctp_connectx() will fail, setting errno to EINVAL. @@ -1182,11 +1188,12 @@ out_free: * addrs The pointer to the addresses in user land * addrssize Size of the addrs buffer * - * Returns 0 if ok, <0 errno code on error. + * Returns >=0 if ok, <0 errno code on error. */ -SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, +SCTP_STATIC int __sctp_setsockopt_connectx(struct sock* sk, struct sockaddr __user *addrs, - int addrs_size) + int addrs_size, + sctp_assoc_t *assoc_id) { int err = 0; struct sockaddr *kaddrs; @@ -1209,13 +1216,46 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, if (__copy_from_user(kaddrs, addrs, addrs_size)) { err = -EFAULT; } else { - err = __sctp_connect(sk, kaddrs, addrs_size); + err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); } kfree(kaddrs); + return err; } +/* + * This is an older interface. It's kept for backward compatibility + * to the option that doesn't provide association id. + */ +SCTP_STATIC int sctp_setsockopt_connectx_old(struct sock* sk, + struct sockaddr __user *addrs, + int addrs_size) +{ + return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL); +} + +/* + * New interface for the API. The since the API is done with a socket + * option, to make it simple we feed back the association id is as a return + * indication to the call. Error is always negative and association id is + * always positive. + */ +SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, + struct sockaddr __user *addrs, + int addrs_size) +{ + sctp_assoc_t assoc_id = 0; + int err = 0; + + err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id); + + if (err) + return err; + else + return assoc_id; +} + /* API 3.1.4 close() - UDP Style Syntax * Applications use close() to perform graceful shutdown (as described in * Section 10.1 of [SCTP]) on ALL the associations currently represented @@ -2305,74 +2345,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, return 0; } -/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) - * - * This options will get or set the delayed ack timer. The time is set - * in milliseconds. If the assoc_id is 0, then this sets or gets the - * endpoints default delayed ack timer value. If the assoc_id field is - * non-zero, then the set or get effects the specified association. - * - * struct sctp_assoc_value { - * sctp_assoc_t assoc_id; - * uint32_t assoc_value; - * }; +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + * + * struct sctp_sack_info { + * sctp_assoc_t sack_assoc_id; + * uint32_t sack_delay; + * uint32_t sack_freq; + * }; * - * assoc_id - This parameter, indicates which association the - * user is preforming an action upon. Note that if - * this field's value is zero then the endpoints - * default value is changed (effecting future - * associations only). + * sack_assoc_id - This parameter, indicates which association the user + * is performing an action upon. Note that if this field's value is + * zero then the endpoints default value is changed (effecting future + * associations only). * - * assoc_value - This parameter contains the number of milliseconds - * that the user is requesting the delayed ACK timer - * be set to. Note that this value is defined in - * the standard to be between 200 and 500 milliseconds. + * sack_delay - This parameter contains the number of milliseconds that + * the user is requesting the delayed ACK timer be set to. Note that + * this value is defined in the standard to be between 200 and 500 + * milliseconds. * - * Note: a value of zero will leave the value alone, - * but disable SACK delay. A non-zero value will also - * enable SACK delay. + * sack_freq - This parameter contains the number of packets that must + * be received before a sack is sent without waiting for the delay + * timer to expire. The default value for this is 2, setting this + * value to 1 will disable the delayed sack algorithm. */ -static int sctp_setsockopt_delayed_ack_time(struct sock *sk, +static int sctp_setsockopt_delayed_ack(struct sock *sk, char __user *optval, int optlen) { - struct sctp_assoc_value params; + struct sctp_sack_info params; struct sctp_transport *trans = NULL; struct sctp_association *asoc = NULL; struct sctp_sock *sp = sctp_sk(sk); - if (optlen != sizeof(struct sctp_assoc_value)) - return - EINVAL; + if (optlen == sizeof(struct sctp_sack_info)) { + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; - if (copy_from_user(¶ms, optval, optlen)) - return -EFAULT; + if (params.sack_delay == 0 && params.sack_freq == 0) + return 0; + } else if (optlen == sizeof(struct sctp_assoc_value)) { + printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + "in delayed_ack socket option deprecated\n"); + printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; + + if (params.sack_delay == 0) + params.sack_freq = 1; + else + params.sack_freq = 0; + } else + return - EINVAL; /* Validate value parameter. */ - if (params.assoc_value > 500) + if (params.sack_delay > 500) return -EINVAL; - /* Get association, if assoc_id != 0 and the socket is a one + /* Get association, if sack_assoc_id != 0 and the socket is a one * to many style socket, and an association was not found, then * the id was invalid. */ - asoc = sctp_id2assoc(sk, params.assoc_id); - if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + asoc = sctp_id2assoc(sk, params.sack_assoc_id); + if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) return -EINVAL; - if (params.assoc_value) { + if (params.sack_delay) { if (asoc) { asoc->sackdelay = - msecs_to_jiffies(params.assoc_value); + msecs_to_jiffies(params.sack_delay); asoc->param_flags = (asoc->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; } else { - sp->sackdelay = params.assoc_value; + sp->sackdelay = params.sack_delay; sp->param_flags = (sp->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; } - } else { + } + + if (params.sack_freq == 1) { if (asoc) { asoc->param_flags = (asoc->param_flags & ~SPP_SACKDELAY) | @@ -2382,22 +2446,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk, (sp->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; } + } else if (params.sack_freq > 1) { + if (asoc) { + asoc->sackfreq = params.sack_freq; + asoc->param_flags = + (asoc->param_flags & ~SPP_SACKDELAY) | + SPP_SACKDELAY_ENABLE; + } else { + sp->sackfreq = params.sack_freq; + sp->param_flags = + (sp->param_flags & ~SPP_SACKDELAY) | + SPP_SACKDELAY_ENABLE; + } } /* If change is for association, also apply to each transport. */ if (asoc) { list_for_each_entry(trans, &asoc->peer.transport_addr_list, transports) { - if (params.assoc_value) { + if (params.sack_delay) { trans->sackdelay = - msecs_to_jiffies(params.assoc_value); + msecs_to_jiffies(params.sack_delay); trans->param_flags = (trans->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE; - } else { + } + if (params.sack_delay == 1) { trans->param_flags = (trans->param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE; + } else if (params.sack_freq > 1) { + trans->sackfreq = params.sack_freq; + trans->param_flags = + (trans->param_flags & ~SPP_SACKDELAY) | + SPP_SACKDELAY_ENABLE; } } } @@ -3164,10 +3246,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, optlen, SCTP_BINDX_REM_ADDR); break; + case SCTP_SOCKOPT_CONNECTX_OLD: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_connectx_old(sk, + (struct sockaddr __user *)optval, + optlen); + break; + case SCTP_SOCKOPT_CONNECTX: /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval, - optlen); + retval = sctp_setsockopt_connectx(sk, + (struct sockaddr __user *)optval, + optlen); break; case SCTP_DISABLE_FRAGMENTS: @@ -3186,8 +3276,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); break; - case SCTP_DELAYED_ACK_TIME: - retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen); + case SCTP_DELAYED_ACK: + retval = sctp_setsockopt_delayed_ack(sk, optval, optlen); break; case SCTP_PARTIAL_DELIVERY_POINT: retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen); @@ -3294,7 +3384,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr, /* Pass correct addr len to common routine (so it knows there * is only one address being passed. */ - err = __sctp_connect(sk, addr, af->sockaddr_len); + err = __sctp_connect(sk, addr, af->sockaddr_len, NULL); } sctp_release_sock(sk); @@ -3446,6 +3536,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->pathmaxrxt = sctp_max_retrans_path; sp->pathmtu = 0; // allow default discovery sp->sackdelay = sctp_sack_timeout; + sp->sackfreq = 3; sp->param_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE | SPP_SACKDELAY_ENABLE; @@ -3999,70 +4090,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, return 0; } -/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) - * - * This options will get or set the delayed ack timer. The time is set - * in milliseconds. If the assoc_id is 0, then this sets or gets the - * endpoints default delayed ack timer value. If the assoc_id field is - * non-zero, then the set or get effects the specified association. - * - * struct sctp_assoc_value { - * sctp_assoc_t assoc_id; - * uint32_t assoc_value; - * }; +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + * + * struct sctp_sack_info { + * sctp_assoc_t sack_assoc_id; + * uint32_t sack_delay; + * uint32_t sack_freq; + * }; * - * assoc_id - This parameter, indicates which association the - * user is preforming an action upon. Note that if - * this field's value is zero then the endpoints - * default value is changed (effecting future - * associations only). + * sack_assoc_id - This parameter, indicates which association the user + * is performing an action upon. Note that if this field's value is + * zero then the endpoints default value is changed (effecting future + * associations only). * - * assoc_value - This parameter contains the number of milliseconds - * that the user is requesting the delayed ACK timer - * be set to. Note that this value is defined in - * the standard to be between 200 and 500 milliseconds. + * sack_delay - This parameter contains the number of milliseconds that + * the user is requesting the delayed ACK timer be set to. Note that + * this value is defined in the standard to be between 200 and 500 + * milliseconds. * - * Note: a value of zero will leave the value alone, - * but disable SACK delay. A non-zero value will also - * enable SACK delay. + * sack_freq - This parameter contains the number of packets that must + * be received before a sack is sent without waiting for the delay + * timer to expire. The default value for this is 2, setting this + * value to 1 will disable the delayed sack algorithm. */ -static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len, +static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, char __user *optval, int __user *optlen) { - struct sctp_assoc_value params; + struct sctp_sack_info params; struct sctp_association *asoc = NULL; struct sctp_sock *sp = sctp_sk(sk); - if (len < sizeof(struct sctp_assoc_value)) - return - EINVAL; - - len = sizeof(struct sctp_assoc_value); + if (len >= sizeof(struct sctp_sack_info)) { + len = sizeof(struct sctp_sack_info); - if (copy_from_user(¶ms, optval, len)) - return -EFAULT; + if (copy_from_user(¶ms, optval, len)) + return -EFAULT; + } else if (len == sizeof(struct sctp_assoc_value)) { + printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + "in delayed_ack socket option deprecated\n"); + printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + if (copy_from_user(¶ms, optval, len)) + return -EFAULT; + } else + return - EINVAL; - /* Get association, if assoc_id != 0 and the socket is a one + /* Get association, if sack_assoc_id != 0 and the socket is a one * to many style socket, and an association was not found, then * the id was invalid. */ - asoc = sctp_id2assoc(sk, params.assoc_id); - if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + asoc = sctp_id2assoc(sk, params.sack_assoc_id); + if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP)) return -EINVAL; if (asoc) { /* Fetch association values. */ - if (asoc->param_flags & SPP_SACKDELAY_ENABLE) - params.assoc_value = jiffies_to_msecs( + if (asoc->param_flags & SPP_SACKDELAY_ENABLE) { + params.sack_delay = jiffies_to_msecs( asoc->sackdelay); - else - params.assoc_value = 0; + params.sack_freq = asoc->sackfreq; + + } else { + params.sack_delay = 0; + params.sack_freq = 1; + } } else { /* Fetch socket values. */ - if (sp->param_flags & SPP_SACKDELAY_ENABLE) - params.assoc_value = sp->sackdelay; - else - params.assoc_value = 0; + if (sp->param_flags & SPP_SACKDELAY_ENABLE) { + params.sack_delay = sp->sackdelay; + params.sack_freq = sp->sackfreq; + } else { + params.sack_delay = 0; + params.sack_freq = 1; + } } if (copy_to_user(optval, ¶ms, len)) @@ -5218,8 +5330,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_peer_addr_params(sk, len, optval, optlen); break; - case SCTP_DELAYED_ACK_TIME: - retval = sctp_getsockopt_delayed_ack_time(sk, len, optval, + case SCTP_DELAYED_ACK: + retval = sctp_getsockopt_delayed_ack(sk, len, optval, optlen); break; case SCTP_INITMSG: diff --git a/net/tipc/config.c b/net/tipc/config.c index c71337a22d33..91d56f8fee9f 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c @@ -529,7 +529,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area break; #endif case TIPC_CMD_SET_LOG_SIZE: - rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space); + rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space); break; case TIPC_CMD_DUMP_LOG: rep_tlv_buf = tipc_log_dump(); diff --git a/net/tipc/core.c b/net/tipc/core.c index 740aac5cdfb6..6d6aa5a3c240 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -49,7 +49,7 @@ #include "config.h" -#define TIPC_MOD_VER "1.6.3" +#define TIPC_MOD_VER "1.6.4" #ifndef CONFIG_TIPC_ZONES #define CONFIG_TIPC_ZONES 3 @@ -182,7 +182,7 @@ static int __init tipc_init(void) { int res; - tipc_log_reinit(CONFIG_TIPC_LOG); + tipc_log_resize(CONFIG_TIPC_LOG); info("Activated (version " TIPC_MOD_VER " compiled " __DATE__ " " __TIME__ ")\n"); @@ -209,7 +209,7 @@ static void __exit tipc_exit(void) tipc_core_stop_net(); tipc_core_stop(); info("Deactivated\n"); - tipc_log_stop(); + tipc_log_resize(0); } module_init(tipc_init); diff --git a/net/tipc/core.h b/net/tipc/core.h index 5a0e4878d3b7..bd78d1705c0f 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -2,7 +2,7 @@ * net/tipc/core.h: Include file for TIPC global declarations * * Copyright (c) 2005-2006, Ericsson AB - * Copyright (c) 2005-2006, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,84 +59,108 @@ #include <linux/vmalloc.h> /* - * TIPC debugging code + * TIPC sanity test macros */ #define assert(i) BUG_ON(!(i)) -struct tipc_msg; -extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG; -extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *); -void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*); -void tipc_printf(struct print_buf *, const char *fmt, ...); -void tipc_dump(struct print_buf*,const char *fmt, ...); - -#ifdef CONFIG_TIPC_DEBUG - /* - * TIPC debug support included: - * - system messages are printed to TIPC_OUTPUT print buffer - * - debug messages are printed to DBG_OUTPUT print buffer + * TIPC system monitoring code */ -#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg) -#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg) -#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg) +/* + * TIPC's print buffer subsystem supports the following print buffers: + * + * TIPC_NULL : null buffer (i.e. print nowhere) + * TIPC_CONS : system console + * TIPC_LOG : TIPC log buffer + * &buf : user-defined buffer (struct print_buf *) + * + * Note: TIPC_LOG is configured to echo its output to the system console; + * user-defined buffers can be configured to do the same thing. + */ -#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0) -#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0) -#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0) +extern struct print_buf *const TIPC_NULL; +extern struct print_buf *const TIPC_CONS; +extern struct print_buf *const TIPC_LOG; +void tipc_printf(struct print_buf *, const char *fmt, ...); /* - * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer, - * while DBG_OUTPUT is the null print buffer. These defaults can be changed - * here, or on a per .c file basis, by redefining these symbols. The following - * print buffer options are available: - * - * TIPC_NULL : null buffer (i.e. print nowhere) - * TIPC_CONS : system console - * TIPC_LOG : TIPC log buffer - * &buf : user-defined buffer (struct print_buf *) - * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG)) + * TIPC_OUTPUT is the destination print buffer for system messages. */ #ifndef TIPC_OUTPUT -#define TIPC_OUTPUT TIPC_TEE(TIPC_CONS,TIPC_LOG) -#endif - -#ifndef DBG_OUTPUT -#define DBG_OUTPUT TIPC_NULL +#define TIPC_OUTPUT TIPC_LOG #endif -#else - /* - * TIPC debug support not included: - * - system messages are printed to system console - * - debug messages are not printed + * TIPC can be configured to send system messages to TIPC_OUTPUT + * or to the system console only. */ +#ifdef CONFIG_TIPC_DEBUG + +#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ + KERN_ERR "TIPC: " fmt, ## arg) +#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ + KERN_WARNING "TIPC: " fmt, ## arg) +#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ + KERN_NOTICE "TIPC: " fmt, ## arg) + +#else + #define err(fmt, arg...) printk(KERN_ERR "TIPC: " fmt , ## arg) #define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg) #define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg) -#define dbg(fmt, arg...) do {} while (0) -#define msg_dbg(msg,txt) do {} while (0) -#define dump(fmt,arg...) do {} while (0) +#endif +/* + * DBG_OUTPUT is the destination print buffer for debug messages. + * It defaults to the the null print buffer, but can be redefined + * (typically in the individual .c files being debugged) to allow + * selected debug messages to be generated where needed. + */ + +#ifndef DBG_OUTPUT +#define DBG_OUTPUT TIPC_NULL +#endif /* - * TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is - * the null print buffer. Thes ensures that any system or debug messages - * that are generated without using the above macros are handled correctly. + * TIPC can be configured to send debug messages to the specified print buffer + * (typically DBG_OUTPUT) or to suppress them entirely. */ -#undef TIPC_OUTPUT -#define TIPC_OUTPUT TIPC_CONS +#ifdef CONFIG_TIPC_DEBUG -#undef DBG_OUTPUT -#define DBG_OUTPUT TIPC_NULL +#define dbg(fmt, arg...) \ + do { \ + if (DBG_OUTPUT != TIPC_NULL) \ + tipc_printf(DBG_OUTPUT, fmt, ## arg); \ + } while (0) +#define msg_dbg(msg, txt) \ + do { \ + if (DBG_OUTPUT != TIPC_NULL) \ + tipc_msg_dbg(DBG_OUTPUT, msg, txt); \ + } while (0) +#define dump(fmt, arg...) \ + do { \ + if (DBG_OUTPUT != TIPC_NULL) \ + tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \ + } while (0) + +void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *); +void tipc_dump_dbg(struct print_buf *, const char *fmt, ...); + +#else + +#define dbg(fmt, arg...) do {} while (0) +#define msg_dbg(msg, txt) do {} while (0) +#define dump(fmt, arg...) do {} while (0) + +#define tipc_msg_dbg(...) do {} while (0) +#define tipc_dump_dbg(...) do {} while (0) #endif diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c index e809d2a2ce06..29ecae851668 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/dbg.c @@ -2,7 +2,7 @@ * net/tipc/dbg.c: TIPC print buffer routines for debugging * * Copyright (c) 1996-2006, Ericsson AB - * Copyright (c) 2005-2006, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,17 +38,43 @@ #include "config.h" #include "dbg.h" -static char print_string[TIPC_PB_MAX_STR]; -static DEFINE_SPINLOCK(print_lock); +/* + * TIPC pre-defines the following print buffers: + * + * TIPC_NULL : null buffer (i.e. print nowhere) + * TIPC_CONS : system console + * TIPC_LOG : TIPC log buffer + * + * Additional user-defined print buffers are also permitted. + */ -static struct print_buf null_buf = { NULL, 0, NULL, NULL }; -struct print_buf *TIPC_NULL = &null_buf; +static struct print_buf null_buf = { NULL, 0, NULL, 0 }; +struct print_buf *const TIPC_NULL = &null_buf; -static struct print_buf cons_buf = { NULL, 0, NULL, NULL }; -struct print_buf *TIPC_CONS = &cons_buf; +static struct print_buf cons_buf = { NULL, 0, NULL, 1 }; +struct print_buf *const TIPC_CONS = &cons_buf; -static struct print_buf log_buf = { NULL, 0, NULL, NULL }; -struct print_buf *TIPC_LOG = &log_buf; +static struct print_buf log_buf = { NULL, 0, NULL, 1 }; +struct print_buf *const TIPC_LOG = &log_buf; + +/* + * Locking policy when using print buffers. + * + * 1) tipc_printf() uses 'print_lock' to protect against concurrent access to + * 'print_string' when writing to a print buffer. This also protects against + * concurrent writes to the print buffer being written to. + * + * 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned + * use of 'print_lock' to protect against all types of concurrent operations + * on their associated print buffer (not just write operations). + * + * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely + * on the caller to prevent simultaneous use of the print buffer(s) being + * manipulated. + */ + +static char print_string[TIPC_PB_MAX_STR]; +static DEFINE_SPINLOCK(print_lock); #define FORMAT(PTR,LEN,FMT) \ @@ -60,27 +86,14 @@ struct print_buf *TIPC_LOG = &log_buf; *(PTR + LEN) = '\0';\ } -/* - * Locking policy when using print buffers. - * - * The following routines use 'print_lock' for protection: - * 1) tipc_printf() - to protect its print buffer(s) and 'print_string' - * 2) TIPC_TEE() - to protect its print buffer(s) - * 3) tipc_dump() - to protect its print buffer(s) and 'print_string' - * 4) tipc_log_XXX() - to protect TIPC_LOG - * - * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent - * simultaneous use of the print buffer(s) being manipulated. - */ - /** * tipc_printbuf_init - initialize print buffer to empty * @pb: pointer to print buffer structure * @raw: pointer to character array used by print buffer * @size: size of character array * - * Makes the print buffer a null device that discards anything written to it - * if the character array is too small (or absent). + * Note: If the character array is too small (or absent), the print buffer + * becomes a null device that discards anything written to it. */ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) @@ -88,13 +101,13 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) pb->buf = raw; pb->crs = raw; pb->size = size; - pb->next = NULL; + pb->echo = 0; if (size < TIPC_PB_MIN_SIZE) { pb->buf = NULL; } else if (raw) { pb->buf[0] = 0; - pb->buf[size-1] = ~0; + pb->buf[size - 1] = ~0; } } @@ -105,7 +118,11 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) void tipc_printbuf_reset(struct print_buf *pb) { - tipc_printbuf_init(pb, pb->buf, pb->size); + if (pb->buf) { + pb->crs = pb->buf; + pb->buf[0] = 0; + pb->buf[pb->size - 1] = ~0; + } } /** @@ -141,7 +158,7 @@ int tipc_printbuf_validate(struct print_buf *pb) if (pb->buf[pb->size - 1] == 0) { cp_buf = kmalloc(pb->size, GFP_ATOMIC); - if (cp_buf != NULL){ + if (cp_buf) { tipc_printbuf_init(&cb, cp_buf, pb->size); tipc_printbuf_move(&cb, pb); tipc_printbuf_move(pb, &cb); @@ -179,15 +196,16 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) } if (pb_to->size < pb_from->size) { - tipc_printbuf_reset(pb_to); - tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***"); + strcpy(pb_to->buf, "*** PRINT BUFFER MOVE ERROR ***"); + pb_to->buf[pb_to->size - 1] = ~0; + pb_to->crs = strchr(pb_to->buf, 0); return; } /* Copy data from char after cursor to end (if used) */ len = pb_from->buf + pb_from->size - pb_from->crs - 2; - if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) { + if ((pb_from->buf[pb_from->size - 1] == 0) && (len > 0)) { strcpy(pb_to->buf, pb_from->crs + 1); pb_to->crs = pb_to->buf + len; } else @@ -203,8 +221,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) } /** - * tipc_printf - append formatted output to print buffer chain - * @pb: pointer to chain of print buffers (may be NULL) + * tipc_printf - append formatted output to print buffer + * @pb: pointer to print buffer * @fmt: formatted info to be printed */ @@ -213,68 +231,40 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) int chars_to_add; int chars_left; char save_char; - struct print_buf *pb_next; spin_lock_bh(&print_lock); + FORMAT(print_string, chars_to_add, fmt); if (chars_to_add >= TIPC_PB_MAX_STR) strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***"); - while (pb) { - if (pb == TIPC_CONS) - printk(print_string); - else if (pb->buf) { - chars_left = pb->buf + pb->size - pb->crs - 1; - if (chars_to_add <= chars_left) { - strcpy(pb->crs, print_string); - pb->crs += chars_to_add; - } else if (chars_to_add >= (pb->size - 1)) { - strcpy(pb->buf, print_string + chars_to_add + 1 - - pb->size); - pb->crs = pb->buf + pb->size - 1; - } else { - strcpy(pb->buf, print_string + chars_left); - save_char = print_string[chars_left]; - print_string[chars_left] = 0; - strcpy(pb->crs, print_string); - print_string[chars_left] = save_char; - pb->crs = pb->buf + chars_to_add - chars_left; - } + if (pb->buf) { + chars_left = pb->buf + pb->size - pb->crs - 1; + if (chars_to_add <= chars_left) { + strcpy(pb->crs, print_string); + pb->crs += chars_to_add; + } else if (chars_to_add >= (pb->size - 1)) { + strcpy(pb->buf, print_string + chars_to_add + 1 + - pb->size); + pb->crs = pb->buf + pb->size - 1; + } else { + strcpy(pb->buf, print_string + chars_left); + save_char = print_string[chars_left]; + print_string[chars_left] = 0; + strcpy(pb->crs, print_string); + print_string[chars_left] = save_char; + pb->crs = pb->buf + chars_to_add - chars_left; } - pb_next = pb->next; - pb->next = NULL; - pb = pb_next; } - spin_unlock_bh(&print_lock); -} -/** - * TIPC_TEE - perform next output operation on both print buffers - * @b0: pointer to chain of print buffers (may be NULL) - * @b1: pointer to print buffer to add to chain - * - * Returns pointer to print buffer chain. - */ + if (pb->echo) + printk(print_string); -struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1) -{ - struct print_buf *pb = b0; - - if (!b0 || (b0 == b1)) - return b1; - - spin_lock_bh(&print_lock); - while (pb->next) { - if ((pb->next == b1) || (pb->next == b0)) - pb->next = pb->next->next; - else - pb = pb->next; - } - pb->next = b1; spin_unlock_bh(&print_lock); - return b0; } +#ifdef CONFIG_TIPC_DEBUG + /** * print_to_console - write string of bytes to console in multiple chunks */ @@ -321,72 +311,66 @@ static void printbuf_dump(struct print_buf *pb) } /** - * tipc_dump - dump non-console print buffer(s) to console - * @pb: pointer to chain of print buffers + * tipc_dump_dbg - dump (non-console) print buffer to console + * @pb: pointer to print buffer */ -void tipc_dump(struct print_buf *pb, const char *fmt, ...) +void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...) { - struct print_buf *pb_next; int len; + if (pb == TIPC_CONS) + return; + spin_lock_bh(&print_lock); + FORMAT(print_string, len, fmt); printk(print_string); - for (; pb; pb = pb->next) { - if (pb != TIPC_CONS) { - printk("\n---- Start of %s log dump ----\n\n", - (pb == TIPC_LOG) ? "global" : "local"); - printbuf_dump(pb); - tipc_printbuf_reset(pb); - printk("\n---- End of dump ----\n"); - } - pb_next = pb->next; - pb->next = NULL; - pb = pb_next; - } + printk("\n---- Start of %s log dump ----\n\n", + (pb == TIPC_LOG) ? "global" : "local"); + printbuf_dump(pb); + tipc_printbuf_reset(pb); + printk("\n---- End of dump ----\n"); + spin_unlock_bh(&print_lock); } +#endif + /** - * tipc_log_stop - free up TIPC log print buffer + * tipc_log_resize - change the size of the TIPC log buffer + * @log_size: print buffer size to use */ -void tipc_log_stop(void) +int tipc_log_resize(int log_size) { + int res = 0; + spin_lock_bh(&print_lock); if (TIPC_LOG->buf) { kfree(TIPC_LOG->buf); TIPC_LOG->buf = NULL; } - spin_unlock_bh(&print_lock); -} - -/** - * tipc_log_reinit - (re)initialize TIPC log print buffer - * @log_size: print buffer size to use - */ - -void tipc_log_reinit(int log_size) -{ - tipc_log_stop(); - if (log_size) { if (log_size < TIPC_PB_MIN_SIZE) log_size = TIPC_PB_MIN_SIZE; - spin_lock_bh(&print_lock); + res = TIPC_LOG->echo; tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size); - spin_unlock_bh(&print_lock); + TIPC_LOG->echo = res; + res = !TIPC_LOG->buf; } + spin_unlock_bh(&print_lock); + + return res; } /** - * tipc_log_resize - reconfigure size of TIPC log buffer + * tipc_log_resize_cmd - reconfigure size of TIPC log buffer */ -struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) +struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space) { u32 value; @@ -397,7 +381,9 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) if (value != delimit(value, 0, 32768)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (log size must be 0-32768)"); - tipc_log_reinit(value); + if (tipc_log_resize(value)) + return tipc_cfg_reply_error_string( + "unable to create specified log (log size is now 0)"); return tipc_cfg_reply_none(); } @@ -410,27 +396,32 @@ struct sk_buff *tipc_log_dump(void) struct sk_buff *reply; spin_lock_bh(&print_lock); - if (!TIPC_LOG->buf) + if (!TIPC_LOG->buf) { + spin_unlock_bh(&print_lock); reply = tipc_cfg_reply_ultra_string("log not activated\n"); - else if (tipc_printbuf_empty(TIPC_LOG)) + } else if (tipc_printbuf_empty(TIPC_LOG)) { + spin_unlock_bh(&print_lock); reply = tipc_cfg_reply_ultra_string("log is empty\n"); + } else { struct tlv_desc *rep_tlv; struct print_buf pb; int str_len; str_len = min(TIPC_LOG->size, 32768u); + spin_unlock_bh(&print_lock); reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len)); if (reply) { rep_tlv = (struct tlv_desc *)reply->data; tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len); + spin_lock_bh(&print_lock); tipc_printbuf_move(&pb, TIPC_LOG); + spin_unlock_bh(&print_lock); str_len = strlen(TLV_DATA(rep_tlv)) + 1; skb_put(reply, TLV_SPACE(str_len)); TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); } } - spin_unlock_bh(&print_lock); return reply; } diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h index c01b085000e0..5ef1bc8f64ef 100644 --- a/net/tipc/dbg.h +++ b/net/tipc/dbg.h @@ -2,7 +2,7 @@ * net/tipc/dbg.h: Include file for TIPC print buffer routines * * Copyright (c) 1997-2006, Ericsson AB - * Copyright (c) 2005-2006, Wind River Systems + * Copyright (c) 2005-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,14 +42,14 @@ * @buf: pointer to character array containing print buffer contents * @size: size of character array * @crs: pointer to first unused space in character array (i.e. final NUL) - * @next: used to link print buffers when printing to more than one at a time + * @echo: echo output to system console if non-zero */ struct print_buf { char *buf; u32 size; char *crs; - struct print_buf *next; + int echo; }; #define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */ @@ -61,10 +61,10 @@ int tipc_printbuf_empty(struct print_buf *pb); int tipc_printbuf_validate(struct print_buf *pb); void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from); -void tipc_log_reinit(int log_size); -void tipc_log_stop(void); +int tipc_log_resize(int log_size); -struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space); +struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, + int req_tlv_space); struct sk_buff *tipc_log_dump(void); #endif diff --git a/net/tipc/link.c b/net/tipc/link.c index 2a26a16e269f..bd206ebe4eea 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -147,9 +147,21 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, #define LINK_LOG_BUF_SIZE 0 -#define dbg_link(fmt, arg...) do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0) -#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) tipc_msg_print(&l_ptr->print_buf, msg, txt); } while(0) -#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0) +#define dbg_link(fmt, arg...) \ + do { \ + if (LINK_LOG_BUF_SIZE) \ + tipc_printf(&l_ptr->print_buf, fmt, ## arg); \ + } while (0) +#define dbg_link_msg(msg, txt) \ + do { \ + if (LINK_LOG_BUF_SIZE) \ + tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \ + } while (0) +#define dbg_link_state(txt) \ + do { \ + if (LINK_LOG_BUF_SIZE) \ + link_print(l_ptr, &l_ptr->print_buf, txt); \ + } while (0) #define dbg_link_dump() do { \ if (LINK_LOG_BUF_SIZE) { \ tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \ @@ -1651,7 +1663,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf) struct tipc_msg *msg = buf_msg(buf); warn("Retransmission failure on link <%s>\n", l_ptr->name); - tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>"); + tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>"); if (l_ptr->addr) { diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 696a8633df75..38abebaae889 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -41,7 +41,9 @@ #include "bearer.h" -void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str) +#ifdef CONFIG_TIPC_DEBUG + +void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) { u32 usr = msg_user(msg); tipc_printf(buf, str); @@ -315,9 +317,11 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str } tipc_printf(buf, "\n"); if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) { - tipc_msg_print(buf,msg_get_wrapped(msg)," /"); + tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); } if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) { - tipc_msg_print(buf,msg_get_wrapped(msg)," /"); + tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); } } + +#endif diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 39fd1619febf..aecba5cd87d6 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -41,9 +41,6 @@ #include "msg.h" #include "name_distr.h" -#undef DBG_OUTPUT -#define DBG_OUTPUT NULL - #define ITEM_SIZE sizeof(struct distr_item) /** diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index ac7dfdda7973..892373e498e4 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -1050,15 +1050,12 @@ void tipc_nametbl_dump(void) int tipc_nametbl_init(void) { - int array_size = sizeof(struct hlist_head) * tipc_nametbl_size; - - table.types = kzalloc(array_size, GFP_ATOMIC); + table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head), + GFP_ATOMIC); if (!table.types) return -ENOMEM; - write_lock_bh(&tipc_nametbl_lock); table.local_publ_count = 0; - write_unlock_bh(&tipc_nametbl_lock); return 0; } diff --git a/net/tipc/port.c b/net/tipc/port.c index 2f5806410c64..757de38fe6af 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -211,15 +211,18 @@ exit: } /** - * tipc_createport_raw - create a native TIPC port + * tipc_createport_raw - create a generic TIPC port * - * Returns local port reference + * Returns port reference, or 0 if unable to create it + * + * Note: The newly created port is returned in the locked state. */ u32 tipc_createport_raw(void *usr_handle, u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), void (*wakeup)(struct tipc_port *), - const u32 importance) + const u32 importance, + struct tipc_port **tp_ptr) { struct port *p_ptr; struct tipc_msg *msg; @@ -237,7 +240,6 @@ u32 tipc_createport_raw(void *usr_handle, return 0; } - tipc_port_lock(ref); p_ptr->publ.usr_handle = usr_handle; p_ptr->publ.max_pkt = MAX_PKT_DEFAULT; p_ptr->publ.ref = ref; @@ -262,7 +264,7 @@ u32 tipc_createport_raw(void *usr_handle, INIT_LIST_HEAD(&p_ptr->port_list); list_add_tail(&p_ptr->port_list, &ports); spin_unlock_bh(&tipc_port_list_lock); - tipc_port_unlock(p_ptr); + *tp_ptr = &p_ptr->publ; return ref; } @@ -1053,6 +1055,7 @@ int tipc_createport(u32 user_ref, { struct user_port *up_ptr; struct port *p_ptr; + struct tipc_port *tp_ptr; u32 ref; up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC); @@ -1060,12 +1063,13 @@ int tipc_createport(u32 user_ref, warn("Port creation failed, no memory\n"); return -ENOMEM; } - ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance); - p_ptr = tipc_port_lock(ref); - if (!p_ptr) { + ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, + importance, &tp_ptr); + if (ref == 0) { kfree(up_ptr); return -ENOMEM; } + p_ptr = (struct port *)tp_ptr; p_ptr->user_port = up_ptr; up_ptr->user_ref = user_ref; diff --git a/net/tipc/ref.c b/net/tipc/ref.c index 89cbab24d08f..a101de86824d 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -142,9 +142,13 @@ void tipc_ref_table_stop(void) /** * tipc_ref_acquire - create reference to an object * - * Return a unique reference value which can be translated back to the pointer - * 'object' at a later time. Also, pass back a pointer to the lock protecting - * the object, but without locking it. + * Register an object pointer in reference table and lock the object. + * Returns a unique reference value that is used from then on to retrieve the + * object pointer, or to determine that the object has been deregistered. + * + * Note: The object is returned in the locked state so that the caller can + * register a partially initialized object, without running the risk that + * the object will be accessed before initialization is complete. */ u32 tipc_ref_acquire(void *object, spinlock_t **lock) @@ -178,13 +182,13 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) ref = (next_plus_upper & ~index_mask) + index; entry->ref = ref; entry->object = object; - spin_unlock_bh(&entry->lock); *lock = &entry->lock; } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { index = tipc_ref_table.init_point++; entry = &(tipc_ref_table.entries[index]); spin_lock_init(&entry->lock); + spin_lock_bh(&entry->lock); ref = tipc_ref_table.start_mask + index; entry->ref = ref; entry->object = object; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 230f9ca2ad6b..38f48795b40e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -188,6 +188,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) const struct proto_ops *ops; socket_state state; struct sock *sk; + struct tipc_port *tp_ptr; u32 portref; /* Validate arguments */ @@ -225,7 +226,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) /* Allocate TIPC port for socket to use */ portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch, - TIPC_LOW_IMPORTANCE); + TIPC_LOW_IMPORTANCE, &tp_ptr); if (unlikely(portref == 0)) { sk_free(sk); return -ENOMEM; @@ -241,6 +242,8 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) sk->sk_backlog_rcv = backlog_rcv; tipc_sk(sk)->p = tipc_get_port(portref); + spin_unlock_bh(tp_ptr->lock); + if (sock->state == SS_READY) { tipc_set_portunreturnable(portref, 1); if (sock->type == SOCK_DGRAM) diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 8c01ccd3626c..8f8d0a6c1c16 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -474,6 +474,7 @@ static void subscr_named_msg_event(void *usr_handle, kfree(subscriber); return; } + spin_unlock_bh(subscriber->lock); /* Establish a connection to subscriber */ |