diff options
Diffstat (limited to 'net')
297 files changed, 17805 insertions, 6286 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 52077ca22072..6e64f7c6a2e9 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -272,13 +272,11 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) | |||
272 | snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); | 272 | snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); |
273 | } | 273 | } |
274 | 274 | ||
275 | new_dev = alloc_netdev_mq(sizeof(struct vlan_dev_info), name, | 275 | new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name, vlan_setup); |
276 | vlan_setup, real_dev->num_tx_queues); | ||
277 | 276 | ||
278 | if (new_dev == NULL) | 277 | if (new_dev == NULL) |
279 | return -ENOBUFS; | 278 | return -ENOBUFS; |
280 | 279 | ||
281 | netif_copy_real_num_queues(new_dev, real_dev); | ||
282 | dev_net_set(new_dev, net); | 280 | dev_net_set(new_dev, net); |
283 | /* need 4 bytes for extra VLAN header info, | 281 | /* need 4 bytes for extra VLAN header info, |
284 | * hope the underlying device can handle it. | 282 | * hope the underlying device can handle it. |
@@ -334,12 +332,15 @@ static void vlan_transfer_features(struct net_device *dev, | |||
334 | vlandev->features &= ~dev->vlan_features; | 332 | vlandev->features &= ~dev->vlan_features; |
335 | vlandev->features |= dev->features & dev->vlan_features; | 333 | vlandev->features |= dev->features & dev->vlan_features; |
336 | vlandev->gso_max_size = dev->gso_max_size; | 334 | vlandev->gso_max_size = dev->gso_max_size; |
335 | |||
336 | if (dev->features & NETIF_F_HW_VLAN_TX) | ||
337 | vlandev->hard_header_len = dev->hard_header_len; | ||
338 | else | ||
339 | vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN; | ||
340 | |||
337 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 341 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
338 | vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; | 342 | vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; |
339 | #endif | 343 | #endif |
340 | vlandev->real_num_tx_queues = dev->real_num_tx_queues; | ||
341 | BUG_ON(vlandev->real_num_tx_queues > vlandev->num_tx_queues); | ||
342 | |||
343 | if (old_features != vlandev->features) | 344 | if (old_features != vlandev->features) |
344 | netdev_features_change(vlandev); | 345 | netdev_features_change(vlandev); |
345 | } | 346 | } |
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index db01b3181fdc..5687c9b95f33 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
@@ -19,19 +19,25 @@ struct vlan_priority_tci_mapping { | |||
19 | 19 | ||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * struct vlan_rx_stats - VLAN percpu rx stats | 22 | * struct vlan_pcpu_stats - VLAN percpu rx/tx stats |
23 | * @rx_packets: number of received packets | 23 | * @rx_packets: number of received packets |
24 | * @rx_bytes: number of received bytes | 24 | * @rx_bytes: number of received bytes |
25 | * @rx_multicast: number of received multicast packets | 25 | * @rx_multicast: number of received multicast packets |
26 | * @tx_packets: number of transmitted packets | ||
27 | * @tx_bytes: number of transmitted bytes | ||
26 | * @syncp: synchronization point for 64bit counters | 28 | * @syncp: synchronization point for 64bit counters |
27 | * @rx_errors: number of errors | 29 | * @rx_errors: number of rx errors |
30 | * @tx_dropped: number of tx drops | ||
28 | */ | 31 | */ |
29 | struct vlan_rx_stats { | 32 | struct vlan_pcpu_stats { |
30 | u64 rx_packets; | 33 | u64 rx_packets; |
31 | u64 rx_bytes; | 34 | u64 rx_bytes; |
32 | u64 rx_multicast; | 35 | u64 rx_multicast; |
36 | u64 tx_packets; | ||
37 | u64 tx_bytes; | ||
33 | struct u64_stats_sync syncp; | 38 | struct u64_stats_sync syncp; |
34 | unsigned long rx_errors; | 39 | u32 rx_errors; |
40 | u32 tx_dropped; | ||
35 | }; | 41 | }; |
36 | 42 | ||
37 | /** | 43 | /** |
@@ -45,9 +51,7 @@ struct vlan_rx_stats { | |||
45 | * @real_dev: underlying netdevice | 51 | * @real_dev: underlying netdevice |
46 | * @real_dev_addr: address of underlying netdevice | 52 | * @real_dev_addr: address of underlying netdevice |
47 | * @dent: proc dir entry | 53 | * @dent: proc dir entry |
48 | * @cnt_inc_headroom_on_tx: statistic - number of skb expansions on TX | 54 | * @vlan_pcpu_stats: ptr to percpu rx stats |
49 | * @cnt_encap_on_xmit: statistic - number of skb encapsulations on TX | ||
50 | * @vlan_rx_stats: ptr to percpu rx stats | ||
51 | */ | 55 | */ |
52 | struct vlan_dev_info { | 56 | struct vlan_dev_info { |
53 | unsigned int nr_ingress_mappings; | 57 | unsigned int nr_ingress_mappings; |
@@ -62,9 +66,7 @@ struct vlan_dev_info { | |||
62 | unsigned char real_dev_addr[ETH_ALEN]; | 66 | unsigned char real_dev_addr[ETH_ALEN]; |
63 | 67 | ||
64 | struct proc_dir_entry *dent; | 68 | struct proc_dir_entry *dent; |
65 | unsigned long cnt_inc_headroom_on_tx; | 69 | struct vlan_pcpu_stats __percpu *vlan_pcpu_stats; |
66 | unsigned long cnt_encap_on_xmit; | ||
67 | struct vlan_rx_stats __percpu *vlan_rx_stats; | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) | 72 | static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev) |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 69b2f79800a5..ce8e3ab3e7a5 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -9,7 +9,7 @@ bool vlan_hwaccel_do_receive(struct sk_buff **skbp) | |||
9 | struct sk_buff *skb = *skbp; | 9 | struct sk_buff *skb = *skbp; |
10 | u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK; | 10 | u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK; |
11 | struct net_device *vlan_dev; | 11 | struct net_device *vlan_dev; |
12 | struct vlan_rx_stats *rx_stats; | 12 | struct vlan_pcpu_stats *rx_stats; |
13 | 13 | ||
14 | vlan_dev = vlan_find_dev(skb->dev, vlan_id); | 14 | vlan_dev = vlan_find_dev(skb->dev, vlan_id); |
15 | if (!vlan_dev) { | 15 | if (!vlan_dev) { |
@@ -26,7 +26,7 @@ bool vlan_hwaccel_do_receive(struct sk_buff **skbp) | |||
26 | skb->priority = vlan_get_ingress_priority(vlan_dev, skb->vlan_tci); | 26 | skb->priority = vlan_get_ingress_priority(vlan_dev, skb->vlan_tci); |
27 | skb->vlan_tci = 0; | 27 | skb->vlan_tci = 0; |
28 | 28 | ||
29 | rx_stats = this_cpu_ptr(vlan_dev_info(vlan_dev)->vlan_rx_stats); | 29 | rx_stats = this_cpu_ptr(vlan_dev_info(vlan_dev)->vlan_pcpu_stats); |
30 | 30 | ||
31 | u64_stats_update_begin(&rx_stats->syncp); | 31 | u64_stats_update_begin(&rx_stats->syncp); |
32 | rx_stats->rx_packets++; | 32 | rx_stats->rx_packets++; |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 14e3d1fa07a0..be737539f34d 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -141,7 +141,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
141 | struct packet_type *ptype, struct net_device *orig_dev) | 141 | struct packet_type *ptype, struct net_device *orig_dev) |
142 | { | 142 | { |
143 | struct vlan_hdr *vhdr; | 143 | struct vlan_hdr *vhdr; |
144 | struct vlan_rx_stats *rx_stats; | 144 | struct vlan_pcpu_stats *rx_stats; |
145 | struct net_device *vlan_dev; | 145 | struct net_device *vlan_dev; |
146 | u16 vlan_id; | 146 | u16 vlan_id; |
147 | u16 vlan_tci; | 147 | u16 vlan_tci; |
@@ -177,7 +177,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
177 | } else { | 177 | } else { |
178 | skb->dev = vlan_dev; | 178 | skb->dev = vlan_dev; |
179 | 179 | ||
180 | rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_rx_stats); | 180 | rx_stats = this_cpu_ptr(vlan_dev_info(skb->dev)->vlan_pcpu_stats); |
181 | 181 | ||
182 | u64_stats_update_begin(&rx_stats->syncp); | 182 | u64_stats_update_begin(&rx_stats->syncp); |
183 | rx_stats->rx_packets++; | 183 | rx_stats->rx_packets++; |
@@ -274,9 +274,6 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
274 | u16 vlan_tci = 0; | 274 | u16 vlan_tci = 0; |
275 | int rc; | 275 | int rc; |
276 | 276 | ||
277 | if (WARN_ON(skb_headroom(skb) < dev->hard_header_len)) | ||
278 | return -ENOSPC; | ||
279 | |||
280 | if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) { | 277 | if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) { |
281 | vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); | 278 | vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN); |
282 | 279 | ||
@@ -313,8 +310,6 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
313 | static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, | 310 | static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, |
314 | struct net_device *dev) | 311 | struct net_device *dev) |
315 | { | 312 | { |
316 | int i = skb_get_queue_mapping(skb); | ||
317 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | ||
318 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); | 313 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); |
319 | unsigned int len; | 314 | unsigned int len; |
320 | int ret; | 315 | int ret; |
@@ -326,71 +321,31 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, | |||
326 | */ | 321 | */ |
327 | if (veth->h_vlan_proto != htons(ETH_P_8021Q) || | 322 | if (veth->h_vlan_proto != htons(ETH_P_8021Q) || |
328 | vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) { | 323 | vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) { |
329 | unsigned int orig_headroom = skb_headroom(skb); | ||
330 | u16 vlan_tci; | 324 | u16 vlan_tci; |
331 | |||
332 | vlan_dev_info(dev)->cnt_encap_on_xmit++; | ||
333 | |||
334 | vlan_tci = vlan_dev_info(dev)->vlan_id; | 325 | vlan_tci = vlan_dev_info(dev)->vlan_id; |
335 | vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); | 326 | vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); |
336 | skb = __vlan_put_tag(skb, vlan_tci); | 327 | skb = __vlan_hwaccel_put_tag(skb, vlan_tci); |
337 | if (!skb) { | ||
338 | txq->tx_dropped++; | ||
339 | return NETDEV_TX_OK; | ||
340 | } | ||
341 | |||
342 | if (orig_headroom < VLAN_HLEN) | ||
343 | vlan_dev_info(dev)->cnt_inc_headroom_on_tx++; | ||
344 | } | 328 | } |
345 | 329 | ||
346 | |||
347 | skb_set_dev(skb, vlan_dev_info(dev)->real_dev); | 330 | skb_set_dev(skb, vlan_dev_info(dev)->real_dev); |
348 | len = skb->len; | 331 | len = skb->len; |
349 | ret = dev_queue_xmit(skb); | 332 | ret = dev_queue_xmit(skb); |
350 | 333 | ||
351 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { | 334 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { |
352 | txq->tx_packets++; | 335 | struct vlan_pcpu_stats *stats; |
353 | txq->tx_bytes += len; | ||
354 | } else | ||
355 | txq->tx_dropped++; | ||
356 | 336 | ||
357 | return ret; | 337 | stats = this_cpu_ptr(vlan_dev_info(dev)->vlan_pcpu_stats); |
358 | } | 338 | u64_stats_update_begin(&stats->syncp); |
359 | 339 | stats->tx_packets++; | |
360 | static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, | 340 | stats->tx_bytes += len; |
361 | struct net_device *dev) | 341 | u64_stats_update_begin(&stats->syncp); |
362 | { | 342 | } else { |
363 | int i = skb_get_queue_mapping(skb); | 343 | this_cpu_inc(vlan_dev_info(dev)->vlan_pcpu_stats->tx_dropped); |
364 | struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | 344 | } |
365 | u16 vlan_tci; | ||
366 | unsigned int len; | ||
367 | int ret; | ||
368 | |||
369 | vlan_tci = vlan_dev_info(dev)->vlan_id; | ||
370 | vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb); | ||
371 | skb = __vlan_hwaccel_put_tag(skb, vlan_tci); | ||
372 | |||
373 | skb->dev = vlan_dev_info(dev)->real_dev; | ||
374 | len = skb->len; | ||
375 | ret = dev_queue_xmit(skb); | ||
376 | |||
377 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { | ||
378 | txq->tx_packets++; | ||
379 | txq->tx_bytes += len; | ||
380 | } else | ||
381 | txq->tx_dropped++; | ||
382 | 345 | ||
383 | return ret; | 346 | return ret; |
384 | } | 347 | } |
385 | 348 | ||
386 | static u16 vlan_dev_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
387 | { | ||
388 | struct net_device *rdev = vlan_dev_info(dev)->real_dev; | ||
389 | const struct net_device_ops *ops = rdev->netdev_ops; | ||
390 | |||
391 | return ops->ndo_select_queue(rdev, skb); | ||
392 | } | ||
393 | |||
394 | static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) | 349 | static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) |
395 | { | 350 | { |
396 | /* TODO: gotta make sure the underlying layer can handle it, | 351 | /* TODO: gotta make sure the underlying layer can handle it, |
@@ -719,8 +674,7 @@ static const struct header_ops vlan_header_ops = { | |||
719 | .parse = eth_header_parse, | 674 | .parse = eth_header_parse, |
720 | }; | 675 | }; |
721 | 676 | ||
722 | static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops, | 677 | static const struct net_device_ops vlan_netdev_ops; |
723 | vlan_netdev_ops_sq, vlan_netdev_accel_ops_sq; | ||
724 | 678 | ||
725 | static int vlan_dev_init(struct net_device *dev) | 679 | static int vlan_dev_init(struct net_device *dev) |
726 | { | 680 | { |
@@ -738,6 +692,7 @@ static int vlan_dev_init(struct net_device *dev) | |||
738 | (1<<__LINK_STATE_PRESENT); | 692 | (1<<__LINK_STATE_PRESENT); |
739 | 693 | ||
740 | dev->features |= real_dev->features & real_dev->vlan_features; | 694 | dev->features |= real_dev->features & real_dev->vlan_features; |
695 | dev->features |= NETIF_F_LLTX; | ||
741 | dev->gso_max_size = real_dev->gso_max_size; | 696 | dev->gso_max_size = real_dev->gso_max_size; |
742 | 697 | ||
743 | /* ipv6 shared card related stuff */ | 698 | /* ipv6 shared card related stuff */ |
@@ -755,26 +710,20 @@ static int vlan_dev_init(struct net_device *dev) | |||
755 | if (real_dev->features & NETIF_F_HW_VLAN_TX) { | 710 | if (real_dev->features & NETIF_F_HW_VLAN_TX) { |
756 | dev->header_ops = real_dev->header_ops; | 711 | dev->header_ops = real_dev->header_ops; |
757 | dev->hard_header_len = real_dev->hard_header_len; | 712 | dev->hard_header_len = real_dev->hard_header_len; |
758 | if (real_dev->netdev_ops->ndo_select_queue) | ||
759 | dev->netdev_ops = &vlan_netdev_accel_ops_sq; | ||
760 | else | ||
761 | dev->netdev_ops = &vlan_netdev_accel_ops; | ||
762 | } else { | 713 | } else { |
763 | dev->header_ops = &vlan_header_ops; | 714 | dev->header_ops = &vlan_header_ops; |
764 | dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; | 715 | dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; |
765 | if (real_dev->netdev_ops->ndo_select_queue) | ||
766 | dev->netdev_ops = &vlan_netdev_ops_sq; | ||
767 | else | ||
768 | dev->netdev_ops = &vlan_netdev_ops; | ||
769 | } | 716 | } |
770 | 717 | ||
718 | dev->netdev_ops = &vlan_netdev_ops; | ||
719 | |||
771 | if (is_vlan_dev(real_dev)) | 720 | if (is_vlan_dev(real_dev)) |
772 | subclass = 1; | 721 | subclass = 1; |
773 | 722 | ||
774 | vlan_dev_set_lockdep_class(dev, subclass); | 723 | vlan_dev_set_lockdep_class(dev, subclass); |
775 | 724 | ||
776 | vlan_dev_info(dev)->vlan_rx_stats = alloc_percpu(struct vlan_rx_stats); | 725 | vlan_dev_info(dev)->vlan_pcpu_stats = alloc_percpu(struct vlan_pcpu_stats); |
777 | if (!vlan_dev_info(dev)->vlan_rx_stats) | 726 | if (!vlan_dev_info(dev)->vlan_pcpu_stats) |
778 | return -ENOMEM; | 727 | return -ENOMEM; |
779 | 728 | ||
780 | return 0; | 729 | return 0; |
@@ -786,8 +735,8 @@ static void vlan_dev_uninit(struct net_device *dev) | |||
786 | struct vlan_dev_info *vlan = vlan_dev_info(dev); | 735 | struct vlan_dev_info *vlan = vlan_dev_info(dev); |
787 | int i; | 736 | int i; |
788 | 737 | ||
789 | free_percpu(vlan->vlan_rx_stats); | 738 | free_percpu(vlan->vlan_pcpu_stats); |
790 | vlan->vlan_rx_stats = NULL; | 739 | vlan->vlan_pcpu_stats = NULL; |
791 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { | 740 | for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) { |
792 | while ((pm = vlan->egress_priority_map[i]) != NULL) { | 741 | while ((pm = vlan->egress_priority_map[i]) != NULL) { |
793 | vlan->egress_priority_map[i] = pm->next; | 742 | vlan->egress_priority_map[i] = pm->next; |
@@ -825,33 +774,37 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev) | |||
825 | 774 | ||
826 | static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) | 775 | static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) |
827 | { | 776 | { |
828 | dev_txq_stats_fold(dev, stats); | ||
829 | 777 | ||
830 | if (vlan_dev_info(dev)->vlan_rx_stats) { | 778 | if (vlan_dev_info(dev)->vlan_pcpu_stats) { |
831 | struct vlan_rx_stats *p, accum = {0}; | 779 | struct vlan_pcpu_stats *p; |
780 | u32 rx_errors = 0, tx_dropped = 0; | ||
832 | int i; | 781 | int i; |
833 | 782 | ||
834 | for_each_possible_cpu(i) { | 783 | for_each_possible_cpu(i) { |
835 | u64 rxpackets, rxbytes, rxmulticast; | 784 | u64 rxpackets, rxbytes, rxmulticast, txpackets, txbytes; |
836 | unsigned int start; | 785 | unsigned int start; |
837 | 786 | ||
838 | p = per_cpu_ptr(vlan_dev_info(dev)->vlan_rx_stats, i); | 787 | p = per_cpu_ptr(vlan_dev_info(dev)->vlan_pcpu_stats, i); |
839 | do { | 788 | do { |
840 | start = u64_stats_fetch_begin_bh(&p->syncp); | 789 | start = u64_stats_fetch_begin_bh(&p->syncp); |
841 | rxpackets = p->rx_packets; | 790 | rxpackets = p->rx_packets; |
842 | rxbytes = p->rx_bytes; | 791 | rxbytes = p->rx_bytes; |
843 | rxmulticast = p->rx_multicast; | 792 | rxmulticast = p->rx_multicast; |
793 | txpackets = p->tx_packets; | ||
794 | txbytes = p->tx_bytes; | ||
844 | } while (u64_stats_fetch_retry_bh(&p->syncp, start)); | 795 | } while (u64_stats_fetch_retry_bh(&p->syncp, start)); |
845 | accum.rx_packets += rxpackets; | 796 | |
846 | accum.rx_bytes += rxbytes; | 797 | stats->rx_packets += rxpackets; |
847 | accum.rx_multicast += rxmulticast; | 798 | stats->rx_bytes += rxbytes; |
848 | /* rx_errors is ulong, not protected by syncp */ | 799 | stats->multicast += rxmulticast; |
849 | accum.rx_errors += p->rx_errors; | 800 | stats->tx_packets += txpackets; |
801 | stats->tx_bytes += txbytes; | ||
802 | /* rx_errors & tx_dropped are u32 */ | ||
803 | rx_errors += p->rx_errors; | ||
804 | tx_dropped += p->tx_dropped; | ||
850 | } | 805 | } |
851 | stats->rx_packets = accum.rx_packets; | 806 | stats->rx_errors = rx_errors; |
852 | stats->rx_bytes = accum.rx_bytes; | 807 | stats->tx_dropped = tx_dropped; |
853 | stats->rx_errors = accum.rx_errors; | ||
854 | stats->multicast = accum.rx_multicast; | ||
855 | } | 808 | } |
856 | return stats; | 809 | return stats; |
857 | } | 810 | } |
@@ -908,80 +861,6 @@ static const struct net_device_ops vlan_netdev_ops = { | |||
908 | #endif | 861 | #endif |
909 | }; | 862 | }; |
910 | 863 | ||
911 | static const struct net_device_ops vlan_netdev_accel_ops = { | ||
912 | .ndo_change_mtu = vlan_dev_change_mtu, | ||
913 | .ndo_init = vlan_dev_init, | ||
914 | .ndo_uninit = vlan_dev_uninit, | ||
915 | .ndo_open = vlan_dev_open, | ||
916 | .ndo_stop = vlan_dev_stop, | ||
917 | .ndo_start_xmit = vlan_dev_hwaccel_hard_start_xmit, | ||
918 | .ndo_validate_addr = eth_validate_addr, | ||
919 | .ndo_set_mac_address = vlan_dev_set_mac_address, | ||
920 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, | ||
921 | .ndo_set_multicast_list = vlan_dev_set_rx_mode, | ||
922 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | ||
923 | .ndo_do_ioctl = vlan_dev_ioctl, | ||
924 | .ndo_neigh_setup = vlan_dev_neigh_setup, | ||
925 | .ndo_get_stats64 = vlan_dev_get_stats64, | ||
926 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | ||
927 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | ||
928 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | ||
929 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | ||
930 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | ||
931 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
932 | #endif | ||
933 | }; | ||
934 | |||
935 | static const struct net_device_ops vlan_netdev_ops_sq = { | ||
936 | .ndo_select_queue = vlan_dev_select_queue, | ||
937 | .ndo_change_mtu = vlan_dev_change_mtu, | ||
938 | .ndo_init = vlan_dev_init, | ||
939 | .ndo_uninit = vlan_dev_uninit, | ||
940 | .ndo_open = vlan_dev_open, | ||
941 | .ndo_stop = vlan_dev_stop, | ||
942 | .ndo_start_xmit = vlan_dev_hard_start_xmit, | ||
943 | .ndo_validate_addr = eth_validate_addr, | ||
944 | .ndo_set_mac_address = vlan_dev_set_mac_address, | ||
945 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, | ||
946 | .ndo_set_multicast_list = vlan_dev_set_rx_mode, | ||
947 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | ||
948 | .ndo_do_ioctl = vlan_dev_ioctl, | ||
949 | .ndo_neigh_setup = vlan_dev_neigh_setup, | ||
950 | .ndo_get_stats64 = vlan_dev_get_stats64, | ||
951 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | ||
952 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | ||
953 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | ||
954 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | ||
955 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | ||
956 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
957 | #endif | ||
958 | }; | ||
959 | |||
960 | static const struct net_device_ops vlan_netdev_accel_ops_sq = { | ||
961 | .ndo_select_queue = vlan_dev_select_queue, | ||
962 | .ndo_change_mtu = vlan_dev_change_mtu, | ||
963 | .ndo_init = vlan_dev_init, | ||
964 | .ndo_uninit = vlan_dev_uninit, | ||
965 | .ndo_open = vlan_dev_open, | ||
966 | .ndo_stop = vlan_dev_stop, | ||
967 | .ndo_start_xmit = vlan_dev_hwaccel_hard_start_xmit, | ||
968 | .ndo_validate_addr = eth_validate_addr, | ||
969 | .ndo_set_mac_address = vlan_dev_set_mac_address, | ||
970 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, | ||
971 | .ndo_set_multicast_list = vlan_dev_set_rx_mode, | ||
972 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | ||
973 | .ndo_do_ioctl = vlan_dev_ioctl, | ||
974 | .ndo_neigh_setup = vlan_dev_neigh_setup, | ||
975 | .ndo_get_stats64 = vlan_dev_get_stats64, | ||
976 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | ||
977 | .ndo_fcoe_ddp_setup = vlan_dev_fcoe_ddp_setup, | ||
978 | .ndo_fcoe_ddp_done = vlan_dev_fcoe_ddp_done, | ||
979 | .ndo_fcoe_enable = vlan_dev_fcoe_enable, | ||
980 | .ndo_fcoe_disable = vlan_dev_fcoe_disable, | ||
981 | .ndo_fcoe_get_wwn = vlan_dev_fcoe_get_wwn, | ||
982 | #endif | ||
983 | }; | ||
984 | |||
985 | void vlan_setup(struct net_device *dev) | 864 | void vlan_setup(struct net_device *dev) |
986 | { | 865 | { |
987 | ether_setup(dev); | 866 | ether_setup(dev); |
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index ddc105734af7..be9a5c19a775 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c | |||
@@ -101,25 +101,6 @@ static int vlan_changelink(struct net_device *dev, | |||
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
104 | static int vlan_get_tx_queues(struct net *net, | ||
105 | struct nlattr *tb[], | ||
106 | unsigned int *num_tx_queues, | ||
107 | unsigned int *real_num_tx_queues) | ||
108 | { | ||
109 | struct net_device *real_dev; | ||
110 | |||
111 | if (!tb[IFLA_LINK]) | ||
112 | return -EINVAL; | ||
113 | |||
114 | real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK])); | ||
115 | if (!real_dev) | ||
116 | return -ENODEV; | ||
117 | |||
118 | *num_tx_queues = real_dev->num_tx_queues; | ||
119 | *real_num_tx_queues = real_dev->real_num_tx_queues; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int vlan_newlink(struct net *src_net, struct net_device *dev, | 104 | static int vlan_newlink(struct net *src_net, struct net_device *dev, |
124 | struct nlattr *tb[], struct nlattr *data[]) | 105 | struct nlattr *tb[], struct nlattr *data[]) |
125 | { | 106 | { |
@@ -237,7 +218,6 @@ struct rtnl_link_ops vlan_link_ops __read_mostly = { | |||
237 | .maxtype = IFLA_VLAN_MAX, | 218 | .maxtype = IFLA_VLAN_MAX, |
238 | .policy = vlan_policy, | 219 | .policy = vlan_policy, |
239 | .priv_size = sizeof(struct vlan_dev_info), | 220 | .priv_size = sizeof(struct vlan_dev_info), |
240 | .get_tx_queues = vlan_get_tx_queues, | ||
241 | .setup = vlan_setup, | 221 | .setup = vlan_setup, |
242 | .validate = vlan_validate, | 222 | .validate = vlan_validate, |
243 | .newlink = vlan_newlink, | 223 | .newlink = vlan_newlink, |
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 80e280f56686..d1314cf18adf 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c | |||
@@ -280,7 +280,6 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset) | |||
280 | const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); | 280 | const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); |
281 | struct rtnl_link_stats64 temp; | 281 | struct rtnl_link_stats64 temp; |
282 | const struct rtnl_link_stats64 *stats; | 282 | const struct rtnl_link_stats64 *stats; |
283 | static const char fmt[] = "%30s %12lu\n"; | ||
284 | static const char fmt64[] = "%30s %12llu\n"; | 283 | static const char fmt64[] = "%30s %12llu\n"; |
285 | int i; | 284 | int i; |
286 | 285 | ||
@@ -299,10 +298,6 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset) | |||
299 | seq_puts(seq, "\n"); | 298 | seq_puts(seq, "\n"); |
300 | seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets); | 299 | seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets); |
301 | seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes); | 300 | seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes); |
302 | seq_printf(seq, fmt, "total headroom inc", | ||
303 | dev_info->cnt_inc_headroom_on_tx); | ||
304 | seq_printf(seq, fmt, "total encap on xmit", | ||
305 | dev_info->cnt_encap_on_xmit); | ||
306 | seq_printf(seq, "Device: %s", dev_info->real_dev->name); | 301 | seq_printf(seq, "Device: %s", dev_info->real_dev->name); |
307 | /* now show all PRIORITY mappings relating to this VLAN */ | 302 | /* now show all PRIORITY mappings relating to this VLAN */ |
308 | seq_printf(seq, "\nINGRESS priority mappings: " | 303 | seq_printf(seq, "\nINGRESS priority mappings: " |
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 45c15f491401..798beac7f100 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -27,31 +27,16 @@ | |||
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/kernel.h> | ||
30 | #include <linux/uaccess.h> | 31 | #include <linux/uaccess.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
32 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/stddef.h> | ||
33 | #include <linux/types.h> | 35 | #include <linux/types.h> |
34 | #include <net/9p/9p.h> | 36 | #include <net/9p/9p.h> |
35 | #include <net/9p/client.h> | 37 | #include <net/9p/client.h> |
36 | #include "protocol.h" | 38 | #include "protocol.h" |
37 | 39 | ||
38 | #ifndef MIN | ||
39 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||
40 | #endif | ||
41 | |||
42 | #ifndef MAX | ||
43 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) | ||
44 | #endif | ||
45 | |||
46 | #ifndef offset_of | ||
47 | #define offset_of(type, memb) \ | ||
48 | ((unsigned long)(&((type *)0)->memb)) | ||
49 | #endif | ||
50 | #ifndef container_of | ||
51 | #define container_of(obj, type, memb) \ | ||
52 | ((type *)(((char *)obj) - offset_of(type, memb))) | ||
53 | #endif | ||
54 | |||
55 | static int | 40 | static int |
56 | p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); | 41 | p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); |
57 | 42 | ||
@@ -104,7 +89,7 @@ EXPORT_SYMBOL(p9stat_free); | |||
104 | 89 | ||
105 | static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) | 90 | static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) |
106 | { | 91 | { |
107 | size_t len = MIN(pdu->size - pdu->offset, size); | 92 | size_t len = min(pdu->size - pdu->offset, size); |
108 | memcpy(data, &pdu->sdata[pdu->offset], len); | 93 | memcpy(data, &pdu->sdata[pdu->offset], len); |
109 | pdu->offset += len; | 94 | pdu->offset += len; |
110 | return size - len; | 95 | return size - len; |
@@ -112,7 +97,7 @@ static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) | |||
112 | 97 | ||
113 | static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) | 98 | static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) |
114 | { | 99 | { |
115 | size_t len = MIN(pdu->capacity - pdu->size, size); | 100 | size_t len = min(pdu->capacity - pdu->size, size); |
116 | memcpy(&pdu->sdata[pdu->size], data, len); | 101 | memcpy(&pdu->sdata[pdu->size], data, len); |
117 | pdu->size += len; | 102 | pdu->size += len; |
118 | return size - len; | 103 | return size - len; |
@@ -121,7 +106,7 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) | |||
121 | static size_t | 106 | static size_t |
122 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | 107 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) |
123 | { | 108 | { |
124 | size_t len = MIN(pdu->capacity - pdu->size, size); | 109 | size_t len = min(pdu->capacity - pdu->size, size); |
125 | if (copy_from_user(&pdu->sdata[pdu->size], udata, len)) | 110 | if (copy_from_user(&pdu->sdata[pdu->size], udata, len)) |
126 | len = 0; | 111 | len = 0; |
127 | 112 | ||
@@ -201,7 +186,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
201 | if (errcode) | 186 | if (errcode) |
202 | break; | 187 | break; |
203 | 188 | ||
204 | size = MAX(len, 0); | 189 | size = max_t(int16_t, len, 0); |
205 | 190 | ||
206 | *sptr = kmalloc(size + 1, GFP_KERNEL); | 191 | *sptr = kmalloc(size + 1, GFP_KERNEL); |
207 | if (*sptr == NULL) { | 192 | if (*sptr == NULL) { |
@@ -256,8 +241,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
256 | p9pdu_readf(pdu, proto_version, "d", count); | 241 | p9pdu_readf(pdu, proto_version, "d", count); |
257 | if (!errcode) { | 242 | if (!errcode) { |
258 | *count = | 243 | *count = |
259 | MIN(*count, | 244 | min_t(int32_t, *count, |
260 | pdu->size - pdu->offset); | 245 | pdu->size - pdu->offset); |
261 | *data = &pdu->sdata[pdu->offset]; | 246 | *data = &pdu->sdata[pdu->offset]; |
262 | } | 247 | } |
263 | } | 248 | } |
@@ -421,7 +406,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
421 | const char *sptr = va_arg(ap, const char *); | 406 | const char *sptr = va_arg(ap, const char *); |
422 | int16_t len = 0; | 407 | int16_t len = 0; |
423 | if (sptr) | 408 | if (sptr) |
424 | len = MIN(strlen(sptr), USHRT_MAX); | 409 | len = min_t(int16_t, strlen(sptr), USHRT_MAX); |
425 | 410 | ||
426 | errcode = p9pdu_writef(pdu, proto_version, | 411 | errcode = p9pdu_writef(pdu, proto_version, |
427 | "w", len); | 412 | "w", len); |
diff --git a/net/Kconfig b/net/Kconfig index 55fd82e9ffd9..ad0aafe903f8 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -214,12 +214,18 @@ source "net/ieee802154/Kconfig" | |||
214 | source "net/sched/Kconfig" | 214 | source "net/sched/Kconfig" |
215 | source "net/dcb/Kconfig" | 215 | source "net/dcb/Kconfig" |
216 | source "net/dns_resolver/Kconfig" | 216 | source "net/dns_resolver/Kconfig" |
217 | source "net/batman-adv/Kconfig" | ||
217 | 218 | ||
218 | config RPS | 219 | config RPS |
219 | boolean | 220 | boolean |
220 | depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS | 221 | depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS |
221 | default y | 222 | default y |
222 | 223 | ||
224 | config XPS | ||
225 | boolean | ||
226 | depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS | ||
227 | default y | ||
228 | |||
223 | menu "Network testing" | 229 | menu "Network testing" |
224 | 230 | ||
225 | config NET_PKTGEN | 231 | config NET_PKTGEN |
diff --git a/net/Makefile b/net/Makefile index 6b7bfd7f1416..a3330ebe2c53 100644 --- a/net/Makefile +++ b/net/Makefile | |||
@@ -69,3 +69,4 @@ endif | |||
69 | obj-$(CONFIG_WIMAX) += wimax/ | 69 | obj-$(CONFIG_WIMAX) += wimax/ |
70 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ | 70 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ |
71 | obj-$(CONFIG_CEPH_LIB) += ceph/ | 71 | obj-$(CONFIG_CEPH_LIB) += ceph/ |
72 | obj-$(CONFIG_BATMAN_ADV) += batman-adv/ | ||
diff --git a/net/atm/br2684.c b/net/atm/br2684.c index ad2b232a2055..fce2eae8d476 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c | |||
@@ -97,7 +97,7 @@ static LIST_HEAD(br2684_devs); | |||
97 | 97 | ||
98 | static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) | 98 | static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) |
99 | { | 99 | { |
100 | return (struct br2684_dev *)netdev_priv(net_dev); | 100 | return netdev_priv(net_dev); |
101 | } | 101 | } |
102 | 102 | ||
103 | static inline struct net_device *list_entry_brdev(const struct list_head *le) | 103 | static inline struct net_device *list_entry_brdev(const struct list_head *le) |
diff --git a/net/atm/clip.c b/net/atm/clip.c index ff956d1115bc..d257da50fcfb 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c | |||
@@ -502,7 +502,8 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) | |||
502 | struct atmarp_entry *entry; | 502 | struct atmarp_entry *entry; |
503 | int error; | 503 | int error; |
504 | struct clip_vcc *clip_vcc; | 504 | struct clip_vcc *clip_vcc; |
505 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1}} }; | 505 | struct flowi fl = { .fl4_dst = ip, |
506 | .fl4_tos = 1 }; | ||
506 | struct rtable *rt; | 507 | struct rtable *rt; |
507 | 508 | ||
508 | if (vcc->push != clip_push) { | 509 | if (vcc->push != clip_push) { |
diff --git a/net/atm/lec.c b/net/atm/lec.c index 181d70c73d70..179e04bc99dd 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c | |||
@@ -816,8 +816,7 @@ static int lec_mcast_attach(struct atm_vcc *vcc, int arg) | |||
816 | if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) | 816 | if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) |
817 | return -EINVAL; | 817 | return -EINVAL; |
818 | vcc->proto_data = dev_lec[arg]; | 818 | vcc->proto_data = dev_lec[arg]; |
819 | return lec_mcast_make((struct lec_priv *)netdev_priv(dev_lec[arg]), | 819 | return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc); |
820 | vcc); | ||
821 | } | 820 | } |
822 | 821 | ||
823 | /* Initialize device. */ | 822 | /* Initialize device. */ |
diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 74bcc662c3dd..644cdf071642 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c | |||
@@ -64,8 +64,6 @@ | |||
64 | do { if (0) printk(KERN_CONT format, ##args); } while (0) | 64 | do { if (0) printk(KERN_CONT format, ##args); } while (0) |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | #define MPOA_TAG_LEN 4 | ||
68 | |||
69 | /* mpc_daemon -> kernel */ | 67 | /* mpc_daemon -> kernel */ |
70 | static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc); | 68 | static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc); |
71 | static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); | 69 | static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); |
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig new file mode 100644 index 000000000000..6c051ad833eb --- /dev/null +++ b/net/batman-adv/Kconfig | |||
@@ -0,0 +1,25 @@ | |||
1 | # | ||
2 | # B.A.T.M.A.N meshing protocol | ||
3 | # | ||
4 | |||
5 | config BATMAN_ADV | ||
6 | tristate "B.A.T.M.A.N. Advanced Meshing Protocol" | ||
7 | depends on NET | ||
8 | default n | ||
9 | ---help--- | ||
10 | |||
11 | B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is | ||
12 | a routing protocol for multi-hop ad-hoc mesh networks. The | ||
13 | networks may be wired or wireless. See | ||
14 | http://www.open-mesh.org/ for more information and user space | ||
15 | tools. | ||
16 | |||
17 | config BATMAN_ADV_DEBUG | ||
18 | bool "B.A.T.M.A.N. debugging" | ||
19 | depends on BATMAN_ADV != n | ||
20 | ---help--- | ||
21 | |||
22 | This is an option for use by developers; most people should | ||
23 | say N here. This enables compilation of support for | ||
24 | outputting debugging information to the kernel log. The | ||
25 | output is controlled via the module parameter debug. | ||
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile new file mode 100644 index 000000000000..d936aeccd194 --- /dev/null +++ b/net/batman-adv/Makefile | |||
@@ -0,0 +1,39 @@ | |||
1 | # | ||
2 | # Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | # | ||
4 | # Marek Lindner, Simon Wunderlich | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or | ||
7 | # modify it under the terms of version 2 of the GNU General Public | ||
8 | # License as published by the Free Software Foundation. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | # 02110-1301, USA | ||
19 | # | ||
20 | |||
21 | obj-$(CONFIG_BATMAN_ADV) += batman-adv.o | ||
22 | batman-adv-y += aggregation.o | ||
23 | batman-adv-y += bat_debugfs.o | ||
24 | batman-adv-y += bat_sysfs.o | ||
25 | batman-adv-y += bitarray.o | ||
26 | batman-adv-y += gateway_client.o | ||
27 | batman-adv-y += gateway_common.o | ||
28 | batman-adv-y += hard-interface.o | ||
29 | batman-adv-y += hash.o | ||
30 | batman-adv-y += icmp_socket.o | ||
31 | batman-adv-y += main.o | ||
32 | batman-adv-y += originator.o | ||
33 | batman-adv-y += ring_buffer.o | ||
34 | batman-adv-y += routing.o | ||
35 | batman-adv-y += send.o | ||
36 | batman-adv-y += soft-interface.o | ||
37 | batman-adv-y += translation-table.o | ||
38 | batman-adv-y += unicast.o | ||
39 | batman-adv-y += vis.o | ||
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c new file mode 100644 index 000000000000..3850a3ecf947 --- /dev/null +++ b/net/batman-adv/aggregation.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "aggregation.h" | ||
24 | #include "send.h" | ||
25 | #include "routing.h" | ||
26 | |||
27 | /* calculate the size of the hna information for a given packet */ | ||
28 | static int hna_len(struct batman_packet *batman_packet) | ||
29 | { | ||
30 | return batman_packet->num_hna * ETH_ALEN; | ||
31 | } | ||
32 | |||
33 | /* return true if new_packet can be aggregated with forw_packet */ | ||
34 | static bool can_aggregate_with(struct batman_packet *new_batman_packet, | ||
35 | int packet_len, | ||
36 | unsigned long send_time, | ||
37 | bool directlink, | ||
38 | struct batman_if *if_incoming, | ||
39 | struct forw_packet *forw_packet) | ||
40 | { | ||
41 | struct batman_packet *batman_packet = | ||
42 | (struct batman_packet *)forw_packet->skb->data; | ||
43 | int aggregated_bytes = forw_packet->packet_len + packet_len; | ||
44 | |||
45 | /** | ||
46 | * we can aggregate the current packet to this aggregated packet | ||
47 | * if: | ||
48 | * | ||
49 | * - the send time is within our MAX_AGGREGATION_MS time | ||
50 | * - the resulting packet wont be bigger than | ||
51 | * MAX_AGGREGATION_BYTES | ||
52 | */ | ||
53 | |||
54 | if (time_before(send_time, forw_packet->send_time) && | ||
55 | time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS), | ||
56 | forw_packet->send_time) && | ||
57 | (aggregated_bytes <= MAX_AGGREGATION_BYTES)) { | ||
58 | |||
59 | /** | ||
60 | * check aggregation compatibility | ||
61 | * -> direct link packets are broadcasted on | ||
62 | * their interface only | ||
63 | * -> aggregate packet if the current packet is | ||
64 | * a "global" packet as well as the base | ||
65 | * packet | ||
66 | */ | ||
67 | |||
68 | /* packets without direct link flag and high TTL | ||
69 | * are flooded through the net */ | ||
70 | if ((!directlink) && | ||
71 | (!(batman_packet->flags & DIRECTLINK)) && | ||
72 | (batman_packet->ttl != 1) && | ||
73 | |||
74 | /* own packets originating non-primary | ||
75 | * interfaces leave only that interface */ | ||
76 | ((!forw_packet->own) || | ||
77 | (forw_packet->if_incoming->if_num == 0))) | ||
78 | return true; | ||
79 | |||
80 | /* if the incoming packet is sent via this one | ||
81 | * interface only - we still can aggregate */ | ||
82 | if ((directlink) && | ||
83 | (new_batman_packet->ttl == 1) && | ||
84 | (forw_packet->if_incoming == if_incoming) && | ||
85 | |||
86 | /* packets from direct neighbors or | ||
87 | * own secondary interface packets | ||
88 | * (= secondary interface packets in general) */ | ||
89 | (batman_packet->flags & DIRECTLINK || | ||
90 | (forw_packet->own && | ||
91 | forw_packet->if_incoming->if_num != 0))) | ||
92 | return true; | ||
93 | } | ||
94 | |||
95 | return false; | ||
96 | } | ||
97 | |||
98 | #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) | ||
99 | /* create a new aggregated packet and add this packet to it */ | ||
100 | static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, | ||
101 | unsigned long send_time, bool direct_link, | ||
102 | struct batman_if *if_incoming, | ||
103 | int own_packet) | ||
104 | { | ||
105 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
106 | struct forw_packet *forw_packet_aggr; | ||
107 | unsigned char *skb_buff; | ||
108 | |||
109 | /* own packet should always be scheduled */ | ||
110 | if (!own_packet) { | ||
111 | if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) { | ||
112 | bat_dbg(DBG_BATMAN, bat_priv, | ||
113 | "batman packet queue full\n"); | ||
114 | return; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | forw_packet_aggr = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | ||
119 | if (!forw_packet_aggr) { | ||
120 | if (!own_packet) | ||
121 | atomic_inc(&bat_priv->batman_queue_left); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | if ((atomic_read(&bat_priv->aggregated_ogms)) && | ||
126 | (packet_len < MAX_AGGREGATION_BYTES)) | ||
127 | forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + | ||
128 | sizeof(struct ethhdr)); | ||
129 | else | ||
130 | forw_packet_aggr->skb = dev_alloc_skb(packet_len + | ||
131 | sizeof(struct ethhdr)); | ||
132 | |||
133 | if (!forw_packet_aggr->skb) { | ||
134 | if (!own_packet) | ||
135 | atomic_inc(&bat_priv->batman_queue_left); | ||
136 | kfree(forw_packet_aggr); | ||
137 | return; | ||
138 | } | ||
139 | skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr)); | ||
140 | |||
141 | INIT_HLIST_NODE(&forw_packet_aggr->list); | ||
142 | |||
143 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
144 | forw_packet_aggr->packet_len = packet_len; | ||
145 | memcpy(skb_buff, packet_buff, packet_len); | ||
146 | |||
147 | forw_packet_aggr->own = own_packet; | ||
148 | forw_packet_aggr->if_incoming = if_incoming; | ||
149 | forw_packet_aggr->num_packets = 0; | ||
150 | forw_packet_aggr->direct_link_flags = 0; | ||
151 | forw_packet_aggr->send_time = send_time; | ||
152 | |||
153 | /* save packet direct link flag status */ | ||
154 | if (direct_link) | ||
155 | forw_packet_aggr->direct_link_flags |= 1; | ||
156 | |||
157 | /* add new packet to packet list */ | ||
158 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
159 | hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); | ||
160 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
161 | |||
162 | /* start timer for this packet */ | ||
163 | INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, | ||
164 | send_outstanding_bat_packet); | ||
165 | queue_delayed_work(bat_event_workqueue, | ||
166 | &forw_packet_aggr->delayed_work, | ||
167 | send_time - jiffies); | ||
168 | } | ||
169 | |||
170 | /* aggregate a new packet into the existing aggregation */ | ||
171 | static void aggregate(struct forw_packet *forw_packet_aggr, | ||
172 | unsigned char *packet_buff, | ||
173 | int packet_len, | ||
174 | bool direct_link) | ||
175 | { | ||
176 | unsigned char *skb_buff; | ||
177 | |||
178 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
179 | memcpy(skb_buff, packet_buff, packet_len); | ||
180 | forw_packet_aggr->packet_len += packet_len; | ||
181 | forw_packet_aggr->num_packets++; | ||
182 | |||
183 | /* save packet direct link flag status */ | ||
184 | if (direct_link) | ||
185 | forw_packet_aggr->direct_link_flags |= | ||
186 | (1 << forw_packet_aggr->num_packets); | ||
187 | } | ||
188 | |||
189 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
190 | unsigned char *packet_buff, int packet_len, | ||
191 | struct batman_if *if_incoming, char own_packet, | ||
192 | unsigned long send_time) | ||
193 | { | ||
194 | /** | ||
195 | * _aggr -> pointer to the packet we want to aggregate with | ||
196 | * _pos -> pointer to the position in the queue | ||
197 | */ | ||
198 | struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; | ||
199 | struct hlist_node *tmp_node; | ||
200 | struct batman_packet *batman_packet = | ||
201 | (struct batman_packet *)packet_buff; | ||
202 | bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; | ||
203 | |||
204 | /* find position for the packet in the forward queue */ | ||
205 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
206 | /* own packets are not to be aggregated */ | ||
207 | if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { | ||
208 | hlist_for_each_entry(forw_packet_pos, tmp_node, | ||
209 | &bat_priv->forw_bat_list, list) { | ||
210 | if (can_aggregate_with(batman_packet, | ||
211 | packet_len, | ||
212 | send_time, | ||
213 | direct_link, | ||
214 | if_incoming, | ||
215 | forw_packet_pos)) { | ||
216 | forw_packet_aggr = forw_packet_pos; | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* nothing to aggregate with - either aggregation disabled or no | ||
223 | * suitable aggregation packet found */ | ||
224 | if (!forw_packet_aggr) { | ||
225 | /* the following section can run without the lock */ | ||
226 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
227 | |||
228 | /** | ||
229 | * if we could not aggregate this packet with one of the others | ||
230 | * we hold it back for a while, so that it might be aggregated | ||
231 | * later on | ||
232 | */ | ||
233 | if ((!own_packet) && | ||
234 | (atomic_read(&bat_priv->aggregated_ogms))) | ||
235 | send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); | ||
236 | |||
237 | new_aggregated_packet(packet_buff, packet_len, | ||
238 | send_time, direct_link, | ||
239 | if_incoming, own_packet); | ||
240 | } else { | ||
241 | aggregate(forw_packet_aggr, | ||
242 | packet_buff, packet_len, | ||
243 | direct_link); | ||
244 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* unpack the aggregated packets and process them one by one */ | ||
249 | void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, | ||
250 | int packet_len, struct batman_if *if_incoming) | ||
251 | { | ||
252 | struct batman_packet *batman_packet; | ||
253 | int buff_pos = 0; | ||
254 | unsigned char *hna_buff; | ||
255 | |||
256 | batman_packet = (struct batman_packet *)packet_buff; | ||
257 | |||
258 | do { | ||
259 | /* network to host order for our 32bit seqno, and the | ||
260 | orig_interval. */ | ||
261 | batman_packet->seqno = ntohl(batman_packet->seqno); | ||
262 | |||
263 | hna_buff = packet_buff + buff_pos + BAT_PACKET_LEN; | ||
264 | receive_bat_packet(ethhdr, batman_packet, | ||
265 | hna_buff, hna_len(batman_packet), | ||
266 | if_incoming); | ||
267 | |||
268 | buff_pos += BAT_PACKET_LEN + hna_len(batman_packet); | ||
269 | batman_packet = (struct batman_packet *) | ||
270 | (packet_buff + buff_pos); | ||
271 | } while (aggregated_packet(buff_pos, packet_len, | ||
272 | batman_packet->num_hna)); | ||
273 | } | ||
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h new file mode 100644 index 000000000000..71a91b3da913 --- /dev/null +++ b/net/batman-adv/aggregation.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_AGGREGATION_H_ | ||
23 | #define _NET_BATMAN_ADV_AGGREGATION_H_ | ||
24 | |||
25 | #include "main.h" | ||
26 | |||
27 | /* is there another aggregated packet here? */ | ||
28 | static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) | ||
29 | { | ||
30 | int next_buff_pos = buff_pos + BAT_PACKET_LEN + (num_hna * ETH_ALEN); | ||
31 | |||
32 | return (next_buff_pos <= packet_len) && | ||
33 | (next_buff_pos <= MAX_AGGREGATION_BYTES); | ||
34 | } | ||
35 | |||
36 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
37 | unsigned char *packet_buff, int packet_len, | ||
38 | struct batman_if *if_incoming, char own_packet, | ||
39 | unsigned long send_time); | ||
40 | void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, | ||
41 | int packet_len, struct batman_if *if_incoming); | ||
42 | |||
43 | #endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */ | ||
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c new file mode 100644 index 000000000000..0ae81d07f102 --- /dev/null +++ b/net/batman-adv/bat_debugfs.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | |||
24 | #include <linux/debugfs.h> | ||
25 | |||
26 | #include "bat_debugfs.h" | ||
27 | #include "translation-table.h" | ||
28 | #include "originator.h" | ||
29 | #include "hard-interface.h" | ||
30 | #include "gateway_common.h" | ||
31 | #include "gateway_client.h" | ||
32 | #include "soft-interface.h" | ||
33 | #include "vis.h" | ||
34 | #include "icmp_socket.h" | ||
35 | |||
36 | static struct dentry *bat_debugfs; | ||
37 | |||
38 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
39 | #define LOG_BUFF_MASK (log_buff_len-1) | ||
40 | #define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) | ||
41 | |||
42 | static int log_buff_len = LOG_BUF_LEN; | ||
43 | |||
44 | static void emit_log_char(struct debug_log *debug_log, char c) | ||
45 | { | ||
46 | LOG_BUFF(debug_log->log_end) = c; | ||
47 | debug_log->log_end++; | ||
48 | |||
49 | if (debug_log->log_end - debug_log->log_start > log_buff_len) | ||
50 | debug_log->log_start = debug_log->log_end - log_buff_len; | ||
51 | } | ||
52 | |||
53 | static int fdebug_log(struct debug_log *debug_log, char *fmt, ...) | ||
54 | { | ||
55 | int printed_len; | ||
56 | va_list args; | ||
57 | static char debug_log_buf[256]; | ||
58 | char *p; | ||
59 | |||
60 | if (!debug_log) | ||
61 | return 0; | ||
62 | |||
63 | spin_lock_bh(&debug_log->lock); | ||
64 | va_start(args, fmt); | ||
65 | printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf), | ||
66 | fmt, args); | ||
67 | va_end(args); | ||
68 | |||
69 | for (p = debug_log_buf; *p != 0; p++) | ||
70 | emit_log_char(debug_log, *p); | ||
71 | |||
72 | spin_unlock_bh(&debug_log->lock); | ||
73 | |||
74 | wake_up(&debug_log->queue_wait); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | int debug_log(struct bat_priv *bat_priv, char *fmt, ...) | ||
80 | { | ||
81 | va_list args; | ||
82 | char tmp_log_buf[256]; | ||
83 | |||
84 | va_start(args, fmt); | ||
85 | vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); | ||
86 | fdebug_log(bat_priv->debug_log, "[%10u] %s", | ||
87 | (jiffies / HZ), tmp_log_buf); | ||
88 | va_end(args); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int log_open(struct inode *inode, struct file *file) | ||
94 | { | ||
95 | nonseekable_open(inode, file); | ||
96 | file->private_data = inode->i_private; | ||
97 | inc_module_count(); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int log_release(struct inode *inode, struct file *file) | ||
102 | { | ||
103 | dec_module_count(); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static ssize_t log_read(struct file *file, char __user *buf, | ||
108 | size_t count, loff_t *ppos) | ||
109 | { | ||
110 | struct bat_priv *bat_priv = file->private_data; | ||
111 | struct debug_log *debug_log = bat_priv->debug_log; | ||
112 | int error, i = 0; | ||
113 | char c; | ||
114 | |||
115 | if ((file->f_flags & O_NONBLOCK) && | ||
116 | !(debug_log->log_end - debug_log->log_start)) | ||
117 | return -EAGAIN; | ||
118 | |||
119 | if ((!buf) || (count < 0)) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if (count == 0) | ||
123 | return 0; | ||
124 | |||
125 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
126 | return -EFAULT; | ||
127 | |||
128 | error = wait_event_interruptible(debug_log->queue_wait, | ||
129 | (debug_log->log_start - debug_log->log_end)); | ||
130 | |||
131 | if (error) | ||
132 | return error; | ||
133 | |||
134 | spin_lock_bh(&debug_log->lock); | ||
135 | |||
136 | while ((!error) && (i < count) && | ||
137 | (debug_log->log_start != debug_log->log_end)) { | ||
138 | c = LOG_BUFF(debug_log->log_start); | ||
139 | |||
140 | debug_log->log_start++; | ||
141 | |||
142 | spin_unlock_bh(&debug_log->lock); | ||
143 | |||
144 | error = __put_user(c, buf); | ||
145 | |||
146 | spin_lock_bh(&debug_log->lock); | ||
147 | |||
148 | buf++; | ||
149 | i++; | ||
150 | |||
151 | } | ||
152 | |||
153 | spin_unlock_bh(&debug_log->lock); | ||
154 | |||
155 | if (!error) | ||
156 | return i; | ||
157 | |||
158 | return error; | ||
159 | } | ||
160 | |||
161 | static unsigned int log_poll(struct file *file, poll_table *wait) | ||
162 | { | ||
163 | struct bat_priv *bat_priv = file->private_data; | ||
164 | struct debug_log *debug_log = bat_priv->debug_log; | ||
165 | |||
166 | poll_wait(file, &debug_log->queue_wait, wait); | ||
167 | |||
168 | if (debug_log->log_end - debug_log->log_start) | ||
169 | return POLLIN | POLLRDNORM; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct file_operations log_fops = { | ||
175 | .open = log_open, | ||
176 | .release = log_release, | ||
177 | .read = log_read, | ||
178 | .poll = log_poll, | ||
179 | .llseek = no_llseek, | ||
180 | }; | ||
181 | |||
182 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
183 | { | ||
184 | struct dentry *d; | ||
185 | |||
186 | if (!bat_priv->debug_dir) | ||
187 | goto err; | ||
188 | |||
189 | bat_priv->debug_log = kzalloc(sizeof(struct debug_log), GFP_ATOMIC); | ||
190 | if (!bat_priv->debug_log) | ||
191 | goto err; | ||
192 | |||
193 | spin_lock_init(&bat_priv->debug_log->lock); | ||
194 | init_waitqueue_head(&bat_priv->debug_log->queue_wait); | ||
195 | |||
196 | d = debugfs_create_file("log", S_IFREG | S_IRUSR, | ||
197 | bat_priv->debug_dir, bat_priv, &log_fops); | ||
198 | if (d) | ||
199 | goto err; | ||
200 | |||
201 | return 0; | ||
202 | |||
203 | err: | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
208 | { | ||
209 | kfree(bat_priv->debug_log); | ||
210 | bat_priv->debug_log = NULL; | ||
211 | } | ||
212 | #else /* CONFIG_BATMAN_ADV_DEBUG */ | ||
213 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
214 | { | ||
215 | bat_priv->debug_log = NULL; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
220 | { | ||
221 | return; | ||
222 | } | ||
223 | #endif | ||
224 | |||
225 | static int originators_open(struct inode *inode, struct file *file) | ||
226 | { | ||
227 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
228 | return single_open(file, orig_seq_print_text, net_dev); | ||
229 | } | ||
230 | |||
231 | static int gateways_open(struct inode *inode, struct file *file) | ||
232 | { | ||
233 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
234 | return single_open(file, gw_client_seq_print_text, net_dev); | ||
235 | } | ||
236 | |||
237 | static int softif_neigh_open(struct inode *inode, struct file *file) | ||
238 | { | ||
239 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
240 | return single_open(file, softif_neigh_seq_print_text, net_dev); | ||
241 | } | ||
242 | |||
243 | static int transtable_global_open(struct inode *inode, struct file *file) | ||
244 | { | ||
245 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
246 | return single_open(file, hna_global_seq_print_text, net_dev); | ||
247 | } | ||
248 | |||
249 | static int transtable_local_open(struct inode *inode, struct file *file) | ||
250 | { | ||
251 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
252 | return single_open(file, hna_local_seq_print_text, net_dev); | ||
253 | } | ||
254 | |||
255 | static int vis_data_open(struct inode *inode, struct file *file) | ||
256 | { | ||
257 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
258 | return single_open(file, vis_seq_print_text, net_dev); | ||
259 | } | ||
260 | |||
261 | struct bat_debuginfo { | ||
262 | struct attribute attr; | ||
263 | const struct file_operations fops; | ||
264 | }; | ||
265 | |||
266 | #define BAT_DEBUGINFO(_name, _mode, _open) \ | ||
267 | struct bat_debuginfo bat_debuginfo_##_name = { \ | ||
268 | .attr = { .name = __stringify(_name), \ | ||
269 | .mode = _mode, }, \ | ||
270 | .fops = { .owner = THIS_MODULE, \ | ||
271 | .open = _open, \ | ||
272 | .read = seq_read, \ | ||
273 | .llseek = seq_lseek, \ | ||
274 | .release = single_release, \ | ||
275 | } \ | ||
276 | }; | ||
277 | |||
278 | static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); | ||
279 | static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); | ||
280 | static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); | ||
281 | static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); | ||
282 | static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); | ||
283 | static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); | ||
284 | |||
285 | static struct bat_debuginfo *mesh_debuginfos[] = { | ||
286 | &bat_debuginfo_originators, | ||
287 | &bat_debuginfo_gateways, | ||
288 | &bat_debuginfo_softif_neigh, | ||
289 | &bat_debuginfo_transtable_global, | ||
290 | &bat_debuginfo_transtable_local, | ||
291 | &bat_debuginfo_vis_data, | ||
292 | NULL, | ||
293 | }; | ||
294 | |||
295 | void debugfs_init(void) | ||
296 | { | ||
297 | bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); | ||
298 | if (bat_debugfs == ERR_PTR(-ENODEV)) | ||
299 | bat_debugfs = NULL; | ||
300 | } | ||
301 | |||
302 | void debugfs_destroy(void) | ||
303 | { | ||
304 | if (bat_debugfs) { | ||
305 | debugfs_remove_recursive(bat_debugfs); | ||
306 | bat_debugfs = NULL; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | int debugfs_add_meshif(struct net_device *dev) | ||
311 | { | ||
312 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
313 | struct bat_debuginfo **bat_debug; | ||
314 | struct dentry *file; | ||
315 | |||
316 | if (!bat_debugfs) | ||
317 | goto out; | ||
318 | |||
319 | bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); | ||
320 | if (!bat_priv->debug_dir) | ||
321 | goto out; | ||
322 | |||
323 | bat_socket_setup(bat_priv); | ||
324 | debug_log_setup(bat_priv); | ||
325 | |||
326 | for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { | ||
327 | file = debugfs_create_file(((*bat_debug)->attr).name, | ||
328 | S_IFREG | ((*bat_debug)->attr).mode, | ||
329 | bat_priv->debug_dir, | ||
330 | dev, &(*bat_debug)->fops); | ||
331 | if (!file) { | ||
332 | bat_err(dev, "Can't add debugfs file: %s/%s\n", | ||
333 | dev->name, ((*bat_debug)->attr).name); | ||
334 | goto rem_attr; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | return 0; | ||
339 | rem_attr: | ||
340 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
341 | bat_priv->debug_dir = NULL; | ||
342 | out: | ||
343 | #ifdef CONFIG_DEBUG_FS | ||
344 | return -ENOMEM; | ||
345 | #else | ||
346 | return 0; | ||
347 | #endif /* CONFIG_DEBUG_FS */ | ||
348 | } | ||
349 | |||
350 | void debugfs_del_meshif(struct net_device *dev) | ||
351 | { | ||
352 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
353 | |||
354 | debug_log_cleanup(bat_priv); | ||
355 | |||
356 | if (bat_debugfs) { | ||
357 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
358 | bat_priv->debug_dir = NULL; | ||
359 | } | ||
360 | } | ||
diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h new file mode 100644 index 000000000000..72df532b7d5f --- /dev/null +++ b/net/batman-adv/bat_debugfs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | |||
23 | #ifndef _NET_BATMAN_ADV_DEBUGFS_H_ | ||
24 | #define _NET_BATMAN_ADV_DEBUGFS_H_ | ||
25 | |||
26 | #define DEBUGFS_BAT_SUBDIR "batman_adv" | ||
27 | |||
28 | void debugfs_init(void); | ||
29 | void debugfs_destroy(void); | ||
30 | int debugfs_add_meshif(struct net_device *dev); | ||
31 | void debugfs_del_meshif(struct net_device *dev); | ||
32 | |||
33 | #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ | ||
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c new file mode 100644 index 000000000000..cd7bb51825f1 --- /dev/null +++ b/net/batman-adv/bat_sysfs.c | |||
@@ -0,0 +1,593 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "bat_sysfs.h" | ||
24 | #include "translation-table.h" | ||
25 | #include "originator.h" | ||
26 | #include "hard-interface.h" | ||
27 | #include "gateway_common.h" | ||
28 | #include "gateway_client.h" | ||
29 | #include "vis.h" | ||
30 | |||
31 | #define to_dev(obj) container_of(obj, struct device, kobj) | ||
32 | #define kobj_to_netdev(obj) to_net_dev(to_dev(obj->parent)) | ||
33 | #define kobj_to_batpriv(obj) netdev_priv(kobj_to_netdev(obj)) | ||
34 | |||
35 | /* Use this, if you have customized show and store functions */ | ||
36 | #define BAT_ATTR(_name, _mode, _show, _store) \ | ||
37 | struct bat_attribute bat_attr_##_name = { \ | ||
38 | .attr = {.name = __stringify(_name), \ | ||
39 | .mode = _mode }, \ | ||
40 | .show = _show, \ | ||
41 | .store = _store, \ | ||
42 | }; | ||
43 | |||
44 | #define BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
45 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
46 | char *buff, size_t count) \ | ||
47 | { \ | ||
48 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
49 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
50 | return __store_bool_attr(buff, count, _post_func, attr, \ | ||
51 | &bat_priv->_name, net_dev); \ | ||
52 | } | ||
53 | |||
54 | #define BAT_ATTR_SHOW_BOOL(_name) \ | ||
55 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
56 | char *buff) \ | ||
57 | { \ | ||
58 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
59 | return sprintf(buff, "%s\n", \ | ||
60 | atomic_read(&bat_priv->_name) == 0 ? \ | ||
61 | "disabled" : "enabled"); \ | ||
62 | } \ | ||
63 | |||
64 | /* Use this, if you are going to turn a [name] in bat_priv on or off */ | ||
65 | #define BAT_ATTR_BOOL(_name, _mode, _post_func) \ | ||
66 | static BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
67 | static BAT_ATTR_SHOW_BOOL(_name) \ | ||
68 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
69 | |||
70 | |||
71 | #define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
72 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
73 | char *buff, size_t count) \ | ||
74 | { \ | ||
75 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
76 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
77 | return __store_uint_attr(buff, count, _min, _max, _post_func, \ | ||
78 | attr, &bat_priv->_name, net_dev); \ | ||
79 | } | ||
80 | |||
81 | #define BAT_ATTR_SHOW_UINT(_name) \ | ||
82 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
83 | char *buff) \ | ||
84 | { \ | ||
85 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
86 | return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ | ||
87 | } \ | ||
88 | |||
89 | /* Use this, if you are going to set [name] in bat_priv to unsigned integer | ||
90 | * values only */ | ||
91 | #define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ | ||
92 | static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
93 | static BAT_ATTR_SHOW_UINT(_name) \ | ||
94 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
95 | |||
96 | |||
97 | static int store_bool_attr(char *buff, size_t count, | ||
98 | struct net_device *net_dev, | ||
99 | char *attr_name, atomic_t *attr) | ||
100 | { | ||
101 | int enabled = -1; | ||
102 | |||
103 | if (buff[count - 1] == '\n') | ||
104 | buff[count - 1] = '\0'; | ||
105 | |||
106 | if ((strncmp(buff, "1", 2) == 0) || | ||
107 | (strncmp(buff, "enable", 7) == 0) || | ||
108 | (strncmp(buff, "enabled", 8) == 0)) | ||
109 | enabled = 1; | ||
110 | |||
111 | if ((strncmp(buff, "0", 2) == 0) || | ||
112 | (strncmp(buff, "disable", 8) == 0) || | ||
113 | (strncmp(buff, "disabled", 9) == 0)) | ||
114 | enabled = 0; | ||
115 | |||
116 | if (enabled < 0) { | ||
117 | bat_info(net_dev, | ||
118 | "%s: Invalid parameter received: %s\n", | ||
119 | attr_name, buff); | ||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | if (atomic_read(attr) == enabled) | ||
124 | return count; | ||
125 | |||
126 | bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, | ||
127 | atomic_read(attr) == 1 ? "enabled" : "disabled", | ||
128 | enabled == 1 ? "enabled" : "disabled"); | ||
129 | |||
130 | atomic_set(attr, (unsigned)enabled); | ||
131 | return count; | ||
132 | } | ||
133 | |||
134 | static inline ssize_t __store_bool_attr(char *buff, size_t count, | ||
135 | void (*post_func)(struct net_device *), | ||
136 | struct attribute *attr, | ||
137 | atomic_t *attr_store, struct net_device *net_dev) | ||
138 | { | ||
139 | int ret; | ||
140 | |||
141 | ret = store_bool_attr(buff, count, net_dev, (char *)attr->name, | ||
142 | attr_store); | ||
143 | if (post_func && ret) | ||
144 | post_func(net_dev); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int store_uint_attr(char *buff, size_t count, | ||
150 | struct net_device *net_dev, char *attr_name, | ||
151 | unsigned int min, unsigned int max, atomic_t *attr) | ||
152 | { | ||
153 | unsigned long uint_val; | ||
154 | int ret; | ||
155 | |||
156 | ret = strict_strtoul(buff, 10, &uint_val); | ||
157 | if (ret) { | ||
158 | bat_info(net_dev, | ||
159 | "%s: Invalid parameter received: %s\n", | ||
160 | attr_name, buff); | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | if (uint_val < min) { | ||
165 | bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", | ||
166 | attr_name, uint_val, min); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | if (uint_val > max) { | ||
171 | bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", | ||
172 | attr_name, uint_val, max); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | if (atomic_read(attr) == uint_val) | ||
177 | return count; | ||
178 | |||
179 | bat_info(net_dev, "%s: Changing from: %i to: %lu\n", | ||
180 | attr_name, atomic_read(attr), uint_val); | ||
181 | |||
182 | atomic_set(attr, uint_val); | ||
183 | return count; | ||
184 | } | ||
185 | |||
186 | static inline ssize_t __store_uint_attr(char *buff, size_t count, | ||
187 | int min, int max, | ||
188 | void (*post_func)(struct net_device *), | ||
189 | struct attribute *attr, | ||
190 | atomic_t *attr_store, struct net_device *net_dev) | ||
191 | { | ||
192 | int ret; | ||
193 | |||
194 | ret = store_uint_attr(buff, count, net_dev, (char *)attr->name, | ||
195 | min, max, attr_store); | ||
196 | if (post_func && ret) | ||
197 | post_func(net_dev); | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
203 | char *buff) | ||
204 | { | ||
205 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
206 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
207 | |||
208 | return sprintf(buff, "%s\n", | ||
209 | vis_mode == VIS_TYPE_CLIENT_UPDATE ? | ||
210 | "client" : "server"); | ||
211 | } | ||
212 | |||
213 | static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
214 | char *buff, size_t count) | ||
215 | { | ||
216 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
217 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
218 | unsigned long val; | ||
219 | int ret, vis_mode_tmp = -1; | ||
220 | |||
221 | ret = strict_strtoul(buff, 10, &val); | ||
222 | |||
223 | if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || | ||
224 | (strncmp(buff, "client", 6) == 0) || | ||
225 | (strncmp(buff, "off", 3) == 0)) | ||
226 | vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; | ||
227 | |||
228 | if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || | ||
229 | (strncmp(buff, "server", 6) == 0)) | ||
230 | vis_mode_tmp = VIS_TYPE_SERVER_SYNC; | ||
231 | |||
232 | if (vis_mode_tmp < 0) { | ||
233 | if (buff[count - 1] == '\n') | ||
234 | buff[count - 1] = '\0'; | ||
235 | |||
236 | bat_info(net_dev, | ||
237 | "Invalid parameter for 'vis mode' setting received: " | ||
238 | "%s\n", buff); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
243 | return count; | ||
244 | |||
245 | bat_info(net_dev, "Changing vis mode from: %s to: %s\n", | ||
246 | atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? | ||
247 | "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? | ||
248 | "client" : "server"); | ||
249 | |||
250 | atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); | ||
251 | return count; | ||
252 | } | ||
253 | |||
254 | static void post_gw_deselect(struct net_device *net_dev) | ||
255 | { | ||
256 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
257 | gw_deselect(bat_priv); | ||
258 | } | ||
259 | |||
260 | static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
261 | char *buff) | ||
262 | { | ||
263 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
264 | int bytes_written; | ||
265 | |||
266 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
267 | case GW_MODE_CLIENT: | ||
268 | bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); | ||
269 | break; | ||
270 | case GW_MODE_SERVER: | ||
271 | bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); | ||
272 | break; | ||
273 | default: | ||
274 | bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); | ||
275 | break; | ||
276 | } | ||
277 | |||
278 | return bytes_written; | ||
279 | } | ||
280 | |||
281 | static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
282 | char *buff, size_t count) | ||
283 | { | ||
284 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
285 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
286 | char *curr_gw_mode_str; | ||
287 | int gw_mode_tmp = -1; | ||
288 | |||
289 | if (buff[count - 1] == '\n') | ||
290 | buff[count - 1] = '\0'; | ||
291 | |||
292 | if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) | ||
293 | gw_mode_tmp = GW_MODE_OFF; | ||
294 | |||
295 | if (strncmp(buff, GW_MODE_CLIENT_NAME, | ||
296 | strlen(GW_MODE_CLIENT_NAME)) == 0) | ||
297 | gw_mode_tmp = GW_MODE_CLIENT; | ||
298 | |||
299 | if (strncmp(buff, GW_MODE_SERVER_NAME, | ||
300 | strlen(GW_MODE_SERVER_NAME)) == 0) | ||
301 | gw_mode_tmp = GW_MODE_SERVER; | ||
302 | |||
303 | if (gw_mode_tmp < 0) { | ||
304 | bat_info(net_dev, | ||
305 | "Invalid parameter for 'gw mode' setting received: " | ||
306 | "%s\n", buff); | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) | ||
311 | return count; | ||
312 | |||
313 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
314 | case GW_MODE_CLIENT: | ||
315 | curr_gw_mode_str = GW_MODE_CLIENT_NAME; | ||
316 | break; | ||
317 | case GW_MODE_SERVER: | ||
318 | curr_gw_mode_str = GW_MODE_SERVER_NAME; | ||
319 | break; | ||
320 | default: | ||
321 | curr_gw_mode_str = GW_MODE_OFF_NAME; | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | bat_info(net_dev, "Changing gw mode from: %s to: %s\n", | ||
326 | curr_gw_mode_str, buff); | ||
327 | |||
328 | gw_deselect(bat_priv); | ||
329 | atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); | ||
330 | return count; | ||
331 | } | ||
332 | |||
333 | static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
334 | char *buff) | ||
335 | { | ||
336 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
337 | int down, up; | ||
338 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | ||
339 | |||
340 | gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | ||
341 | return sprintf(buff, "%i%s/%i%s\n", | ||
342 | (down > 2048 ? down / 1024 : down), | ||
343 | (down > 2048 ? "MBit" : "KBit"), | ||
344 | (up > 2048 ? up / 1024 : up), | ||
345 | (up > 2048 ? "MBit" : "KBit")); | ||
346 | } | ||
347 | |||
348 | static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
349 | char *buff, size_t count) | ||
350 | { | ||
351 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
352 | |||
353 | if (buff[count - 1] == '\n') | ||
354 | buff[count - 1] = '\0'; | ||
355 | |||
356 | return gw_bandwidth_set(net_dev, buff, count); | ||
357 | } | ||
358 | |||
359 | BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | ||
360 | BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | ||
361 | BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); | ||
362 | static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); | ||
363 | static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); | ||
364 | BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); | ||
365 | BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); | ||
366 | BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, | ||
367 | post_gw_deselect); | ||
368 | static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, | ||
369 | store_gw_bwidth); | ||
370 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
371 | BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 3, NULL); | ||
372 | #endif | ||
373 | |||
374 | static struct bat_attribute *mesh_attrs[] = { | ||
375 | &bat_attr_aggregated_ogms, | ||
376 | &bat_attr_bonding, | ||
377 | &bat_attr_fragmentation, | ||
378 | &bat_attr_vis_mode, | ||
379 | &bat_attr_gw_mode, | ||
380 | &bat_attr_orig_interval, | ||
381 | &bat_attr_hop_penalty, | ||
382 | &bat_attr_gw_sel_class, | ||
383 | &bat_attr_gw_bandwidth, | ||
384 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
385 | &bat_attr_log_level, | ||
386 | #endif | ||
387 | NULL, | ||
388 | }; | ||
389 | |||
390 | int sysfs_add_meshif(struct net_device *dev) | ||
391 | { | ||
392 | struct kobject *batif_kobject = &dev->dev.kobj; | ||
393 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
394 | struct bat_attribute **bat_attr; | ||
395 | int err; | ||
396 | |||
397 | bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, | ||
398 | batif_kobject); | ||
399 | if (!bat_priv->mesh_obj) { | ||
400 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
401 | SYSFS_IF_MESH_SUBDIR); | ||
402 | goto out; | ||
403 | } | ||
404 | |||
405 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) { | ||
406 | err = sysfs_create_file(bat_priv->mesh_obj, | ||
407 | &((*bat_attr)->attr)); | ||
408 | if (err) { | ||
409 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
410 | dev->name, SYSFS_IF_MESH_SUBDIR, | ||
411 | ((*bat_attr)->attr).name); | ||
412 | goto rem_attr; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | |||
418 | rem_attr: | ||
419 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
420 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
421 | |||
422 | kobject_put(bat_priv->mesh_obj); | ||
423 | bat_priv->mesh_obj = NULL; | ||
424 | out: | ||
425 | return -ENOMEM; | ||
426 | } | ||
427 | |||
428 | void sysfs_del_meshif(struct net_device *dev) | ||
429 | { | ||
430 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
431 | struct bat_attribute **bat_attr; | ||
432 | |||
433 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
434 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
435 | |||
436 | kobject_put(bat_priv->mesh_obj); | ||
437 | bat_priv->mesh_obj = NULL; | ||
438 | } | ||
439 | |||
440 | static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
441 | char *buff) | ||
442 | { | ||
443 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
444 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
445 | ssize_t length; | ||
446 | |||
447 | if (!batman_if) | ||
448 | return 0; | ||
449 | |||
450 | length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? | ||
451 | "none" : batman_if->soft_iface->name); | ||
452 | |||
453 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
454 | |||
455 | return length; | ||
456 | } | ||
457 | |||
458 | static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
459 | char *buff, size_t count) | ||
460 | { | ||
461 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
462 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
463 | int status_tmp = -1; | ||
464 | int ret; | ||
465 | |||
466 | if (!batman_if) | ||
467 | return count; | ||
468 | |||
469 | if (buff[count - 1] == '\n') | ||
470 | buff[count - 1] = '\0'; | ||
471 | |||
472 | if (strlen(buff) >= IFNAMSIZ) { | ||
473 | pr_err("Invalid parameter for 'mesh_iface' setting received: " | ||
474 | "interface name too long '%s'\n", buff); | ||
475 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | |||
479 | if (strncmp(buff, "none", 4) == 0) | ||
480 | status_tmp = IF_NOT_IN_USE; | ||
481 | else | ||
482 | status_tmp = IF_I_WANT_YOU; | ||
483 | |||
484 | if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && | ||
485 | (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { | ||
486 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
487 | return count; | ||
488 | } | ||
489 | |||
490 | if (status_tmp == IF_NOT_IN_USE) { | ||
491 | rtnl_lock(); | ||
492 | hardif_disable_interface(batman_if); | ||
493 | rtnl_unlock(); | ||
494 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
495 | return count; | ||
496 | } | ||
497 | |||
498 | /* if the interface already is in use */ | ||
499 | if (batman_if->if_status != IF_NOT_IN_USE) { | ||
500 | rtnl_lock(); | ||
501 | hardif_disable_interface(batman_if); | ||
502 | rtnl_unlock(); | ||
503 | } | ||
504 | |||
505 | ret = hardif_enable_interface(batman_if, buff); | ||
506 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
507 | |||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, | ||
512 | char *buff) | ||
513 | { | ||
514 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
515 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
516 | ssize_t length; | ||
517 | |||
518 | if (!batman_if) | ||
519 | return 0; | ||
520 | |||
521 | switch (batman_if->if_status) { | ||
522 | case IF_TO_BE_REMOVED: | ||
523 | length = sprintf(buff, "disabling\n"); | ||
524 | break; | ||
525 | case IF_INACTIVE: | ||
526 | length = sprintf(buff, "inactive\n"); | ||
527 | break; | ||
528 | case IF_ACTIVE: | ||
529 | length = sprintf(buff, "active\n"); | ||
530 | break; | ||
531 | case IF_TO_BE_ACTIVATED: | ||
532 | length = sprintf(buff, "enabling\n"); | ||
533 | break; | ||
534 | case IF_NOT_IN_USE: | ||
535 | default: | ||
536 | length = sprintf(buff, "not in use\n"); | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
541 | |||
542 | return length; | ||
543 | } | ||
544 | |||
545 | static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, | ||
546 | show_mesh_iface, store_mesh_iface); | ||
547 | static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); | ||
548 | |||
549 | static struct bat_attribute *batman_attrs[] = { | ||
550 | &bat_attr_mesh_iface, | ||
551 | &bat_attr_iface_status, | ||
552 | NULL, | ||
553 | }; | ||
554 | |||
555 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) | ||
556 | { | ||
557 | struct kobject *hardif_kobject = &dev->dev.kobj; | ||
558 | struct bat_attribute **bat_attr; | ||
559 | int err; | ||
560 | |||
561 | *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR, | ||
562 | hardif_kobject); | ||
563 | |||
564 | if (!*hardif_obj) { | ||
565 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
566 | SYSFS_IF_BAT_SUBDIR); | ||
567 | goto out; | ||
568 | } | ||
569 | |||
570 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) { | ||
571 | err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); | ||
572 | if (err) { | ||
573 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
574 | dev->name, SYSFS_IF_BAT_SUBDIR, | ||
575 | ((*bat_attr)->attr).name); | ||
576 | goto rem_attr; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | |||
582 | rem_attr: | ||
583 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) | ||
584 | sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); | ||
585 | out: | ||
586 | return -ENOMEM; | ||
587 | } | ||
588 | |||
589 | void sysfs_del_hardif(struct kobject **hardif_obj) | ||
590 | { | ||
591 | kobject_put(*hardif_obj); | ||
592 | *hardif_obj = NULL; | ||
593 | } | ||
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h new file mode 100644 index 000000000000..7f186c007b4f --- /dev/null +++ b/net/batman-adv/bat_sysfs.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | |||
23 | #ifndef _NET_BATMAN_ADV_SYSFS_H_ | ||
24 | #define _NET_BATMAN_ADV_SYSFS_H_ | ||
25 | |||
26 | #define SYSFS_IF_MESH_SUBDIR "mesh" | ||
27 | #define SYSFS_IF_BAT_SUBDIR "batman_adv" | ||
28 | |||
29 | struct bat_attribute { | ||
30 | struct attribute attr; | ||
31 | ssize_t (*show)(struct kobject *kobj, struct attribute *attr, | ||
32 | char *buf); | ||
33 | ssize_t (*store)(struct kobject *kobj, struct attribute *attr, | ||
34 | char *buf, size_t count); | ||
35 | }; | ||
36 | |||
37 | int sysfs_add_meshif(struct net_device *dev); | ||
38 | void sysfs_del_meshif(struct net_device *dev); | ||
39 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev); | ||
40 | void sysfs_del_hardif(struct kobject **hardif_obj); | ||
41 | |||
42 | #endif /* _NET_BATMAN_ADV_SYSFS_H_ */ | ||
diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c new file mode 100644 index 000000000000..bbcd8f744cdd --- /dev/null +++ b/net/batman-adv/bitarray.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Simon Wunderlich, Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "bitarray.h" | ||
24 | |||
25 | #include <linux/bitops.h> | ||
26 | |||
27 | /* returns true if the corresponding bit in the given seq_bits indicates true | ||
28 | * and curr_seqno is within range of last_seqno */ | ||
29 | uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno, | ||
30 | uint32_t curr_seqno) | ||
31 | { | ||
32 | int32_t diff, word_offset, word_num; | ||
33 | |||
34 | diff = last_seqno - curr_seqno; | ||
35 | if (diff < 0 || diff >= TQ_LOCAL_WINDOW_SIZE) { | ||
36 | return 0; | ||
37 | } else { | ||
38 | /* which word */ | ||
39 | word_num = (last_seqno - curr_seqno) / WORD_BIT_SIZE; | ||
40 | /* which position in the selected word */ | ||
41 | word_offset = (last_seqno - curr_seqno) % WORD_BIT_SIZE; | ||
42 | |||
43 | if (test_bit(word_offset, &seq_bits[word_num])) | ||
44 | return 1; | ||
45 | else | ||
46 | return 0; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /* turn corresponding bit on, so we can remember that we got the packet */ | ||
51 | void bit_mark(unsigned long *seq_bits, int32_t n) | ||
52 | { | ||
53 | int32_t word_offset, word_num; | ||
54 | |||
55 | /* if too old, just drop it */ | ||
56 | if (n < 0 || n >= TQ_LOCAL_WINDOW_SIZE) | ||
57 | return; | ||
58 | |||
59 | /* which word */ | ||
60 | word_num = n / WORD_BIT_SIZE; | ||
61 | /* which position in the selected word */ | ||
62 | word_offset = n % WORD_BIT_SIZE; | ||
63 | |||
64 | set_bit(word_offset, &seq_bits[word_num]); /* turn the position on */ | ||
65 | } | ||
66 | |||
67 | /* shift the packet array by n places. */ | ||
68 | static void bit_shift(unsigned long *seq_bits, int32_t n) | ||
69 | { | ||
70 | int32_t word_offset, word_num; | ||
71 | int32_t i; | ||
72 | |||
73 | if (n <= 0 || n >= TQ_LOCAL_WINDOW_SIZE) | ||
74 | return; | ||
75 | |||
76 | word_offset = n % WORD_BIT_SIZE;/* shift how much inside each word */ | ||
77 | word_num = n / WORD_BIT_SIZE; /* shift over how much (full) words */ | ||
78 | |||
79 | for (i = NUM_WORDS - 1; i > word_num; i--) { | ||
80 | /* going from old to new, so we don't overwrite the data we copy | ||
81 | * from. | ||
82 | * | ||
83 | * left is high, right is low: FEDC BA98 7654 3210 | ||
84 | * ^^ ^^ | ||
85 | * vvvv | ||
86 | * ^^^^ = from, vvvvv =to, we'd have word_num==1 and | ||
87 | * word_offset==WORD_BIT_SIZE/2 ????? in this example. | ||
88 | * (=24 bits) | ||
89 | * | ||
90 | * our desired output would be: 9876 5432 1000 0000 | ||
91 | * */ | ||
92 | |||
93 | seq_bits[i] = | ||
94 | (seq_bits[i - word_num] << word_offset) + | ||
95 | /* take the lower port from the left half, shift it left | ||
96 | * to its final position */ | ||
97 | (seq_bits[i - word_num - 1] >> | ||
98 | (WORD_BIT_SIZE-word_offset)); | ||
99 | /* and the upper part of the right half and shift it left to | ||
100 | * it's position */ | ||
101 | /* for our example that would be: word[0] = 9800 + 0076 = | ||
102 | * 9876 */ | ||
103 | } | ||
104 | /* now for our last word, i==word_num, we only have the it's "left" | ||
105 | * half. that's the 1000 word in our example.*/ | ||
106 | |||
107 | seq_bits[i] = (seq_bits[i - word_num] << word_offset); | ||
108 | |||
109 | /* pad the rest with 0, if there is anything */ | ||
110 | i--; | ||
111 | |||
112 | for (; i >= 0; i--) | ||
113 | seq_bits[i] = 0; | ||
114 | } | ||
115 | |||
116 | static void bit_reset_window(unsigned long *seq_bits) | ||
117 | { | ||
118 | int i; | ||
119 | for (i = 0; i < NUM_WORDS; i++) | ||
120 | seq_bits[i] = 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | /* receive and process one packet within the sequence number window. | ||
125 | * | ||
126 | * returns: | ||
127 | * 1 if the window was moved (either new or very old) | ||
128 | * 0 if the window was not moved/shifted. | ||
129 | */ | ||
130 | char bit_get_packet(void *priv, unsigned long *seq_bits, | ||
131 | int32_t seq_num_diff, int8_t set_mark) | ||
132 | { | ||
133 | struct bat_priv *bat_priv = (struct bat_priv *)priv; | ||
134 | |||
135 | /* sequence number is slightly older. We already got a sequence number | ||
136 | * higher than this one, so we just mark it. */ | ||
137 | |||
138 | if ((seq_num_diff <= 0) && (seq_num_diff > -TQ_LOCAL_WINDOW_SIZE)) { | ||
139 | if (set_mark) | ||
140 | bit_mark(seq_bits, -seq_num_diff); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* sequence number is slightly newer, so we shift the window and | ||
145 | * set the mark if required */ | ||
146 | |||
147 | if ((seq_num_diff > 0) && (seq_num_diff < TQ_LOCAL_WINDOW_SIZE)) { | ||
148 | bit_shift(seq_bits, seq_num_diff); | ||
149 | |||
150 | if (set_mark) | ||
151 | bit_mark(seq_bits, 0); | ||
152 | return 1; | ||
153 | } | ||
154 | |||
155 | /* sequence number is much newer, probably missed a lot of packets */ | ||
156 | |||
157 | if ((seq_num_diff >= TQ_LOCAL_WINDOW_SIZE) | ||
158 | || (seq_num_diff < EXPECTED_SEQNO_RANGE)) { | ||
159 | bat_dbg(DBG_BATMAN, bat_priv, | ||
160 | "We missed a lot of packets (%i) !\n", | ||
161 | seq_num_diff - 1); | ||
162 | bit_reset_window(seq_bits); | ||
163 | if (set_mark) | ||
164 | bit_mark(seq_bits, 0); | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | /* received a much older packet. The other host either restarted | ||
169 | * or the old packet got delayed somewhere in the network. The | ||
170 | * packet should be dropped without calling this function if the | ||
171 | * seqno window is protected. */ | ||
172 | |||
173 | if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) | ||
174 | || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { | ||
175 | |||
176 | bat_dbg(DBG_BATMAN, bat_priv, | ||
177 | "Other host probably restarted!\n"); | ||
178 | |||
179 | bit_reset_window(seq_bits); | ||
180 | if (set_mark) | ||
181 | bit_mark(seq_bits, 0); | ||
182 | |||
183 | return 1; | ||
184 | } | ||
185 | |||
186 | /* never reached */ | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* count the hamming weight, how many good packets did we receive? just count | ||
191 | * the 1's. | ||
192 | */ | ||
193 | int bit_packet_count(unsigned long *seq_bits) | ||
194 | { | ||
195 | int i, hamming = 0; | ||
196 | |||
197 | for (i = 0; i < NUM_WORDS; i++) | ||
198 | hamming += hweight_long(seq_bits[i]); | ||
199 | |||
200 | return hamming; | ||
201 | } | ||
diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h new file mode 100644 index 000000000000..ac54017601b1 --- /dev/null +++ b/net/batman-adv/bitarray.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Simon Wunderlich, Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_BITARRAY_H_ | ||
23 | #define _NET_BATMAN_ADV_BITARRAY_H_ | ||
24 | |||
25 | #define WORD_BIT_SIZE (sizeof(unsigned long) * 8) | ||
26 | |||
27 | /* returns true if the corresponding bit in the given seq_bits indicates true | ||
28 | * and curr_seqno is within range of last_seqno */ | ||
29 | uint8_t get_bit_status(unsigned long *seq_bits, uint32_t last_seqno, | ||
30 | uint32_t curr_seqno); | ||
31 | |||
32 | /* turn corresponding bit on, so we can remember that we got the packet */ | ||
33 | void bit_mark(unsigned long *seq_bits, int32_t n); | ||
34 | |||
35 | |||
36 | /* receive and process one packet, returns 1 if received seq_num is considered | ||
37 | * new, 0 if old */ | ||
38 | char bit_get_packet(void *priv, unsigned long *seq_bits, | ||
39 | int32_t seq_num_diff, int8_t set_mark); | ||
40 | |||
41 | /* count the hamming weight, how many good packets did we receive? */ | ||
42 | int bit_packet_count(unsigned long *seq_bits); | ||
43 | |||
44 | #endif /* _NET_BATMAN_ADV_BITARRAY_H_ */ | ||
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c new file mode 100644 index 000000000000..0065ffb8d96d --- /dev/null +++ b/net/batman-adv/gateway_client.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "gateway_client.h" | ||
24 | #include "gateway_common.h" | ||
25 | #include "hard-interface.h" | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/ipv6.h> | ||
28 | #include <linux/udp.h> | ||
29 | #include <linux/if_vlan.h> | ||
30 | |||
31 | static void gw_node_free_ref(struct kref *refcount) | ||
32 | { | ||
33 | struct gw_node *gw_node; | ||
34 | |||
35 | gw_node = container_of(refcount, struct gw_node, refcount); | ||
36 | kfree(gw_node); | ||
37 | } | ||
38 | |||
39 | static void gw_node_free_rcu(struct rcu_head *rcu) | ||
40 | { | ||
41 | struct gw_node *gw_node; | ||
42 | |||
43 | gw_node = container_of(rcu, struct gw_node, rcu); | ||
44 | kref_put(&gw_node->refcount, gw_node_free_ref); | ||
45 | } | ||
46 | |||
47 | void *gw_get_selected(struct bat_priv *bat_priv) | ||
48 | { | ||
49 | struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; | ||
50 | |||
51 | if (!curr_gateway_tmp) | ||
52 | return NULL; | ||
53 | |||
54 | return curr_gateway_tmp->orig_node; | ||
55 | } | ||
56 | |||
57 | void gw_deselect(struct bat_priv *bat_priv) | ||
58 | { | ||
59 | struct gw_node *gw_node = bat_priv->curr_gw; | ||
60 | |||
61 | bat_priv->curr_gw = NULL; | ||
62 | |||
63 | if (gw_node) | ||
64 | kref_put(&gw_node->refcount, gw_node_free_ref); | ||
65 | } | ||
66 | |||
67 | static struct gw_node *gw_select(struct bat_priv *bat_priv, | ||
68 | struct gw_node *new_gw_node) | ||
69 | { | ||
70 | struct gw_node *curr_gw_node = bat_priv->curr_gw; | ||
71 | |||
72 | if (new_gw_node) | ||
73 | kref_get(&new_gw_node->refcount); | ||
74 | |||
75 | bat_priv->curr_gw = new_gw_node; | ||
76 | return curr_gw_node; | ||
77 | } | ||
78 | |||
79 | void gw_election(struct bat_priv *bat_priv) | ||
80 | { | ||
81 | struct hlist_node *node; | ||
82 | struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL; | ||
83 | uint8_t max_tq = 0; | ||
84 | uint32_t max_gw_factor = 0, tmp_gw_factor = 0; | ||
85 | int down, up; | ||
86 | |||
87 | /** | ||
88 | * The batman daemon checks here if we already passed a full originator | ||
89 | * cycle in order to make sure we don't choose the first gateway we | ||
90 | * hear about. This check is based on the daemon's uptime which we | ||
91 | * don't have. | ||
92 | **/ | ||
93 | if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) | ||
94 | return; | ||
95 | |||
96 | if (bat_priv->curr_gw) | ||
97 | return; | ||
98 | |||
99 | rcu_read_lock(); | ||
100 | if (hlist_empty(&bat_priv->gw_list)) { | ||
101 | rcu_read_unlock(); | ||
102 | |||
103 | if (bat_priv->curr_gw) { | ||
104 | bat_dbg(DBG_BATMAN, bat_priv, | ||
105 | "Removing selected gateway - " | ||
106 | "no gateway in range\n"); | ||
107 | gw_deselect(bat_priv); | ||
108 | } | ||
109 | |||
110 | return; | ||
111 | } | ||
112 | |||
113 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | ||
114 | if (!gw_node->orig_node->router) | ||
115 | continue; | ||
116 | |||
117 | if (gw_node->deleted) | ||
118 | continue; | ||
119 | |||
120 | switch (atomic_read(&bat_priv->gw_sel_class)) { | ||
121 | case 1: /* fast connection */ | ||
122 | gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, | ||
123 | &down, &up); | ||
124 | |||
125 | tmp_gw_factor = (gw_node->orig_node->router->tq_avg * | ||
126 | gw_node->orig_node->router->tq_avg * | ||
127 | down * 100 * 100) / | ||
128 | (TQ_LOCAL_WINDOW_SIZE * | ||
129 | TQ_LOCAL_WINDOW_SIZE * 64); | ||
130 | |||
131 | if ((tmp_gw_factor > max_gw_factor) || | ||
132 | ((tmp_gw_factor == max_gw_factor) && | ||
133 | (gw_node->orig_node->router->tq_avg > max_tq))) | ||
134 | curr_gw_tmp = gw_node; | ||
135 | break; | ||
136 | |||
137 | default: /** | ||
138 | * 2: stable connection (use best statistic) | ||
139 | * 3: fast-switch (use best statistic but change as | ||
140 | * soon as a better gateway appears) | ||
141 | * XX: late-switch (use best statistic but change as | ||
142 | * soon as a better gateway appears which has | ||
143 | * $routing_class more tq points) | ||
144 | **/ | ||
145 | if (gw_node->orig_node->router->tq_avg > max_tq) | ||
146 | curr_gw_tmp = gw_node; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (gw_node->orig_node->router->tq_avg > max_tq) | ||
151 | max_tq = gw_node->orig_node->router->tq_avg; | ||
152 | |||
153 | if (tmp_gw_factor > max_gw_factor) | ||
154 | max_gw_factor = tmp_gw_factor; | ||
155 | } | ||
156 | |||
157 | if (bat_priv->curr_gw != curr_gw_tmp) { | ||
158 | if ((bat_priv->curr_gw) && (!curr_gw_tmp)) | ||
159 | bat_dbg(DBG_BATMAN, bat_priv, | ||
160 | "Removing selected gateway - " | ||
161 | "no gateway in range\n"); | ||
162 | else if ((!bat_priv->curr_gw) && (curr_gw_tmp)) | ||
163 | bat_dbg(DBG_BATMAN, bat_priv, | ||
164 | "Adding route to gateway %pM " | ||
165 | "(gw_flags: %i, tq: %i)\n", | ||
166 | curr_gw_tmp->orig_node->orig, | ||
167 | curr_gw_tmp->orig_node->gw_flags, | ||
168 | curr_gw_tmp->orig_node->router->tq_avg); | ||
169 | else | ||
170 | bat_dbg(DBG_BATMAN, bat_priv, | ||
171 | "Changing route to gateway %pM " | ||
172 | "(gw_flags: %i, tq: %i)\n", | ||
173 | curr_gw_tmp->orig_node->orig, | ||
174 | curr_gw_tmp->orig_node->gw_flags, | ||
175 | curr_gw_tmp->orig_node->router->tq_avg); | ||
176 | |||
177 | old_gw_node = gw_select(bat_priv, curr_gw_tmp); | ||
178 | } | ||
179 | |||
180 | rcu_read_unlock(); | ||
181 | |||
182 | /* the kfree() has to be outside of the rcu lock */ | ||
183 | if (old_gw_node) | ||
184 | kref_put(&old_gw_node->refcount, gw_node_free_ref); | ||
185 | } | ||
186 | |||
187 | void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) | ||
188 | { | ||
189 | struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; | ||
190 | uint8_t gw_tq_avg, orig_tq_avg; | ||
191 | |||
192 | if (!curr_gateway_tmp) | ||
193 | return; | ||
194 | |||
195 | if (!curr_gateway_tmp->orig_node) | ||
196 | goto deselect; | ||
197 | |||
198 | if (!curr_gateway_tmp->orig_node->router) | ||
199 | goto deselect; | ||
200 | |||
201 | /* this node already is the gateway */ | ||
202 | if (curr_gateway_tmp->orig_node == orig_node) | ||
203 | return; | ||
204 | |||
205 | if (!orig_node->router) | ||
206 | return; | ||
207 | |||
208 | gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; | ||
209 | orig_tq_avg = orig_node->router->tq_avg; | ||
210 | |||
211 | /* the TQ value has to be better */ | ||
212 | if (orig_tq_avg < gw_tq_avg) | ||
213 | return; | ||
214 | |||
215 | /** | ||
216 | * if the routing class is greater than 3 the value tells us how much | ||
217 | * greater the TQ value of the new gateway must be | ||
218 | **/ | ||
219 | if ((atomic_read(&bat_priv->gw_sel_class) > 3) && | ||
220 | (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class))) | ||
221 | return; | ||
222 | |||
223 | bat_dbg(DBG_BATMAN, bat_priv, | ||
224 | "Restarting gateway selection: better gateway found (tq curr: " | ||
225 | "%i, tq new: %i)\n", | ||
226 | gw_tq_avg, orig_tq_avg); | ||
227 | |||
228 | deselect: | ||
229 | gw_deselect(bat_priv); | ||
230 | } | ||
231 | |||
232 | static void gw_node_add(struct bat_priv *bat_priv, | ||
233 | struct orig_node *orig_node, uint8_t new_gwflags) | ||
234 | { | ||
235 | struct gw_node *gw_node; | ||
236 | int down, up; | ||
237 | |||
238 | gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); | ||
239 | if (!gw_node) | ||
240 | return; | ||
241 | |||
242 | memset(gw_node, 0, sizeof(struct gw_node)); | ||
243 | INIT_HLIST_NODE(&gw_node->list); | ||
244 | gw_node->orig_node = orig_node; | ||
245 | kref_init(&gw_node->refcount); | ||
246 | |||
247 | spin_lock_bh(&bat_priv->gw_list_lock); | ||
248 | hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list); | ||
249 | spin_unlock_bh(&bat_priv->gw_list_lock); | ||
250 | |||
251 | gw_bandwidth_to_kbit(new_gwflags, &down, &up); | ||
252 | bat_dbg(DBG_BATMAN, bat_priv, | ||
253 | "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", | ||
254 | orig_node->orig, new_gwflags, | ||
255 | (down > 2048 ? down / 1024 : down), | ||
256 | (down > 2048 ? "MBit" : "KBit"), | ||
257 | (up > 2048 ? up / 1024 : up), | ||
258 | (up > 2048 ? "MBit" : "KBit")); | ||
259 | } | ||
260 | |||
261 | void gw_node_update(struct bat_priv *bat_priv, | ||
262 | struct orig_node *orig_node, uint8_t new_gwflags) | ||
263 | { | ||
264 | struct hlist_node *node; | ||
265 | struct gw_node *gw_node; | ||
266 | |||
267 | rcu_read_lock(); | ||
268 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | ||
269 | if (gw_node->orig_node != orig_node) | ||
270 | continue; | ||
271 | |||
272 | bat_dbg(DBG_BATMAN, bat_priv, | ||
273 | "Gateway class of originator %pM changed from " | ||
274 | "%i to %i\n", | ||
275 | orig_node->orig, gw_node->orig_node->gw_flags, | ||
276 | new_gwflags); | ||
277 | |||
278 | gw_node->deleted = 0; | ||
279 | |||
280 | if (new_gwflags == 0) { | ||
281 | gw_node->deleted = jiffies; | ||
282 | bat_dbg(DBG_BATMAN, bat_priv, | ||
283 | "Gateway %pM removed from gateway list\n", | ||
284 | orig_node->orig); | ||
285 | |||
286 | if (gw_node == bat_priv->curr_gw) { | ||
287 | rcu_read_unlock(); | ||
288 | gw_deselect(bat_priv); | ||
289 | return; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | rcu_read_unlock(); | ||
294 | return; | ||
295 | } | ||
296 | rcu_read_unlock(); | ||
297 | |||
298 | if (new_gwflags == 0) | ||
299 | return; | ||
300 | |||
301 | gw_node_add(bat_priv, orig_node, new_gwflags); | ||
302 | } | ||
303 | |||
304 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) | ||
305 | { | ||
306 | return gw_node_update(bat_priv, orig_node, 0); | ||
307 | } | ||
308 | |||
309 | void gw_node_purge(struct bat_priv *bat_priv) | ||
310 | { | ||
311 | struct gw_node *gw_node; | ||
312 | struct hlist_node *node, *node_tmp; | ||
313 | unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; | ||
314 | |||
315 | spin_lock_bh(&bat_priv->gw_list_lock); | ||
316 | |||
317 | hlist_for_each_entry_safe(gw_node, node, node_tmp, | ||
318 | &bat_priv->gw_list, list) { | ||
319 | if (((!gw_node->deleted) || | ||
320 | (time_before(jiffies, gw_node->deleted + timeout))) && | ||
321 | atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) | ||
322 | continue; | ||
323 | |||
324 | if (bat_priv->curr_gw == gw_node) | ||
325 | gw_deselect(bat_priv); | ||
326 | |||
327 | hlist_del_rcu(&gw_node->list); | ||
328 | call_rcu(&gw_node->rcu, gw_node_free_rcu); | ||
329 | } | ||
330 | |||
331 | |||
332 | spin_unlock_bh(&bat_priv->gw_list_lock); | ||
333 | } | ||
334 | |||
335 | static int _write_buffer_text(struct bat_priv *bat_priv, | ||
336 | struct seq_file *seq, struct gw_node *gw_node) | ||
337 | { | ||
338 | int down, up; | ||
339 | |||
340 | gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); | ||
341 | |||
342 | return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", | ||
343 | (bat_priv->curr_gw == gw_node ? "=>" : " "), | ||
344 | gw_node->orig_node->orig, | ||
345 | gw_node->orig_node->router->tq_avg, | ||
346 | gw_node->orig_node->router->addr, | ||
347 | gw_node->orig_node->router->if_incoming->net_dev->name, | ||
348 | gw_node->orig_node->gw_flags, | ||
349 | (down > 2048 ? down / 1024 : down), | ||
350 | (down > 2048 ? "MBit" : "KBit"), | ||
351 | (up > 2048 ? up / 1024 : up), | ||
352 | (up > 2048 ? "MBit" : "KBit")); | ||
353 | } | ||
354 | |||
355 | int gw_client_seq_print_text(struct seq_file *seq, void *offset) | ||
356 | { | ||
357 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
358 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
359 | struct gw_node *gw_node; | ||
360 | struct hlist_node *node; | ||
361 | int gw_count = 0; | ||
362 | |||
363 | if (!bat_priv->primary_if) { | ||
364 | |||
365 | return seq_printf(seq, "BATMAN mesh %s disabled - please " | ||
366 | "specify interfaces to enable it\n", | ||
367 | net_dev->name); | ||
368 | } | ||
369 | |||
370 | if (bat_priv->primary_if->if_status != IF_ACTIVE) { | ||
371 | |||
372 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
373 | "primary interface not active\n", | ||
374 | net_dev->name); | ||
375 | } | ||
376 | |||
377 | seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " | ||
378 | "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", | ||
379 | "Gateway", "#", TQ_MAX_VALUE, "Nexthop", | ||
380 | "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, | ||
381 | bat_priv->primary_if->net_dev->name, | ||
382 | bat_priv->primary_if->net_dev->dev_addr, net_dev->name); | ||
383 | |||
384 | rcu_read_lock(); | ||
385 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | ||
386 | if (gw_node->deleted) | ||
387 | continue; | ||
388 | |||
389 | if (!gw_node->orig_node->router) | ||
390 | continue; | ||
391 | |||
392 | _write_buffer_text(bat_priv, seq, gw_node); | ||
393 | gw_count++; | ||
394 | } | ||
395 | rcu_read_unlock(); | ||
396 | |||
397 | if (gw_count == 0) | ||
398 | seq_printf(seq, "No gateways in range ...\n"); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) | ||
404 | { | ||
405 | struct ethhdr *ethhdr; | ||
406 | struct iphdr *iphdr; | ||
407 | struct ipv6hdr *ipv6hdr; | ||
408 | struct udphdr *udphdr; | ||
409 | unsigned int header_len = 0; | ||
410 | |||
411 | if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) | ||
412 | return 0; | ||
413 | |||
414 | /* check for ethernet header */ | ||
415 | if (!pskb_may_pull(skb, header_len + ETH_HLEN)) | ||
416 | return 0; | ||
417 | ethhdr = (struct ethhdr *)skb->data; | ||
418 | header_len += ETH_HLEN; | ||
419 | |||
420 | /* check for initial vlan header */ | ||
421 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { | ||
422 | if (!pskb_may_pull(skb, header_len + VLAN_HLEN)) | ||
423 | return 0; | ||
424 | ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); | ||
425 | header_len += VLAN_HLEN; | ||
426 | } | ||
427 | |||
428 | /* check for ip header */ | ||
429 | switch (ntohs(ethhdr->h_proto)) { | ||
430 | case ETH_P_IP: | ||
431 | if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) | ||
432 | return 0; | ||
433 | iphdr = (struct iphdr *)(skb->data + header_len); | ||
434 | header_len += iphdr->ihl * 4; | ||
435 | |||
436 | /* check for udp header */ | ||
437 | if (iphdr->protocol != IPPROTO_UDP) | ||
438 | return 0; | ||
439 | |||
440 | break; | ||
441 | case ETH_P_IPV6: | ||
442 | if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr))) | ||
443 | return 0; | ||
444 | ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); | ||
445 | header_len += sizeof(struct ipv6hdr); | ||
446 | |||
447 | /* check for udp header */ | ||
448 | if (ipv6hdr->nexthdr != IPPROTO_UDP) | ||
449 | return 0; | ||
450 | |||
451 | break; | ||
452 | default: | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) | ||
457 | return 0; | ||
458 | udphdr = (struct udphdr *)(skb->data + header_len); | ||
459 | header_len += sizeof(struct udphdr); | ||
460 | |||
461 | /* check for bootp port */ | ||
462 | if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && | ||
463 | (ntohs(udphdr->dest) != 67)) | ||
464 | return 0; | ||
465 | |||
466 | if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && | ||
467 | (ntohs(udphdr->dest) != 547)) | ||
468 | return 0; | ||
469 | |||
470 | if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) | ||
471 | return -1; | ||
472 | |||
473 | if (!bat_priv->curr_gw) | ||
474 | return 0; | ||
475 | |||
476 | return 1; | ||
477 | } | ||
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h new file mode 100644 index 000000000000..4585e6549844 --- /dev/null +++ b/net/batman-adv/gateway_client.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ | ||
23 | #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ | ||
24 | |||
25 | void gw_deselect(struct bat_priv *bat_priv); | ||
26 | void gw_election(struct bat_priv *bat_priv); | ||
27 | void *gw_get_selected(struct bat_priv *bat_priv); | ||
28 | void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); | ||
29 | void gw_node_update(struct bat_priv *bat_priv, | ||
30 | struct orig_node *orig_node, uint8_t new_gwflags); | ||
31 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); | ||
32 | void gw_node_purge(struct bat_priv *bat_priv); | ||
33 | int gw_client_seq_print_text(struct seq_file *seq, void *offset); | ||
34 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); | ||
35 | |||
36 | #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ | ||
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c new file mode 100644 index 000000000000..b962982f017e --- /dev/null +++ b/net/batman-adv/gateway_common.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "gateway_common.h" | ||
24 | #include "gateway_client.h" | ||
25 | |||
26 | /* calculates the gateway class from kbit */ | ||
27 | static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) | ||
28 | { | ||
29 | int mdown = 0, tdown, tup, difference; | ||
30 | uint8_t sbit, part; | ||
31 | |||
32 | *gw_srv_class = 0; | ||
33 | difference = 0x0FFFFFFF; | ||
34 | |||
35 | /* test all downspeeds */ | ||
36 | for (sbit = 0; sbit < 2; sbit++) { | ||
37 | for (part = 0; part < 16; part++) { | ||
38 | tdown = 32 * (sbit + 2) * (1 << part); | ||
39 | |||
40 | if (abs(tdown - down) < difference) { | ||
41 | *gw_srv_class = (sbit << 7) + (part << 3); | ||
42 | difference = abs(tdown - down); | ||
43 | mdown = tdown; | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | |||
48 | /* test all upspeeds */ | ||
49 | difference = 0x0FFFFFFF; | ||
50 | |||
51 | for (part = 0; part < 8; part++) { | ||
52 | tup = ((part + 1) * (mdown)) / 8; | ||
53 | |||
54 | if (abs(tup - up) < difference) { | ||
55 | *gw_srv_class = (*gw_srv_class & 0xF8) | part; | ||
56 | difference = abs(tup - up); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /* returns the up and downspeeds in kbit, calculated from the class */ | ||
62 | void gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) | ||
63 | { | ||
64 | char sbit = (gw_srv_class & 0x80) >> 7; | ||
65 | char dpart = (gw_srv_class & 0x78) >> 3; | ||
66 | char upart = (gw_srv_class & 0x07); | ||
67 | |||
68 | if (!gw_srv_class) { | ||
69 | *down = 0; | ||
70 | *up = 0; | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | *down = 32 * (sbit + 2) * (1 << dpart); | ||
75 | *up = ((upart + 1) * (*down)) / 8; | ||
76 | } | ||
77 | |||
78 | static bool parse_gw_bandwidth(struct net_device *net_dev, char *buff, | ||
79 | long *up, long *down) | ||
80 | { | ||
81 | int ret, multi = 1; | ||
82 | char *slash_ptr, *tmp_ptr; | ||
83 | |||
84 | slash_ptr = strchr(buff, '/'); | ||
85 | if (slash_ptr) | ||
86 | *slash_ptr = 0; | ||
87 | |||
88 | if (strlen(buff) > 4) { | ||
89 | tmp_ptr = buff + strlen(buff) - 4; | ||
90 | |||
91 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) | ||
92 | multi = 1024; | ||
93 | |||
94 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || | ||
95 | (multi > 1)) | ||
96 | *tmp_ptr = '\0'; | ||
97 | } | ||
98 | |||
99 | ret = strict_strtoul(buff, 10, down); | ||
100 | if (ret) { | ||
101 | bat_err(net_dev, | ||
102 | "Download speed of gateway mode invalid: %s\n", | ||
103 | buff); | ||
104 | return false; | ||
105 | } | ||
106 | |||
107 | *down *= multi; | ||
108 | |||
109 | /* we also got some upload info */ | ||
110 | if (slash_ptr) { | ||
111 | multi = 1; | ||
112 | |||
113 | if (strlen(slash_ptr + 1) > 4) { | ||
114 | tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); | ||
115 | |||
116 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) | ||
117 | multi = 1024; | ||
118 | |||
119 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || | ||
120 | (multi > 1)) | ||
121 | *tmp_ptr = '\0'; | ||
122 | } | ||
123 | |||
124 | ret = strict_strtoul(slash_ptr + 1, 10, up); | ||
125 | if (ret) { | ||
126 | bat_err(net_dev, | ||
127 | "Upload speed of gateway mode invalid: " | ||
128 | "%s\n", slash_ptr + 1); | ||
129 | return false; | ||
130 | } | ||
131 | |||
132 | *up *= multi; | ||
133 | } | ||
134 | |||
135 | return true; | ||
136 | } | ||
137 | |||
138 | ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) | ||
139 | { | ||
140 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
141 | long gw_bandwidth_tmp = 0, up = 0, down = 0; | ||
142 | bool ret; | ||
143 | |||
144 | ret = parse_gw_bandwidth(net_dev, buff, &up, &down); | ||
145 | if (!ret) | ||
146 | goto end; | ||
147 | |||
148 | if ((!down) || (down < 256)) | ||
149 | down = 2000; | ||
150 | |||
151 | if (!up) | ||
152 | up = down / 5; | ||
153 | |||
154 | kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); | ||
155 | |||
156 | /** | ||
157 | * the gw bandwidth we guessed above might not match the given | ||
158 | * speeds, hence we need to calculate it back to show the number | ||
159 | * that is going to be propagated | ||
160 | **/ | ||
161 | gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, | ||
162 | (int *)&down, (int *)&up); | ||
163 | |||
164 | gw_deselect(bat_priv); | ||
165 | bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " | ||
166 | "(propagating: %ld%s/%ld%s)\n", | ||
167 | atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, | ||
168 | (down > 2048 ? down / 1024 : down), | ||
169 | (down > 2048 ? "MBit" : "KBit"), | ||
170 | (up > 2048 ? up / 1024 : up), | ||
171 | (up > 2048 ? "MBit" : "KBit")); | ||
172 | |||
173 | atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); | ||
174 | |||
175 | end: | ||
176 | return count; | ||
177 | } | ||
diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h new file mode 100644 index 000000000000..5e728d0b7959 --- /dev/null +++ b/net/batman-adv/gateway_common.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_ | ||
23 | #define _NET_BATMAN_ADV_GATEWAY_COMMON_H_ | ||
24 | |||
25 | enum gw_modes { | ||
26 | GW_MODE_OFF, | ||
27 | GW_MODE_CLIENT, | ||
28 | GW_MODE_SERVER, | ||
29 | }; | ||
30 | |||
31 | #define GW_MODE_OFF_NAME "off" | ||
32 | #define GW_MODE_CLIENT_NAME "client" | ||
33 | #define GW_MODE_SERVER_NAME "server" | ||
34 | |||
35 | void gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); | ||
36 | ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count); | ||
37 | |||
38 | #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ | ||
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c new file mode 100644 index 000000000000..4f95777ce080 --- /dev/null +++ b/net/batman-adv/hard-interface.c | |||
@@ -0,0 +1,651 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "hard-interface.h" | ||
24 | #include "soft-interface.h" | ||
25 | #include "send.h" | ||
26 | #include "translation-table.h" | ||
27 | #include "routing.h" | ||
28 | #include "bat_sysfs.h" | ||
29 | #include "originator.h" | ||
30 | #include "hash.h" | ||
31 | |||
32 | #include <linux/if_arp.h> | ||
33 | |||
34 | /* protect update critical side of if_list - but not the content */ | ||
35 | static DEFINE_SPINLOCK(if_list_lock); | ||
36 | |||
37 | static void hardif_free_rcu(struct rcu_head *rcu) | ||
38 | { | ||
39 | struct batman_if *batman_if; | ||
40 | |||
41 | batman_if = container_of(rcu, struct batman_if, rcu); | ||
42 | dev_put(batman_if->net_dev); | ||
43 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
44 | } | ||
45 | |||
46 | struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev) | ||
47 | { | ||
48 | struct batman_if *batman_if; | ||
49 | |||
50 | rcu_read_lock(); | ||
51 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
52 | if (batman_if->net_dev == net_dev) | ||
53 | goto out; | ||
54 | } | ||
55 | |||
56 | batman_if = NULL; | ||
57 | |||
58 | out: | ||
59 | if (batman_if) | ||
60 | kref_get(&batman_if->refcount); | ||
61 | |||
62 | rcu_read_unlock(); | ||
63 | return batman_if; | ||
64 | } | ||
65 | |||
66 | static int is_valid_iface(struct net_device *net_dev) | ||
67 | { | ||
68 | if (net_dev->flags & IFF_LOOPBACK) | ||
69 | return 0; | ||
70 | |||
71 | if (net_dev->type != ARPHRD_ETHER) | ||
72 | return 0; | ||
73 | |||
74 | if (net_dev->addr_len != ETH_ALEN) | ||
75 | return 0; | ||
76 | |||
77 | /* no batman over batman */ | ||
78 | #ifdef HAVE_NET_DEVICE_OPS | ||
79 | if (net_dev->netdev_ops->ndo_start_xmit == interface_tx) | ||
80 | return 0; | ||
81 | #else | ||
82 | if (net_dev->hard_start_xmit == interface_tx) | ||
83 | return 0; | ||
84 | #endif | ||
85 | |||
86 | /* Device is being bridged */ | ||
87 | /* if (net_dev->priv_flags & IFF_BRIDGE_PORT) | ||
88 | return 0; */ | ||
89 | |||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | static struct batman_if *get_active_batman_if(struct net_device *soft_iface) | ||
94 | { | ||
95 | struct batman_if *batman_if; | ||
96 | |||
97 | rcu_read_lock(); | ||
98 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
99 | if (batman_if->soft_iface != soft_iface) | ||
100 | continue; | ||
101 | |||
102 | if (batman_if->if_status == IF_ACTIVE) | ||
103 | goto out; | ||
104 | } | ||
105 | |||
106 | batman_if = NULL; | ||
107 | |||
108 | out: | ||
109 | if (batman_if) | ||
110 | kref_get(&batman_if->refcount); | ||
111 | |||
112 | rcu_read_unlock(); | ||
113 | return batman_if; | ||
114 | } | ||
115 | |||
116 | static void update_primary_addr(struct bat_priv *bat_priv) | ||
117 | { | ||
118 | struct vis_packet *vis_packet; | ||
119 | |||
120 | vis_packet = (struct vis_packet *) | ||
121 | bat_priv->my_vis_info->skb_packet->data; | ||
122 | memcpy(vis_packet->vis_orig, | ||
123 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
124 | memcpy(vis_packet->sender_orig, | ||
125 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
126 | } | ||
127 | |||
128 | static void set_primary_if(struct bat_priv *bat_priv, | ||
129 | struct batman_if *batman_if) | ||
130 | { | ||
131 | struct batman_packet *batman_packet; | ||
132 | struct batman_if *old_if; | ||
133 | |||
134 | if (batman_if) | ||
135 | kref_get(&batman_if->refcount); | ||
136 | |||
137 | old_if = bat_priv->primary_if; | ||
138 | bat_priv->primary_if = batman_if; | ||
139 | |||
140 | if (old_if) | ||
141 | kref_put(&old_if->refcount, hardif_free_ref); | ||
142 | |||
143 | if (!bat_priv->primary_if) | ||
144 | return; | ||
145 | |||
146 | batman_packet = (struct batman_packet *)(batman_if->packet_buff); | ||
147 | batman_packet->flags = PRIMARIES_FIRST_HOP; | ||
148 | batman_packet->ttl = TTL; | ||
149 | |||
150 | update_primary_addr(bat_priv); | ||
151 | |||
152 | /*** | ||
153 | * hacky trick to make sure that we send the HNA information via | ||
154 | * our new primary interface | ||
155 | */ | ||
156 | atomic_set(&bat_priv->hna_local_changed, 1); | ||
157 | } | ||
158 | |||
159 | static bool hardif_is_iface_up(struct batman_if *batman_if) | ||
160 | { | ||
161 | if (batman_if->net_dev->flags & IFF_UP) | ||
162 | return true; | ||
163 | |||
164 | return false; | ||
165 | } | ||
166 | |||
167 | static void update_mac_addresses(struct batman_if *batman_if) | ||
168 | { | ||
169 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, | ||
170 | batman_if->net_dev->dev_addr, ETH_ALEN); | ||
171 | memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender, | ||
172 | batman_if->net_dev->dev_addr, ETH_ALEN); | ||
173 | } | ||
174 | |||
175 | static void check_known_mac_addr(struct net_device *net_dev) | ||
176 | { | ||
177 | struct batman_if *batman_if; | ||
178 | |||
179 | rcu_read_lock(); | ||
180 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
181 | if ((batman_if->if_status != IF_ACTIVE) && | ||
182 | (batman_if->if_status != IF_TO_BE_ACTIVATED)) | ||
183 | continue; | ||
184 | |||
185 | if (batman_if->net_dev == net_dev) | ||
186 | continue; | ||
187 | |||
188 | if (!compare_orig(batman_if->net_dev->dev_addr, | ||
189 | net_dev->dev_addr)) | ||
190 | continue; | ||
191 | |||
192 | pr_warning("The newly added mac address (%pM) already exists " | ||
193 | "on: %s\n", net_dev->dev_addr, | ||
194 | batman_if->net_dev->name); | ||
195 | pr_warning("It is strongly recommended to keep mac addresses " | ||
196 | "unique to avoid problems!\n"); | ||
197 | } | ||
198 | rcu_read_unlock(); | ||
199 | } | ||
200 | |||
201 | int hardif_min_mtu(struct net_device *soft_iface) | ||
202 | { | ||
203 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
204 | struct batman_if *batman_if; | ||
205 | /* allow big frames if all devices are capable to do so | ||
206 | * (have MTU > 1500 + BAT_HEADER_LEN) */ | ||
207 | int min_mtu = ETH_DATA_LEN; | ||
208 | |||
209 | if (atomic_read(&bat_priv->fragmentation)) | ||
210 | goto out; | ||
211 | |||
212 | rcu_read_lock(); | ||
213 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
214 | if ((batman_if->if_status != IF_ACTIVE) && | ||
215 | (batman_if->if_status != IF_TO_BE_ACTIVATED)) | ||
216 | continue; | ||
217 | |||
218 | if (batman_if->soft_iface != soft_iface) | ||
219 | continue; | ||
220 | |||
221 | min_mtu = min_t(int, batman_if->net_dev->mtu - BAT_HEADER_LEN, | ||
222 | min_mtu); | ||
223 | } | ||
224 | rcu_read_unlock(); | ||
225 | out: | ||
226 | return min_mtu; | ||
227 | } | ||
228 | |||
229 | /* adjusts the MTU if a new interface with a smaller MTU appeared. */ | ||
230 | void update_min_mtu(struct net_device *soft_iface) | ||
231 | { | ||
232 | int min_mtu; | ||
233 | |||
234 | min_mtu = hardif_min_mtu(soft_iface); | ||
235 | if (soft_iface->mtu != min_mtu) | ||
236 | soft_iface->mtu = min_mtu; | ||
237 | } | ||
238 | |||
239 | static void hardif_activate_interface(struct batman_if *batman_if) | ||
240 | { | ||
241 | struct bat_priv *bat_priv; | ||
242 | |||
243 | if (batman_if->if_status != IF_INACTIVE) | ||
244 | return; | ||
245 | |||
246 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
247 | |||
248 | update_mac_addresses(batman_if); | ||
249 | batman_if->if_status = IF_TO_BE_ACTIVATED; | ||
250 | |||
251 | /** | ||
252 | * the first active interface becomes our primary interface or | ||
253 | * the next active interface after the old primay interface was removed | ||
254 | */ | ||
255 | if (!bat_priv->primary_if) | ||
256 | set_primary_if(bat_priv, batman_if); | ||
257 | |||
258 | bat_info(batman_if->soft_iface, "Interface activated: %s\n", | ||
259 | batman_if->net_dev->name); | ||
260 | |||
261 | update_min_mtu(batman_if->soft_iface); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | static void hardif_deactivate_interface(struct batman_if *batman_if) | ||
266 | { | ||
267 | if ((batman_if->if_status != IF_ACTIVE) && | ||
268 | (batman_if->if_status != IF_TO_BE_ACTIVATED)) | ||
269 | return; | ||
270 | |||
271 | batman_if->if_status = IF_INACTIVE; | ||
272 | |||
273 | bat_info(batman_if->soft_iface, "Interface deactivated: %s\n", | ||
274 | batman_if->net_dev->name); | ||
275 | |||
276 | update_min_mtu(batman_if->soft_iface); | ||
277 | } | ||
278 | |||
279 | int hardif_enable_interface(struct batman_if *batman_if, char *iface_name) | ||
280 | { | ||
281 | struct bat_priv *bat_priv; | ||
282 | struct batman_packet *batman_packet; | ||
283 | |||
284 | if (batman_if->if_status != IF_NOT_IN_USE) | ||
285 | goto out; | ||
286 | |||
287 | batman_if->soft_iface = dev_get_by_name(&init_net, iface_name); | ||
288 | |||
289 | if (!batman_if->soft_iface) { | ||
290 | batman_if->soft_iface = softif_create(iface_name); | ||
291 | |||
292 | if (!batman_if->soft_iface) | ||
293 | goto err; | ||
294 | |||
295 | /* dev_get_by_name() increases the reference counter for us */ | ||
296 | dev_hold(batman_if->soft_iface); | ||
297 | } | ||
298 | |||
299 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
300 | batman_if->packet_len = BAT_PACKET_LEN; | ||
301 | batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC); | ||
302 | |||
303 | if (!batman_if->packet_buff) { | ||
304 | bat_err(batman_if->soft_iface, "Can't add interface packet " | ||
305 | "(%s): out of memory\n", batman_if->net_dev->name); | ||
306 | goto err; | ||
307 | } | ||
308 | |||
309 | batman_packet = (struct batman_packet *)(batman_if->packet_buff); | ||
310 | batman_packet->packet_type = BAT_PACKET; | ||
311 | batman_packet->version = COMPAT_VERSION; | ||
312 | batman_packet->flags = 0; | ||
313 | batman_packet->ttl = 2; | ||
314 | batman_packet->tq = TQ_MAX_VALUE; | ||
315 | batman_packet->num_hna = 0; | ||
316 | |||
317 | batman_if->if_num = bat_priv->num_ifaces; | ||
318 | bat_priv->num_ifaces++; | ||
319 | batman_if->if_status = IF_INACTIVE; | ||
320 | orig_hash_add_if(batman_if, bat_priv->num_ifaces); | ||
321 | |||
322 | batman_if->batman_adv_ptype.type = __constant_htons(ETH_P_BATMAN); | ||
323 | batman_if->batman_adv_ptype.func = batman_skb_recv; | ||
324 | batman_if->batman_adv_ptype.dev = batman_if->net_dev; | ||
325 | kref_get(&batman_if->refcount); | ||
326 | dev_add_pack(&batman_if->batman_adv_ptype); | ||
327 | |||
328 | atomic_set(&batman_if->seqno, 1); | ||
329 | atomic_set(&batman_if->frag_seqno, 1); | ||
330 | bat_info(batman_if->soft_iface, "Adding interface: %s\n", | ||
331 | batman_if->net_dev->name); | ||
332 | |||
333 | if (atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < | ||
334 | ETH_DATA_LEN + BAT_HEADER_LEN) | ||
335 | bat_info(batman_if->soft_iface, | ||
336 | "The MTU of interface %s is too small (%i) to handle " | ||
337 | "the transport of batman-adv packets. Packets going " | ||
338 | "over this interface will be fragmented on layer2 " | ||
339 | "which could impact the performance. Setting the MTU " | ||
340 | "to %zi would solve the problem.\n", | ||
341 | batman_if->net_dev->name, batman_if->net_dev->mtu, | ||
342 | ETH_DATA_LEN + BAT_HEADER_LEN); | ||
343 | |||
344 | if (!atomic_read(&bat_priv->fragmentation) && batman_if->net_dev->mtu < | ||
345 | ETH_DATA_LEN + BAT_HEADER_LEN) | ||
346 | bat_info(batman_if->soft_iface, | ||
347 | "The MTU of interface %s is too small (%i) to handle " | ||
348 | "the transport of batman-adv packets. If you experience" | ||
349 | " problems getting traffic through try increasing the " | ||
350 | "MTU to %zi.\n", | ||
351 | batman_if->net_dev->name, batman_if->net_dev->mtu, | ||
352 | ETH_DATA_LEN + BAT_HEADER_LEN); | ||
353 | |||
354 | if (hardif_is_iface_up(batman_if)) | ||
355 | hardif_activate_interface(batman_if); | ||
356 | else | ||
357 | bat_err(batman_if->soft_iface, "Not using interface %s " | ||
358 | "(retrying later): interface not active\n", | ||
359 | batman_if->net_dev->name); | ||
360 | |||
361 | /* begin scheduling originator messages on that interface */ | ||
362 | schedule_own_packet(batman_if); | ||
363 | |||
364 | out: | ||
365 | return 0; | ||
366 | |||
367 | err: | ||
368 | return -ENOMEM; | ||
369 | } | ||
370 | |||
371 | void hardif_disable_interface(struct batman_if *batman_if) | ||
372 | { | ||
373 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
374 | |||
375 | if (batman_if->if_status == IF_ACTIVE) | ||
376 | hardif_deactivate_interface(batman_if); | ||
377 | |||
378 | if (batman_if->if_status != IF_INACTIVE) | ||
379 | return; | ||
380 | |||
381 | bat_info(batman_if->soft_iface, "Removing interface: %s\n", | ||
382 | batman_if->net_dev->name); | ||
383 | dev_remove_pack(&batman_if->batman_adv_ptype); | ||
384 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
385 | |||
386 | bat_priv->num_ifaces--; | ||
387 | orig_hash_del_if(batman_if, bat_priv->num_ifaces); | ||
388 | |||
389 | if (batman_if == bat_priv->primary_if) { | ||
390 | struct batman_if *new_if; | ||
391 | |||
392 | new_if = get_active_batman_if(batman_if->soft_iface); | ||
393 | set_primary_if(bat_priv, new_if); | ||
394 | |||
395 | if (new_if) | ||
396 | kref_put(&new_if->refcount, hardif_free_ref); | ||
397 | } | ||
398 | |||
399 | kfree(batman_if->packet_buff); | ||
400 | batman_if->packet_buff = NULL; | ||
401 | batman_if->if_status = IF_NOT_IN_USE; | ||
402 | |||
403 | /* delete all references to this batman_if */ | ||
404 | purge_orig_ref(bat_priv); | ||
405 | purge_outstanding_packets(bat_priv, batman_if); | ||
406 | dev_put(batman_if->soft_iface); | ||
407 | |||
408 | /* nobody uses this interface anymore */ | ||
409 | if (!bat_priv->num_ifaces) | ||
410 | softif_destroy(batman_if->soft_iface); | ||
411 | |||
412 | batman_if->soft_iface = NULL; | ||
413 | } | ||
414 | |||
415 | static struct batman_if *hardif_add_interface(struct net_device *net_dev) | ||
416 | { | ||
417 | struct batman_if *batman_if; | ||
418 | int ret; | ||
419 | |||
420 | ret = is_valid_iface(net_dev); | ||
421 | if (ret != 1) | ||
422 | goto out; | ||
423 | |||
424 | dev_hold(net_dev); | ||
425 | |||
426 | batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC); | ||
427 | if (!batman_if) { | ||
428 | pr_err("Can't add interface (%s): out of memory\n", | ||
429 | net_dev->name); | ||
430 | goto release_dev; | ||
431 | } | ||
432 | |||
433 | ret = sysfs_add_hardif(&batman_if->hardif_obj, net_dev); | ||
434 | if (ret) | ||
435 | goto free_if; | ||
436 | |||
437 | batman_if->if_num = -1; | ||
438 | batman_if->net_dev = net_dev; | ||
439 | batman_if->soft_iface = NULL; | ||
440 | batman_if->if_status = IF_NOT_IN_USE; | ||
441 | INIT_LIST_HEAD(&batman_if->list); | ||
442 | kref_init(&batman_if->refcount); | ||
443 | |||
444 | check_known_mac_addr(batman_if->net_dev); | ||
445 | |||
446 | spin_lock(&if_list_lock); | ||
447 | list_add_tail_rcu(&batman_if->list, &if_list); | ||
448 | spin_unlock(&if_list_lock); | ||
449 | |||
450 | /* extra reference for return */ | ||
451 | kref_get(&batman_if->refcount); | ||
452 | return batman_if; | ||
453 | |||
454 | free_if: | ||
455 | kfree(batman_if); | ||
456 | release_dev: | ||
457 | dev_put(net_dev); | ||
458 | out: | ||
459 | return NULL; | ||
460 | } | ||
461 | |||
462 | static void hardif_remove_interface(struct batman_if *batman_if) | ||
463 | { | ||
464 | /* first deactivate interface */ | ||
465 | if (batman_if->if_status != IF_NOT_IN_USE) | ||
466 | hardif_disable_interface(batman_if); | ||
467 | |||
468 | if (batman_if->if_status != IF_NOT_IN_USE) | ||
469 | return; | ||
470 | |||
471 | batman_if->if_status = IF_TO_BE_REMOVED; | ||
472 | sysfs_del_hardif(&batman_if->hardif_obj); | ||
473 | call_rcu(&batman_if->rcu, hardif_free_rcu); | ||
474 | } | ||
475 | |||
476 | void hardif_remove_interfaces(void) | ||
477 | { | ||
478 | struct batman_if *batman_if, *batman_if_tmp; | ||
479 | struct list_head if_queue; | ||
480 | |||
481 | INIT_LIST_HEAD(&if_queue); | ||
482 | |||
483 | spin_lock(&if_list_lock); | ||
484 | list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { | ||
485 | list_del_rcu(&batman_if->list); | ||
486 | list_add_tail(&batman_if->list, &if_queue); | ||
487 | } | ||
488 | spin_unlock(&if_list_lock); | ||
489 | |||
490 | rtnl_lock(); | ||
491 | list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) { | ||
492 | hardif_remove_interface(batman_if); | ||
493 | } | ||
494 | rtnl_unlock(); | ||
495 | } | ||
496 | |||
497 | static int hard_if_event(struct notifier_block *this, | ||
498 | unsigned long event, void *ptr) | ||
499 | { | ||
500 | struct net_device *net_dev = (struct net_device *)ptr; | ||
501 | struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); | ||
502 | struct bat_priv *bat_priv; | ||
503 | |||
504 | if (!batman_if && event == NETDEV_REGISTER) | ||
505 | batman_if = hardif_add_interface(net_dev); | ||
506 | |||
507 | if (!batman_if) | ||
508 | goto out; | ||
509 | |||
510 | switch (event) { | ||
511 | case NETDEV_UP: | ||
512 | hardif_activate_interface(batman_if); | ||
513 | break; | ||
514 | case NETDEV_GOING_DOWN: | ||
515 | case NETDEV_DOWN: | ||
516 | hardif_deactivate_interface(batman_if); | ||
517 | break; | ||
518 | case NETDEV_UNREGISTER: | ||
519 | spin_lock(&if_list_lock); | ||
520 | list_del_rcu(&batman_if->list); | ||
521 | spin_unlock(&if_list_lock); | ||
522 | |||
523 | hardif_remove_interface(batman_if); | ||
524 | break; | ||
525 | case NETDEV_CHANGEMTU: | ||
526 | if (batman_if->soft_iface) | ||
527 | update_min_mtu(batman_if->soft_iface); | ||
528 | break; | ||
529 | case NETDEV_CHANGEADDR: | ||
530 | if (batman_if->if_status == IF_NOT_IN_USE) | ||
531 | goto hardif_put; | ||
532 | |||
533 | check_known_mac_addr(batman_if->net_dev); | ||
534 | update_mac_addresses(batman_if); | ||
535 | |||
536 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
537 | if (batman_if == bat_priv->primary_if) | ||
538 | update_primary_addr(bat_priv); | ||
539 | break; | ||
540 | default: | ||
541 | break; | ||
542 | }; | ||
543 | |||
544 | hardif_put: | ||
545 | kref_put(&batman_if->refcount, hardif_free_ref); | ||
546 | out: | ||
547 | return NOTIFY_DONE; | ||
548 | } | ||
549 | |||
550 | /* receive a packet with the batman ethertype coming on a hard | ||
551 | * interface */ | ||
552 | int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, | ||
553 | struct packet_type *ptype, struct net_device *orig_dev) | ||
554 | { | ||
555 | struct bat_priv *bat_priv; | ||
556 | struct batman_packet *batman_packet; | ||
557 | struct batman_if *batman_if; | ||
558 | int ret; | ||
559 | |||
560 | batman_if = container_of(ptype, struct batman_if, batman_adv_ptype); | ||
561 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
562 | |||
563 | /* skb was released by skb_share_check() */ | ||
564 | if (!skb) | ||
565 | goto err_out; | ||
566 | |||
567 | /* packet should hold at least type and version */ | ||
568 | if (unlikely(!pskb_may_pull(skb, 2))) | ||
569 | goto err_free; | ||
570 | |||
571 | /* expect a valid ethernet header here. */ | ||
572 | if (unlikely(skb->mac_len != sizeof(struct ethhdr) | ||
573 | || !skb_mac_header(skb))) | ||
574 | goto err_free; | ||
575 | |||
576 | if (!batman_if->soft_iface) | ||
577 | goto err_free; | ||
578 | |||
579 | bat_priv = netdev_priv(batman_if->soft_iface); | ||
580 | |||
581 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
582 | goto err_free; | ||
583 | |||
584 | /* discard frames on not active interfaces */ | ||
585 | if (batman_if->if_status != IF_ACTIVE) | ||
586 | goto err_free; | ||
587 | |||
588 | batman_packet = (struct batman_packet *)skb->data; | ||
589 | |||
590 | if (batman_packet->version != COMPAT_VERSION) { | ||
591 | bat_dbg(DBG_BATMAN, bat_priv, | ||
592 | "Drop packet: incompatible batman version (%i)\n", | ||
593 | batman_packet->version); | ||
594 | goto err_free; | ||
595 | } | ||
596 | |||
597 | /* all receive handlers return whether they received or reused | ||
598 | * the supplied skb. if not, we have to free the skb. */ | ||
599 | |||
600 | switch (batman_packet->packet_type) { | ||
601 | /* batman originator packet */ | ||
602 | case BAT_PACKET: | ||
603 | ret = recv_bat_packet(skb, batman_if); | ||
604 | break; | ||
605 | |||
606 | /* batman icmp packet */ | ||
607 | case BAT_ICMP: | ||
608 | ret = recv_icmp_packet(skb, batman_if); | ||
609 | break; | ||
610 | |||
611 | /* unicast packet */ | ||
612 | case BAT_UNICAST: | ||
613 | ret = recv_unicast_packet(skb, batman_if); | ||
614 | break; | ||
615 | |||
616 | /* fragmented unicast packet */ | ||
617 | case BAT_UNICAST_FRAG: | ||
618 | ret = recv_ucast_frag_packet(skb, batman_if); | ||
619 | break; | ||
620 | |||
621 | /* broadcast packet */ | ||
622 | case BAT_BCAST: | ||
623 | ret = recv_bcast_packet(skb, batman_if); | ||
624 | break; | ||
625 | |||
626 | /* vis packet */ | ||
627 | case BAT_VIS: | ||
628 | ret = recv_vis_packet(skb, batman_if); | ||
629 | break; | ||
630 | default: | ||
631 | ret = NET_RX_DROP; | ||
632 | } | ||
633 | |||
634 | if (ret == NET_RX_DROP) | ||
635 | kfree_skb(skb); | ||
636 | |||
637 | /* return NET_RX_SUCCESS in any case as we | ||
638 | * most probably dropped the packet for | ||
639 | * routing-logical reasons. */ | ||
640 | |||
641 | return NET_RX_SUCCESS; | ||
642 | |||
643 | err_free: | ||
644 | kfree_skb(skb); | ||
645 | err_out: | ||
646 | return NET_RX_DROP; | ||
647 | } | ||
648 | |||
649 | struct notifier_block hard_if_notifier = { | ||
650 | .notifier_call = hard_if_event, | ||
651 | }; | ||
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h new file mode 100644 index 000000000000..30ec3b8db459 --- /dev/null +++ b/net/batman-adv/hard-interface.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_ | ||
23 | #define _NET_BATMAN_ADV_HARD_INTERFACE_H_ | ||
24 | |||
25 | #define IF_NOT_IN_USE 0 | ||
26 | #define IF_TO_BE_REMOVED 1 | ||
27 | #define IF_INACTIVE 2 | ||
28 | #define IF_ACTIVE 3 | ||
29 | #define IF_TO_BE_ACTIVATED 4 | ||
30 | #define IF_I_WANT_YOU 5 | ||
31 | |||
32 | extern struct notifier_block hard_if_notifier; | ||
33 | |||
34 | struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev); | ||
35 | int hardif_enable_interface(struct batman_if *batman_if, char *iface_name); | ||
36 | void hardif_disable_interface(struct batman_if *batman_if); | ||
37 | void hardif_remove_interfaces(void); | ||
38 | int batman_skb_recv(struct sk_buff *skb, | ||
39 | struct net_device *dev, | ||
40 | struct packet_type *ptype, | ||
41 | struct net_device *orig_dev); | ||
42 | int hardif_min_mtu(struct net_device *soft_iface); | ||
43 | void update_min_mtu(struct net_device *soft_iface); | ||
44 | |||
45 | static inline void hardif_free_ref(struct kref *refcount) | ||
46 | { | ||
47 | struct batman_if *batman_if; | ||
48 | |||
49 | batman_if = container_of(refcount, struct batman_if, refcount); | ||
50 | kfree(batman_if); | ||
51 | } | ||
52 | |||
53 | #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ | ||
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c new file mode 100644 index 000000000000..26e623eb9def --- /dev/null +++ b/net/batman-adv/hash.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Simon Wunderlich, Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "hash.h" | ||
24 | |||
25 | /* clears the hash */ | ||
26 | static void hash_init(struct hashtable_t *hash) | ||
27 | { | ||
28 | int i; | ||
29 | |||
30 | for (i = 0 ; i < hash->size; i++) | ||
31 | INIT_HLIST_HEAD(&hash->table[i]); | ||
32 | } | ||
33 | |||
34 | /* free only the hashtable and the hash itself. */ | ||
35 | void hash_destroy(struct hashtable_t *hash) | ||
36 | { | ||
37 | kfree(hash->table); | ||
38 | kfree(hash); | ||
39 | } | ||
40 | |||
41 | /* allocates and clears the hash */ | ||
42 | struct hashtable_t *hash_new(int size) | ||
43 | { | ||
44 | struct hashtable_t *hash; | ||
45 | |||
46 | hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC); | ||
47 | |||
48 | if (!hash) | ||
49 | return NULL; | ||
50 | |||
51 | hash->size = size; | ||
52 | hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC); | ||
53 | |||
54 | if (!hash->table) { | ||
55 | kfree(hash); | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | hash_init(hash); | ||
60 | |||
61 | return hash; | ||
62 | } | ||
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h new file mode 100644 index 000000000000..09216ade16f1 --- /dev/null +++ b/net/batman-adv/hash.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Simon Wunderlich, Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_HASH_H_ | ||
23 | #define _NET_BATMAN_ADV_HASH_H_ | ||
24 | |||
25 | #include <linux/list.h> | ||
26 | |||
27 | /* callback to a compare function. should | ||
28 | * compare 2 element datas for their keys, | ||
29 | * return 0 if same and not 0 if not | ||
30 | * same */ | ||
31 | typedef int (*hashdata_compare_cb)(void *, void *); | ||
32 | |||
33 | /* the hashfunction, should return an index | ||
34 | * based on the key in the data of the first | ||
35 | * argument and the size the second */ | ||
36 | typedef int (*hashdata_choose_cb)(void *, int); | ||
37 | typedef void (*hashdata_free_cb)(void *, void *); | ||
38 | |||
39 | struct element_t { | ||
40 | void *data; /* pointer to the data */ | ||
41 | struct hlist_node hlist; /* bucket list pointer */ | ||
42 | }; | ||
43 | |||
44 | struct hashtable_t { | ||
45 | struct hlist_head *table; /* the hashtable itself, with the buckets */ | ||
46 | int size; /* size of hashtable */ | ||
47 | }; | ||
48 | |||
49 | /* allocates and clears the hash */ | ||
50 | struct hashtable_t *hash_new(int size); | ||
51 | |||
52 | /* remove element if you already found the element you want to delete and don't | ||
53 | * need the overhead to find it again with hash_remove(). But usually, you | ||
54 | * don't want to use this function, as it fiddles with hash-internals. */ | ||
55 | void *hash_remove_element(struct hashtable_t *hash, struct element_t *elem); | ||
56 | |||
57 | /* free only the hashtable and the hash itself. */ | ||
58 | void hash_destroy(struct hashtable_t *hash); | ||
59 | |||
60 | /* remove the hash structure. if hashdata_free_cb != NULL, this function will be | ||
61 | * called to remove the elements inside of the hash. if you don't remove the | ||
62 | * elements, memory might be leaked. */ | ||
63 | static inline void hash_delete(struct hashtable_t *hash, | ||
64 | hashdata_free_cb free_cb, void *arg) | ||
65 | { | ||
66 | struct hlist_head *head; | ||
67 | struct hlist_node *walk, *safe; | ||
68 | struct element_t *bucket; | ||
69 | int i; | ||
70 | |||
71 | for (i = 0; i < hash->size; i++) { | ||
72 | head = &hash->table[i]; | ||
73 | |||
74 | hlist_for_each_safe(walk, safe, head) { | ||
75 | bucket = hlist_entry(walk, struct element_t, hlist); | ||
76 | if (free_cb) | ||
77 | free_cb(bucket->data, arg); | ||
78 | |||
79 | hlist_del(walk); | ||
80 | kfree(bucket); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | hash_destroy(hash); | ||
85 | } | ||
86 | |||
87 | /* adds data to the hashtable. returns 0 on success, -1 on error */ | ||
88 | static inline int hash_add(struct hashtable_t *hash, | ||
89 | hashdata_compare_cb compare, | ||
90 | hashdata_choose_cb choose, void *data) | ||
91 | { | ||
92 | int index; | ||
93 | struct hlist_head *head; | ||
94 | struct hlist_node *walk, *safe; | ||
95 | struct element_t *bucket; | ||
96 | |||
97 | if (!hash) | ||
98 | return -1; | ||
99 | |||
100 | index = choose(data, hash->size); | ||
101 | head = &hash->table[index]; | ||
102 | |||
103 | hlist_for_each_safe(walk, safe, head) { | ||
104 | bucket = hlist_entry(walk, struct element_t, hlist); | ||
105 | if (compare(bucket->data, data)) | ||
106 | return -1; | ||
107 | } | ||
108 | |||
109 | /* no duplicate found in list, add new element */ | ||
110 | bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); | ||
111 | |||
112 | if (!bucket) | ||
113 | return -1; | ||
114 | |||
115 | bucket->data = data; | ||
116 | hlist_add_head(&bucket->hlist, head); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* removes data from hash, if found. returns pointer do data on success, so you | ||
122 | * can remove the used structure yourself, or NULL on error . data could be the | ||
123 | * structure you use with just the key filled, we just need the key for | ||
124 | * comparing. */ | ||
125 | static inline void *hash_remove(struct hashtable_t *hash, | ||
126 | hashdata_compare_cb compare, | ||
127 | hashdata_choose_cb choose, void *data) | ||
128 | { | ||
129 | size_t index; | ||
130 | struct hlist_node *walk; | ||
131 | struct element_t *bucket; | ||
132 | struct hlist_head *head; | ||
133 | void *data_save; | ||
134 | |||
135 | index = choose(data, hash->size); | ||
136 | head = &hash->table[index]; | ||
137 | |||
138 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
139 | if (compare(bucket->data, data)) { | ||
140 | data_save = bucket->data; | ||
141 | hlist_del(walk); | ||
142 | kfree(bucket); | ||
143 | return data_save; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | return NULL; | ||
148 | } | ||
149 | |||
150 | /* finds data, based on the key in keydata. returns the found data on success, | ||
151 | * or NULL on error */ | ||
152 | static inline void *hash_find(struct hashtable_t *hash, | ||
153 | hashdata_compare_cb compare, | ||
154 | hashdata_choose_cb choose, void *keydata) | ||
155 | { | ||
156 | int index; | ||
157 | struct hlist_head *head; | ||
158 | struct hlist_node *walk; | ||
159 | struct element_t *bucket; | ||
160 | |||
161 | if (!hash) | ||
162 | return NULL; | ||
163 | |||
164 | index = choose(keydata , hash->size); | ||
165 | head = &hash->table[index]; | ||
166 | |||
167 | hlist_for_each(walk, head) { | ||
168 | bucket = hlist_entry(walk, struct element_t, hlist); | ||
169 | if (compare(bucket->data, keydata)) | ||
170 | return bucket->data; | ||
171 | } | ||
172 | |||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | #endif /* _NET_BATMAN_ADV_HASH_H_ */ | ||
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c new file mode 100644 index 000000000000..ecf6d7ffab2e --- /dev/null +++ b/net/batman-adv/icmp_socket.c | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include <linux/debugfs.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include "icmp_socket.h" | ||
26 | #include "send.h" | ||
27 | #include "types.h" | ||
28 | #include "hash.h" | ||
29 | #include "originator.h" | ||
30 | #include "hard-interface.h" | ||
31 | |||
32 | static struct socket_client *socket_client_hash[256]; | ||
33 | |||
34 | static void bat_socket_add_packet(struct socket_client *socket_client, | ||
35 | struct icmp_packet_rr *icmp_packet, | ||
36 | size_t icmp_len); | ||
37 | |||
38 | void bat_socket_init(void) | ||
39 | { | ||
40 | memset(socket_client_hash, 0, sizeof(socket_client_hash)); | ||
41 | } | ||
42 | |||
43 | static int bat_socket_open(struct inode *inode, struct file *file) | ||
44 | { | ||
45 | unsigned int i; | ||
46 | struct socket_client *socket_client; | ||
47 | |||
48 | nonseekable_open(inode, file); | ||
49 | |||
50 | socket_client = kmalloc(sizeof(struct socket_client), GFP_KERNEL); | ||
51 | |||
52 | if (!socket_client) | ||
53 | return -ENOMEM; | ||
54 | |||
55 | for (i = 0; i < ARRAY_SIZE(socket_client_hash); i++) { | ||
56 | if (!socket_client_hash[i]) { | ||
57 | socket_client_hash[i] = socket_client; | ||
58 | break; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | if (i == ARRAY_SIZE(socket_client_hash)) { | ||
63 | pr_err("Error - can't add another packet client: " | ||
64 | "maximum number of clients reached\n"); | ||
65 | kfree(socket_client); | ||
66 | return -EXFULL; | ||
67 | } | ||
68 | |||
69 | INIT_LIST_HEAD(&socket_client->queue_list); | ||
70 | socket_client->queue_len = 0; | ||
71 | socket_client->index = i; | ||
72 | socket_client->bat_priv = inode->i_private; | ||
73 | spin_lock_init(&socket_client->lock); | ||
74 | init_waitqueue_head(&socket_client->queue_wait); | ||
75 | |||
76 | file->private_data = socket_client; | ||
77 | |||
78 | inc_module_count(); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int bat_socket_release(struct inode *inode, struct file *file) | ||
83 | { | ||
84 | struct socket_client *socket_client = file->private_data; | ||
85 | struct socket_packet *socket_packet; | ||
86 | struct list_head *list_pos, *list_pos_tmp; | ||
87 | |||
88 | spin_lock_bh(&socket_client->lock); | ||
89 | |||
90 | /* for all packets in the queue ... */ | ||
91 | list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) { | ||
92 | socket_packet = list_entry(list_pos, | ||
93 | struct socket_packet, list); | ||
94 | |||
95 | list_del(list_pos); | ||
96 | kfree(socket_packet); | ||
97 | } | ||
98 | |||
99 | socket_client_hash[socket_client->index] = NULL; | ||
100 | spin_unlock_bh(&socket_client->lock); | ||
101 | |||
102 | kfree(socket_client); | ||
103 | dec_module_count(); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static ssize_t bat_socket_read(struct file *file, char __user *buf, | ||
109 | size_t count, loff_t *ppos) | ||
110 | { | ||
111 | struct socket_client *socket_client = file->private_data; | ||
112 | struct socket_packet *socket_packet; | ||
113 | size_t packet_len; | ||
114 | int error; | ||
115 | |||
116 | if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0)) | ||
117 | return -EAGAIN; | ||
118 | |||
119 | if ((!buf) || (count < sizeof(struct icmp_packet))) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
123 | return -EFAULT; | ||
124 | |||
125 | error = wait_event_interruptible(socket_client->queue_wait, | ||
126 | socket_client->queue_len); | ||
127 | |||
128 | if (error) | ||
129 | return error; | ||
130 | |||
131 | spin_lock_bh(&socket_client->lock); | ||
132 | |||
133 | socket_packet = list_first_entry(&socket_client->queue_list, | ||
134 | struct socket_packet, list); | ||
135 | list_del(&socket_packet->list); | ||
136 | socket_client->queue_len--; | ||
137 | |||
138 | spin_unlock_bh(&socket_client->lock); | ||
139 | |||
140 | error = __copy_to_user(buf, &socket_packet->icmp_packet, | ||
141 | socket_packet->icmp_len); | ||
142 | |||
143 | packet_len = socket_packet->icmp_len; | ||
144 | kfree(socket_packet); | ||
145 | |||
146 | if (error) | ||
147 | return -EFAULT; | ||
148 | |||
149 | return packet_len; | ||
150 | } | ||
151 | |||
152 | static ssize_t bat_socket_write(struct file *file, const char __user *buff, | ||
153 | size_t len, loff_t *off) | ||
154 | { | ||
155 | struct socket_client *socket_client = file->private_data; | ||
156 | struct bat_priv *bat_priv = socket_client->bat_priv; | ||
157 | struct sk_buff *skb; | ||
158 | struct icmp_packet_rr *icmp_packet; | ||
159 | |||
160 | struct orig_node *orig_node; | ||
161 | struct batman_if *batman_if; | ||
162 | size_t packet_len = sizeof(struct icmp_packet); | ||
163 | uint8_t dstaddr[ETH_ALEN]; | ||
164 | |||
165 | if (len < sizeof(struct icmp_packet)) { | ||
166 | bat_dbg(DBG_BATMAN, bat_priv, | ||
167 | "Error - can't send packet from char device: " | ||
168 | "invalid packet size\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | if (!bat_priv->primary_if) | ||
173 | return -EFAULT; | ||
174 | |||
175 | if (len >= sizeof(struct icmp_packet_rr)) | ||
176 | packet_len = sizeof(struct icmp_packet_rr); | ||
177 | |||
178 | skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); | ||
179 | if (!skb) | ||
180 | return -ENOMEM; | ||
181 | |||
182 | skb_reserve(skb, sizeof(struct ethhdr)); | ||
183 | icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); | ||
184 | |||
185 | if (!access_ok(VERIFY_READ, buff, packet_len)) { | ||
186 | len = -EFAULT; | ||
187 | goto free_skb; | ||
188 | } | ||
189 | |||
190 | if (__copy_from_user(icmp_packet, buff, packet_len)) { | ||
191 | len = -EFAULT; | ||
192 | goto free_skb; | ||
193 | } | ||
194 | |||
195 | if (icmp_packet->packet_type != BAT_ICMP) { | ||
196 | bat_dbg(DBG_BATMAN, bat_priv, | ||
197 | "Error - can't send packet from char device: " | ||
198 | "got bogus packet type (expected: BAT_ICMP)\n"); | ||
199 | len = -EINVAL; | ||
200 | goto free_skb; | ||
201 | } | ||
202 | |||
203 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
204 | bat_dbg(DBG_BATMAN, bat_priv, | ||
205 | "Error - can't send packet from char device: " | ||
206 | "got bogus message type (expected: ECHO_REQUEST)\n"); | ||
207 | len = -EINVAL; | ||
208 | goto free_skb; | ||
209 | } | ||
210 | |||
211 | icmp_packet->uid = socket_client->index; | ||
212 | |||
213 | if (icmp_packet->version != COMPAT_VERSION) { | ||
214 | icmp_packet->msg_type = PARAMETER_PROBLEM; | ||
215 | icmp_packet->ttl = COMPAT_VERSION; | ||
216 | bat_socket_add_packet(socket_client, icmp_packet, packet_len); | ||
217 | goto free_skb; | ||
218 | } | ||
219 | |||
220 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
221 | goto dst_unreach; | ||
222 | |||
223 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
224 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
225 | compare_orig, choose_orig, | ||
226 | icmp_packet->dst)); | ||
227 | |||
228 | if (!orig_node) | ||
229 | goto unlock; | ||
230 | |||
231 | if (!orig_node->router) | ||
232 | goto unlock; | ||
233 | |||
234 | batman_if = orig_node->router->if_incoming; | ||
235 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
236 | |||
237 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
238 | |||
239 | if (!batman_if) | ||
240 | goto dst_unreach; | ||
241 | |||
242 | if (batman_if->if_status != IF_ACTIVE) | ||
243 | goto dst_unreach; | ||
244 | |||
245 | memcpy(icmp_packet->orig, | ||
246 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
247 | |||
248 | if (packet_len == sizeof(struct icmp_packet_rr)) | ||
249 | memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN); | ||
250 | |||
251 | |||
252 | send_skb_packet(skb, batman_if, dstaddr); | ||
253 | |||
254 | goto out; | ||
255 | |||
256 | unlock: | ||
257 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
258 | dst_unreach: | ||
259 | icmp_packet->msg_type = DESTINATION_UNREACHABLE; | ||
260 | bat_socket_add_packet(socket_client, icmp_packet, packet_len); | ||
261 | free_skb: | ||
262 | kfree_skb(skb); | ||
263 | out: | ||
264 | return len; | ||
265 | } | ||
266 | |||
267 | static unsigned int bat_socket_poll(struct file *file, poll_table *wait) | ||
268 | { | ||
269 | struct socket_client *socket_client = file->private_data; | ||
270 | |||
271 | poll_wait(file, &socket_client->queue_wait, wait); | ||
272 | |||
273 | if (socket_client->queue_len > 0) | ||
274 | return POLLIN | POLLRDNORM; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static const struct file_operations fops = { | ||
280 | .owner = THIS_MODULE, | ||
281 | .open = bat_socket_open, | ||
282 | .release = bat_socket_release, | ||
283 | .read = bat_socket_read, | ||
284 | .write = bat_socket_write, | ||
285 | .poll = bat_socket_poll, | ||
286 | .llseek = no_llseek, | ||
287 | }; | ||
288 | |||
289 | int bat_socket_setup(struct bat_priv *bat_priv) | ||
290 | { | ||
291 | struct dentry *d; | ||
292 | |||
293 | if (!bat_priv->debug_dir) | ||
294 | goto err; | ||
295 | |||
296 | d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, | ||
297 | bat_priv->debug_dir, bat_priv, &fops); | ||
298 | if (d) | ||
299 | goto err; | ||
300 | |||
301 | return 0; | ||
302 | |||
303 | err: | ||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static void bat_socket_add_packet(struct socket_client *socket_client, | ||
308 | struct icmp_packet_rr *icmp_packet, | ||
309 | size_t icmp_len) | ||
310 | { | ||
311 | struct socket_packet *socket_packet; | ||
312 | |||
313 | socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC); | ||
314 | |||
315 | if (!socket_packet) | ||
316 | return; | ||
317 | |||
318 | INIT_LIST_HEAD(&socket_packet->list); | ||
319 | memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len); | ||
320 | socket_packet->icmp_len = icmp_len; | ||
321 | |||
322 | spin_lock_bh(&socket_client->lock); | ||
323 | |||
324 | /* while waiting for the lock the socket_client could have been | ||
325 | * deleted */ | ||
326 | if (!socket_client_hash[icmp_packet->uid]) { | ||
327 | spin_unlock_bh(&socket_client->lock); | ||
328 | kfree(socket_packet); | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | list_add_tail(&socket_packet->list, &socket_client->queue_list); | ||
333 | socket_client->queue_len++; | ||
334 | |||
335 | if (socket_client->queue_len > 100) { | ||
336 | socket_packet = list_first_entry(&socket_client->queue_list, | ||
337 | struct socket_packet, list); | ||
338 | |||
339 | list_del(&socket_packet->list); | ||
340 | kfree(socket_packet); | ||
341 | socket_client->queue_len--; | ||
342 | } | ||
343 | |||
344 | spin_unlock_bh(&socket_client->lock); | ||
345 | |||
346 | wake_up(&socket_client->queue_wait); | ||
347 | } | ||
348 | |||
349 | void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet, | ||
350 | size_t icmp_len) | ||
351 | { | ||
352 | struct socket_client *hash = socket_client_hash[icmp_packet->uid]; | ||
353 | |||
354 | if (hash) | ||
355 | bat_socket_add_packet(hash, icmp_packet, icmp_len); | ||
356 | } | ||
diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h new file mode 100644 index 000000000000..bf9b348cde27 --- /dev/null +++ b/net/batman-adv/icmp_socket.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_ | ||
23 | #define _NET_BATMAN_ADV_ICMP_SOCKET_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | #define ICMP_SOCKET "socket" | ||
28 | |||
29 | void bat_socket_init(void); | ||
30 | int bat_socket_setup(struct bat_priv *bat_priv); | ||
31 | void bat_socket_receive_packet(struct icmp_packet_rr *icmp_packet, | ||
32 | size_t icmp_len); | ||
33 | |||
34 | #endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */ | ||
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c new file mode 100644 index 000000000000..b827f6a158cb --- /dev/null +++ b/net/batman-adv/main.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "bat_sysfs.h" | ||
24 | #include "bat_debugfs.h" | ||
25 | #include "routing.h" | ||
26 | #include "send.h" | ||
27 | #include "originator.h" | ||
28 | #include "soft-interface.h" | ||
29 | #include "icmp_socket.h" | ||
30 | #include "translation-table.h" | ||
31 | #include "hard-interface.h" | ||
32 | #include "gateway_client.h" | ||
33 | #include "types.h" | ||
34 | #include "vis.h" | ||
35 | #include "hash.h" | ||
36 | |||
37 | struct list_head if_list; | ||
38 | |||
39 | unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
40 | |||
41 | struct workqueue_struct *bat_event_workqueue; | ||
42 | |||
43 | static int __init batman_init(void) | ||
44 | { | ||
45 | INIT_LIST_HEAD(&if_list); | ||
46 | |||
47 | /* the name should not be longer than 10 chars - see | ||
48 | * http://lwn.net/Articles/23634/ */ | ||
49 | bat_event_workqueue = create_singlethread_workqueue("bat_events"); | ||
50 | |||
51 | if (!bat_event_workqueue) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | bat_socket_init(); | ||
55 | debugfs_init(); | ||
56 | |||
57 | register_netdevice_notifier(&hard_if_notifier); | ||
58 | |||
59 | pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) " | ||
60 | "loaded\n", SOURCE_VERSION, REVISION_VERSION_STR, | ||
61 | COMPAT_VERSION); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static void __exit batman_exit(void) | ||
67 | { | ||
68 | debugfs_destroy(); | ||
69 | unregister_netdevice_notifier(&hard_if_notifier); | ||
70 | hardif_remove_interfaces(); | ||
71 | |||
72 | flush_workqueue(bat_event_workqueue); | ||
73 | destroy_workqueue(bat_event_workqueue); | ||
74 | bat_event_workqueue = NULL; | ||
75 | |||
76 | rcu_barrier(); | ||
77 | } | ||
78 | |||
79 | int mesh_init(struct net_device *soft_iface) | ||
80 | { | ||
81 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
82 | |||
83 | spin_lock_init(&bat_priv->orig_hash_lock); | ||
84 | spin_lock_init(&bat_priv->forw_bat_list_lock); | ||
85 | spin_lock_init(&bat_priv->forw_bcast_list_lock); | ||
86 | spin_lock_init(&bat_priv->hna_lhash_lock); | ||
87 | spin_lock_init(&bat_priv->hna_ghash_lock); | ||
88 | spin_lock_init(&bat_priv->gw_list_lock); | ||
89 | spin_lock_init(&bat_priv->vis_hash_lock); | ||
90 | spin_lock_init(&bat_priv->vis_list_lock); | ||
91 | spin_lock_init(&bat_priv->softif_neigh_lock); | ||
92 | |||
93 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); | ||
94 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); | ||
95 | INIT_HLIST_HEAD(&bat_priv->gw_list); | ||
96 | INIT_HLIST_HEAD(&bat_priv->softif_neigh_list); | ||
97 | |||
98 | if (originator_init(bat_priv) < 1) | ||
99 | goto err; | ||
100 | |||
101 | if (hna_local_init(bat_priv) < 1) | ||
102 | goto err; | ||
103 | |||
104 | if (hna_global_init(bat_priv) < 1) | ||
105 | goto err; | ||
106 | |||
107 | hna_local_add(soft_iface, soft_iface->dev_addr); | ||
108 | |||
109 | if (vis_init(bat_priv) < 1) | ||
110 | goto err; | ||
111 | |||
112 | atomic_set(&bat_priv->mesh_state, MESH_ACTIVE); | ||
113 | goto end; | ||
114 | |||
115 | err: | ||
116 | pr_err("Unable to allocate memory for mesh information structures: " | ||
117 | "out of mem ?\n"); | ||
118 | mesh_free(soft_iface); | ||
119 | return -1; | ||
120 | |||
121 | end: | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | void mesh_free(struct net_device *soft_iface) | ||
126 | { | ||
127 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
128 | |||
129 | atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING); | ||
130 | |||
131 | purge_outstanding_packets(bat_priv, NULL); | ||
132 | |||
133 | vis_quit(bat_priv); | ||
134 | |||
135 | gw_node_purge(bat_priv); | ||
136 | originator_free(bat_priv); | ||
137 | |||
138 | hna_local_free(bat_priv); | ||
139 | hna_global_free(bat_priv); | ||
140 | |||
141 | softif_neigh_purge(bat_priv); | ||
142 | |||
143 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); | ||
144 | } | ||
145 | |||
146 | void inc_module_count(void) | ||
147 | { | ||
148 | try_module_get(THIS_MODULE); | ||
149 | } | ||
150 | |||
151 | void dec_module_count(void) | ||
152 | { | ||
153 | module_put(THIS_MODULE); | ||
154 | } | ||
155 | |||
156 | int is_my_mac(uint8_t *addr) | ||
157 | { | ||
158 | struct batman_if *batman_if; | ||
159 | |||
160 | rcu_read_lock(); | ||
161 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
162 | if (batman_if->if_status != IF_ACTIVE) | ||
163 | continue; | ||
164 | |||
165 | if (compare_orig(batman_if->net_dev->dev_addr, addr)) { | ||
166 | rcu_read_unlock(); | ||
167 | return 1; | ||
168 | } | ||
169 | } | ||
170 | rcu_read_unlock(); | ||
171 | return 0; | ||
172 | |||
173 | } | ||
174 | |||
175 | module_init(batman_init); | ||
176 | module_exit(batman_exit); | ||
177 | |||
178 | MODULE_LICENSE("GPL"); | ||
179 | |||
180 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
181 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
182 | MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE); | ||
183 | #ifdef REVISION_VERSION | ||
184 | MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION); | ||
185 | #else | ||
186 | MODULE_VERSION(SOURCE_VERSION); | ||
187 | #endif | ||
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h new file mode 100644 index 000000000000..d4d9926c2201 --- /dev/null +++ b/net/batman-adv/main.h | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_MAIN_H_ | ||
23 | #define _NET_BATMAN_ADV_MAIN_H_ | ||
24 | |||
25 | /* Kernel Programming */ | ||
26 | #define LINUX | ||
27 | |||
28 | #define DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \ | ||
29 | "Simon Wunderlich <siwu@hrz.tu-chemnitz.de>" | ||
30 | #define DRIVER_DESC "B.A.T.M.A.N. advanced" | ||
31 | #define DRIVER_DEVICE "batman-adv" | ||
32 | |||
33 | #define SOURCE_VERSION "next" | ||
34 | |||
35 | |||
36 | /* B.A.T.M.A.N. parameters */ | ||
37 | |||
38 | #define TQ_MAX_VALUE 255 | ||
39 | #define JITTER 20 | ||
40 | #define TTL 50 /* Time To Live of broadcast messages */ | ||
41 | |||
42 | #define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no | ||
43 | * valid packet comes in -> TODO: check | ||
44 | * influence on TQ_LOCAL_WINDOW_SIZE */ | ||
45 | #define LOCAL_HNA_TIMEOUT 3600 /* in seconds */ | ||
46 | |||
47 | #define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator | ||
48 | * messages in squence numbers (should be a | ||
49 | * multiple of our word size) */ | ||
50 | #define TQ_GLOBAL_WINDOW_SIZE 5 | ||
51 | #define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 | ||
52 | #define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 | ||
53 | #define TQ_TOTAL_BIDRECT_LIMIT 1 | ||
54 | |||
55 | #define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) | ||
56 | |||
57 | #define PACKBUFF_SIZE 2000 | ||
58 | #define LOG_BUF_LEN 8192 /* has to be a power of 2 */ | ||
59 | |||
60 | #define VIS_INTERVAL 5000 /* 5 seconds */ | ||
61 | |||
62 | /* how much worse secondary interfaces may be to | ||
63 | * to be considered as bonding candidates */ | ||
64 | |||
65 | #define BONDING_TQ_THRESHOLD 50 | ||
66 | |||
67 | #define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or | ||
68 | * change the size of | ||
69 | * forw_packet->direct_link_flags */ | ||
70 | #define MAX_AGGREGATION_MS 100 | ||
71 | |||
72 | #define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ | ||
73 | |||
74 | #define RESET_PROTECTION_MS 30000 | ||
75 | #define EXPECTED_SEQNO_RANGE 65536 | ||
76 | /* don't reset again within 30 seconds */ | ||
77 | |||
78 | #define MESH_INACTIVE 0 | ||
79 | #define MESH_ACTIVE 1 | ||
80 | #define MESH_DEACTIVATING 2 | ||
81 | |||
82 | #define BCAST_QUEUE_LEN 256 | ||
83 | #define BATMAN_QUEUE_LEN 256 | ||
84 | |||
85 | /* | ||
86 | * Debug Messages | ||
87 | */ | ||
88 | #ifdef pr_fmt | ||
89 | #undef pr_fmt | ||
90 | #endif | ||
91 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before | ||
92 | * kernel messages */ | ||
93 | |||
94 | #define DBG_BATMAN 1 /* all messages related to routing / flooding / | ||
95 | * broadcasting / etc */ | ||
96 | #define DBG_ROUTES 2 /* route or hna added / changed / deleted */ | ||
97 | #define DBG_ALL 3 | ||
98 | |||
99 | #define LOG_BUF_LEN 8192 /* has to be a power of 2 */ | ||
100 | |||
101 | |||
102 | /* | ||
103 | * Vis | ||
104 | */ | ||
105 | |||
106 | /* #define VIS_SUBCLUSTERS_DISABLED */ | ||
107 | |||
108 | /* | ||
109 | * Kernel headers | ||
110 | */ | ||
111 | |||
112 | #include <linux/mutex.h> /* mutex */ | ||
113 | #include <linux/module.h> /* needed by all modules */ | ||
114 | #include <linux/netdevice.h> /* netdevice */ | ||
115 | #include <linux/etherdevice.h> /* ethernet address classifaction */ | ||
116 | #include <linux/if_ether.h> /* ethernet header */ | ||
117 | #include <linux/poll.h> /* poll_table */ | ||
118 | #include <linux/kthread.h> /* kernel threads */ | ||
119 | #include <linux/pkt_sched.h> /* schedule types */ | ||
120 | #include <linux/workqueue.h> /* workqueue */ | ||
121 | #include <linux/slab.h> | ||
122 | #include <net/sock.h> /* struct sock */ | ||
123 | #include <linux/jiffies.h> | ||
124 | #include <linux/seq_file.h> | ||
125 | #include "types.h" | ||
126 | |||
127 | #ifndef REVISION_VERSION | ||
128 | #define REVISION_VERSION_STR "" | ||
129 | #else | ||
130 | #define REVISION_VERSION_STR " "REVISION_VERSION | ||
131 | #endif | ||
132 | |||
133 | extern struct list_head if_list; | ||
134 | |||
135 | extern unsigned char broadcast_addr[]; | ||
136 | extern struct workqueue_struct *bat_event_workqueue; | ||
137 | |||
138 | int mesh_init(struct net_device *soft_iface); | ||
139 | void mesh_free(struct net_device *soft_iface); | ||
140 | void inc_module_count(void); | ||
141 | void dec_module_count(void); | ||
142 | int is_my_mac(uint8_t *addr); | ||
143 | |||
144 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
145 | int debug_log(struct bat_priv *bat_priv, char *fmt, ...); | ||
146 | |||
147 | #define bat_dbg(type, bat_priv, fmt, arg...) \ | ||
148 | do { \ | ||
149 | if (atomic_read(&bat_priv->log_level) & type) \ | ||
150 | debug_log(bat_priv, fmt, ## arg); \ | ||
151 | } \ | ||
152 | while (0) | ||
153 | #else /* !CONFIG_BATMAN_ADV_DEBUG */ | ||
154 | static inline void bat_dbg(char type __attribute__((unused)), | ||
155 | struct bat_priv *bat_priv __attribute__((unused)), | ||
156 | char *fmt __attribute__((unused)), ...) | ||
157 | { | ||
158 | } | ||
159 | #endif | ||
160 | |||
161 | #define bat_warning(net_dev, fmt, arg...) \ | ||
162 | do { \ | ||
163 | struct net_device *_netdev = (net_dev); \ | ||
164 | struct bat_priv *_batpriv = netdev_priv(_netdev); \ | ||
165 | bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ | ||
166 | pr_warning("%s: " fmt, _netdev->name, ## arg); \ | ||
167 | } while (0) | ||
168 | #define bat_info(net_dev, fmt, arg...) \ | ||
169 | do { \ | ||
170 | struct net_device *_netdev = (net_dev); \ | ||
171 | struct bat_priv *_batpriv = netdev_priv(_netdev); \ | ||
172 | bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ | ||
173 | pr_info("%s: " fmt, _netdev->name, ## arg); \ | ||
174 | } while (0) | ||
175 | #define bat_err(net_dev, fmt, arg...) \ | ||
176 | do { \ | ||
177 | struct net_device *_netdev = (net_dev); \ | ||
178 | struct bat_priv *_batpriv = netdev_priv(_netdev); \ | ||
179 | bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ | ||
180 | pr_err("%s: " fmt, _netdev->name, ## arg); \ | ||
181 | } while (0) | ||
182 | |||
183 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ | ||
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c new file mode 100644 index 000000000000..6b7fb6b7e6f9 --- /dev/null +++ b/net/batman-adv/originator.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* increase the reference counter for this originator */ | ||
23 | |||
24 | #include "main.h" | ||
25 | #include "originator.h" | ||
26 | #include "hash.h" | ||
27 | #include "translation-table.h" | ||
28 | #include "routing.h" | ||
29 | #include "gateway_client.h" | ||
30 | #include "hard-interface.h" | ||
31 | #include "unicast.h" | ||
32 | #include "soft-interface.h" | ||
33 | |||
34 | static void purge_orig(struct work_struct *work); | ||
35 | |||
36 | static void start_purge_timer(struct bat_priv *bat_priv) | ||
37 | { | ||
38 | INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig); | ||
39 | queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ); | ||
40 | } | ||
41 | |||
42 | int originator_init(struct bat_priv *bat_priv) | ||
43 | { | ||
44 | if (bat_priv->orig_hash) | ||
45 | return 1; | ||
46 | |||
47 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
48 | bat_priv->orig_hash = hash_new(1024); | ||
49 | |||
50 | if (!bat_priv->orig_hash) | ||
51 | goto err; | ||
52 | |||
53 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
54 | start_purge_timer(bat_priv); | ||
55 | return 1; | ||
56 | |||
57 | err: | ||
58 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | struct neigh_node * | ||
63 | create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, | ||
64 | uint8_t *neigh, struct batman_if *if_incoming) | ||
65 | { | ||
66 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
67 | struct neigh_node *neigh_node; | ||
68 | |||
69 | bat_dbg(DBG_BATMAN, bat_priv, | ||
70 | "Creating new last-hop neighbor of originator\n"); | ||
71 | |||
72 | neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC); | ||
73 | if (!neigh_node) | ||
74 | return NULL; | ||
75 | |||
76 | INIT_LIST_HEAD(&neigh_node->list); | ||
77 | |||
78 | memcpy(neigh_node->addr, neigh, ETH_ALEN); | ||
79 | neigh_node->orig_node = orig_neigh_node; | ||
80 | neigh_node->if_incoming = if_incoming; | ||
81 | |||
82 | list_add_tail(&neigh_node->list, &orig_node->neigh_list); | ||
83 | return neigh_node; | ||
84 | } | ||
85 | |||
86 | static void free_orig_node(void *data, void *arg) | ||
87 | { | ||
88 | struct list_head *list_pos, *list_pos_tmp; | ||
89 | struct neigh_node *neigh_node; | ||
90 | struct orig_node *orig_node = (struct orig_node *)data; | ||
91 | struct bat_priv *bat_priv = (struct bat_priv *)arg; | ||
92 | |||
93 | /* for all neighbors towards this originator ... */ | ||
94 | list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { | ||
95 | neigh_node = list_entry(list_pos, struct neigh_node, list); | ||
96 | |||
97 | list_del(list_pos); | ||
98 | kfree(neigh_node); | ||
99 | } | ||
100 | |||
101 | frag_list_free(&orig_node->frag_list); | ||
102 | hna_global_del_orig(bat_priv, orig_node, "originator timed out"); | ||
103 | |||
104 | kfree(orig_node->bcast_own); | ||
105 | kfree(orig_node->bcast_own_sum); | ||
106 | kfree(orig_node); | ||
107 | } | ||
108 | |||
109 | void originator_free(struct bat_priv *bat_priv) | ||
110 | { | ||
111 | if (!bat_priv->orig_hash) | ||
112 | return; | ||
113 | |||
114 | cancel_delayed_work_sync(&bat_priv->orig_work); | ||
115 | |||
116 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
117 | hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv); | ||
118 | bat_priv->orig_hash = NULL; | ||
119 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
120 | } | ||
121 | |||
122 | /* this function finds or creates an originator entry for the given | ||
123 | * address if it does not exits */ | ||
124 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) | ||
125 | { | ||
126 | struct orig_node *orig_node; | ||
127 | int size; | ||
128 | int hash_added; | ||
129 | |||
130 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
131 | compare_orig, choose_orig, | ||
132 | addr)); | ||
133 | |||
134 | if (orig_node) | ||
135 | return orig_node; | ||
136 | |||
137 | bat_dbg(DBG_BATMAN, bat_priv, | ||
138 | "Creating new originator: %pM\n", addr); | ||
139 | |||
140 | orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC); | ||
141 | if (!orig_node) | ||
142 | return NULL; | ||
143 | |||
144 | INIT_LIST_HEAD(&orig_node->neigh_list); | ||
145 | |||
146 | memcpy(orig_node->orig, addr, ETH_ALEN); | ||
147 | orig_node->router = NULL; | ||
148 | orig_node->hna_buff = NULL; | ||
149 | orig_node->bcast_seqno_reset = jiffies - 1 | ||
150 | - msecs_to_jiffies(RESET_PROTECTION_MS); | ||
151 | orig_node->batman_seqno_reset = jiffies - 1 | ||
152 | - msecs_to_jiffies(RESET_PROTECTION_MS); | ||
153 | |||
154 | size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS; | ||
155 | |||
156 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); | ||
157 | if (!orig_node->bcast_own) | ||
158 | goto free_orig_node; | ||
159 | |||
160 | size = bat_priv->num_ifaces * sizeof(uint8_t); | ||
161 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); | ||
162 | |||
163 | INIT_LIST_HEAD(&orig_node->frag_list); | ||
164 | orig_node->last_frag_packet = 0; | ||
165 | |||
166 | if (!orig_node->bcast_own_sum) | ||
167 | goto free_bcast_own; | ||
168 | |||
169 | hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig, | ||
170 | orig_node); | ||
171 | if (hash_added < 0) | ||
172 | goto free_bcast_own_sum; | ||
173 | |||
174 | return orig_node; | ||
175 | free_bcast_own_sum: | ||
176 | kfree(orig_node->bcast_own_sum); | ||
177 | free_bcast_own: | ||
178 | kfree(orig_node->bcast_own); | ||
179 | free_orig_node: | ||
180 | kfree(orig_node); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | static bool purge_orig_neighbors(struct bat_priv *bat_priv, | ||
185 | struct orig_node *orig_node, | ||
186 | struct neigh_node **best_neigh_node) | ||
187 | { | ||
188 | struct list_head *list_pos, *list_pos_tmp; | ||
189 | struct neigh_node *neigh_node; | ||
190 | bool neigh_purged = false; | ||
191 | |||
192 | *best_neigh_node = NULL; | ||
193 | |||
194 | /* for all neighbors towards this originator ... */ | ||
195 | list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) { | ||
196 | neigh_node = list_entry(list_pos, struct neigh_node, list); | ||
197 | |||
198 | if ((time_after(jiffies, | ||
199 | neigh_node->last_valid + PURGE_TIMEOUT * HZ)) || | ||
200 | (neigh_node->if_incoming->if_status == IF_INACTIVE) || | ||
201 | (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) { | ||
202 | |||
203 | if (neigh_node->if_incoming->if_status == | ||
204 | IF_TO_BE_REMOVED) | ||
205 | bat_dbg(DBG_BATMAN, bat_priv, | ||
206 | "neighbor purge: originator %pM, " | ||
207 | "neighbor: %pM, iface: %s\n", | ||
208 | orig_node->orig, neigh_node->addr, | ||
209 | neigh_node->if_incoming->net_dev->name); | ||
210 | else | ||
211 | bat_dbg(DBG_BATMAN, bat_priv, | ||
212 | "neighbor timeout: originator %pM, " | ||
213 | "neighbor: %pM, last_valid: %lu\n", | ||
214 | orig_node->orig, neigh_node->addr, | ||
215 | (neigh_node->last_valid / HZ)); | ||
216 | |||
217 | neigh_purged = true; | ||
218 | list_del(list_pos); | ||
219 | kfree(neigh_node); | ||
220 | } else { | ||
221 | if ((!*best_neigh_node) || | ||
222 | (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) | ||
223 | *best_neigh_node = neigh_node; | ||
224 | } | ||
225 | } | ||
226 | return neigh_purged; | ||
227 | } | ||
228 | |||
229 | static bool purge_orig_node(struct bat_priv *bat_priv, | ||
230 | struct orig_node *orig_node) | ||
231 | { | ||
232 | struct neigh_node *best_neigh_node; | ||
233 | |||
234 | if (time_after(jiffies, | ||
235 | orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) { | ||
236 | |||
237 | bat_dbg(DBG_BATMAN, bat_priv, | ||
238 | "Originator timeout: originator %pM, last_valid %lu\n", | ||
239 | orig_node->orig, (orig_node->last_valid / HZ)); | ||
240 | return true; | ||
241 | } else { | ||
242 | if (purge_orig_neighbors(bat_priv, orig_node, | ||
243 | &best_neigh_node)) { | ||
244 | update_routes(bat_priv, orig_node, | ||
245 | best_neigh_node, | ||
246 | orig_node->hna_buff, | ||
247 | orig_node->hna_buff_len); | ||
248 | /* update bonding candidates, we could have lost | ||
249 | * some candidates. */ | ||
250 | update_bonding_candidates(bat_priv, orig_node); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | return false; | ||
255 | } | ||
256 | |||
257 | static void _purge_orig(struct bat_priv *bat_priv) | ||
258 | { | ||
259 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
260 | struct hlist_node *walk, *safe; | ||
261 | struct hlist_head *head; | ||
262 | struct element_t *bucket; | ||
263 | struct orig_node *orig_node; | ||
264 | int i; | ||
265 | |||
266 | if (!hash) | ||
267 | return; | ||
268 | |||
269 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
270 | |||
271 | /* for all origins... */ | ||
272 | for (i = 0; i < hash->size; i++) { | ||
273 | head = &hash->table[i]; | ||
274 | |||
275 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | ||
276 | orig_node = bucket->data; | ||
277 | |||
278 | if (purge_orig_node(bat_priv, orig_node)) { | ||
279 | if (orig_node->gw_flags) | ||
280 | gw_node_delete(bat_priv, orig_node); | ||
281 | hlist_del(walk); | ||
282 | kfree(bucket); | ||
283 | free_orig_node(orig_node, bat_priv); | ||
284 | } | ||
285 | |||
286 | if (time_after(jiffies, orig_node->last_frag_packet + | ||
287 | msecs_to_jiffies(FRAG_TIMEOUT))) | ||
288 | frag_list_free(&orig_node->frag_list); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
293 | |||
294 | gw_node_purge(bat_priv); | ||
295 | gw_election(bat_priv); | ||
296 | |||
297 | softif_neigh_purge(bat_priv); | ||
298 | } | ||
299 | |||
300 | static void purge_orig(struct work_struct *work) | ||
301 | { | ||
302 | struct delayed_work *delayed_work = | ||
303 | container_of(work, struct delayed_work, work); | ||
304 | struct bat_priv *bat_priv = | ||
305 | container_of(delayed_work, struct bat_priv, orig_work); | ||
306 | |||
307 | _purge_orig(bat_priv); | ||
308 | start_purge_timer(bat_priv); | ||
309 | } | ||
310 | |||
311 | void purge_orig_ref(struct bat_priv *bat_priv) | ||
312 | { | ||
313 | _purge_orig(bat_priv); | ||
314 | } | ||
315 | |||
316 | int orig_seq_print_text(struct seq_file *seq, void *offset) | ||
317 | { | ||
318 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
319 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
320 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
321 | struct hlist_node *walk; | ||
322 | struct hlist_head *head; | ||
323 | struct element_t *bucket; | ||
324 | struct orig_node *orig_node; | ||
325 | struct neigh_node *neigh_node; | ||
326 | int batman_count = 0; | ||
327 | int last_seen_secs; | ||
328 | int last_seen_msecs; | ||
329 | int i; | ||
330 | |||
331 | if ((!bat_priv->primary_if) || | ||
332 | (bat_priv->primary_if->if_status != IF_ACTIVE)) { | ||
333 | if (!bat_priv->primary_if) | ||
334 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
335 | "please specify interfaces to enable it\n", | ||
336 | net_dev->name); | ||
337 | |||
338 | return seq_printf(seq, "BATMAN mesh %s " | ||
339 | "disabled - primary interface not active\n", | ||
340 | net_dev->name); | ||
341 | } | ||
342 | |||
343 | seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", | ||
344 | SOURCE_VERSION, REVISION_VERSION_STR, | ||
345 | bat_priv->primary_if->net_dev->name, | ||
346 | bat_priv->primary_if->net_dev->dev_addr, net_dev->name); | ||
347 | seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", | ||
348 | "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", | ||
349 | "outgoingIF", "Potential nexthops"); | ||
350 | |||
351 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
352 | |||
353 | for (i = 0; i < hash->size; i++) { | ||
354 | head = &hash->table[i]; | ||
355 | |||
356 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
357 | orig_node = bucket->data; | ||
358 | |||
359 | if (!orig_node->router) | ||
360 | continue; | ||
361 | |||
362 | if (orig_node->router->tq_avg == 0) | ||
363 | continue; | ||
364 | |||
365 | last_seen_secs = jiffies_to_msecs(jiffies - | ||
366 | orig_node->last_valid) / 1000; | ||
367 | last_seen_msecs = jiffies_to_msecs(jiffies - | ||
368 | orig_node->last_valid) % 1000; | ||
369 | |||
370 | neigh_node = orig_node->router; | ||
371 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", | ||
372 | orig_node->orig, last_seen_secs, | ||
373 | last_seen_msecs, neigh_node->tq_avg, | ||
374 | neigh_node->addr, | ||
375 | neigh_node->if_incoming->net_dev->name); | ||
376 | |||
377 | list_for_each_entry(neigh_node, &orig_node->neigh_list, | ||
378 | list) { | ||
379 | seq_printf(seq, " %pM (%3i)", neigh_node->addr, | ||
380 | neigh_node->tq_avg); | ||
381 | } | ||
382 | |||
383 | seq_printf(seq, "\n"); | ||
384 | batman_count++; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
389 | |||
390 | if ((batman_count == 0)) | ||
391 | seq_printf(seq, "No batman nodes in range ...\n"); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) | ||
397 | { | ||
398 | void *data_ptr; | ||
399 | |||
400 | data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS, | ||
401 | GFP_ATOMIC); | ||
402 | if (!data_ptr) { | ||
403 | pr_err("Can't resize orig: out of memory\n"); | ||
404 | return -1; | ||
405 | } | ||
406 | |||
407 | memcpy(data_ptr, orig_node->bcast_own, | ||
408 | (max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS); | ||
409 | kfree(orig_node->bcast_own); | ||
410 | orig_node->bcast_own = data_ptr; | ||
411 | |||
412 | data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); | ||
413 | if (!data_ptr) { | ||
414 | pr_err("Can't resize orig: out of memory\n"); | ||
415 | return -1; | ||
416 | } | ||
417 | |||
418 | memcpy(data_ptr, orig_node->bcast_own_sum, | ||
419 | (max_if_num - 1) * sizeof(uint8_t)); | ||
420 | kfree(orig_node->bcast_own_sum); | ||
421 | orig_node->bcast_own_sum = data_ptr; | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) | ||
427 | { | ||
428 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
429 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
430 | struct hlist_node *walk; | ||
431 | struct hlist_head *head; | ||
432 | struct element_t *bucket; | ||
433 | struct orig_node *orig_node; | ||
434 | int i; | ||
435 | |||
436 | /* resize all orig nodes because orig_node->bcast_own(_sum) depend on | ||
437 | * if_num */ | ||
438 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
439 | |||
440 | for (i = 0; i < hash->size; i++) { | ||
441 | head = &hash->table[i]; | ||
442 | |||
443 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
444 | orig_node = bucket->data; | ||
445 | |||
446 | if (orig_node_add_if(orig_node, max_if_num) == -1) | ||
447 | goto err; | ||
448 | } | ||
449 | } | ||
450 | |||
451 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
452 | return 0; | ||
453 | |||
454 | err: | ||
455 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
456 | return -ENOMEM; | ||
457 | } | ||
458 | |||
459 | static int orig_node_del_if(struct orig_node *orig_node, | ||
460 | int max_if_num, int del_if_num) | ||
461 | { | ||
462 | void *data_ptr = NULL; | ||
463 | int chunk_size; | ||
464 | |||
465 | /* last interface was removed */ | ||
466 | if (max_if_num == 0) | ||
467 | goto free_bcast_own; | ||
468 | |||
469 | chunk_size = sizeof(unsigned long) * NUM_WORDS; | ||
470 | data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC); | ||
471 | if (!data_ptr) { | ||
472 | pr_err("Can't resize orig: out of memory\n"); | ||
473 | return -1; | ||
474 | } | ||
475 | |||
476 | /* copy first part */ | ||
477 | memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size); | ||
478 | |||
479 | /* copy second part */ | ||
480 | memcpy(data_ptr + del_if_num * chunk_size, | ||
481 | orig_node->bcast_own + ((del_if_num + 1) * chunk_size), | ||
482 | (max_if_num - del_if_num) * chunk_size); | ||
483 | |||
484 | free_bcast_own: | ||
485 | kfree(orig_node->bcast_own); | ||
486 | orig_node->bcast_own = data_ptr; | ||
487 | |||
488 | if (max_if_num == 0) | ||
489 | goto free_own_sum; | ||
490 | |||
491 | data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC); | ||
492 | if (!data_ptr) { | ||
493 | pr_err("Can't resize orig: out of memory\n"); | ||
494 | return -1; | ||
495 | } | ||
496 | |||
497 | memcpy(data_ptr, orig_node->bcast_own_sum, | ||
498 | del_if_num * sizeof(uint8_t)); | ||
499 | |||
500 | memcpy(data_ptr + del_if_num * sizeof(uint8_t), | ||
501 | orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)), | ||
502 | (max_if_num - del_if_num) * sizeof(uint8_t)); | ||
503 | |||
504 | free_own_sum: | ||
505 | kfree(orig_node->bcast_own_sum); | ||
506 | orig_node->bcast_own_sum = data_ptr; | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) | ||
512 | { | ||
513 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
514 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
515 | struct hlist_node *walk; | ||
516 | struct hlist_head *head; | ||
517 | struct element_t *bucket; | ||
518 | struct batman_if *batman_if_tmp; | ||
519 | struct orig_node *orig_node; | ||
520 | int i, ret; | ||
521 | |||
522 | /* resize all orig nodes because orig_node->bcast_own(_sum) depend on | ||
523 | * if_num */ | ||
524 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
525 | |||
526 | for (i = 0; i < hash->size; i++) { | ||
527 | head = &hash->table[i]; | ||
528 | |||
529 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
530 | orig_node = bucket->data; | ||
531 | |||
532 | ret = orig_node_del_if(orig_node, max_if_num, | ||
533 | batman_if->if_num); | ||
534 | |||
535 | if (ret == -1) | ||
536 | goto err; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | /* renumber remaining batman interfaces _inside_ of orig_hash_lock */ | ||
541 | rcu_read_lock(); | ||
542 | list_for_each_entry_rcu(batman_if_tmp, &if_list, list) { | ||
543 | if (batman_if_tmp->if_status == IF_NOT_IN_USE) | ||
544 | continue; | ||
545 | |||
546 | if (batman_if == batman_if_tmp) | ||
547 | continue; | ||
548 | |||
549 | if (batman_if->soft_iface != batman_if_tmp->soft_iface) | ||
550 | continue; | ||
551 | |||
552 | if (batman_if_tmp->if_num > batman_if->if_num) | ||
553 | batman_if_tmp->if_num--; | ||
554 | } | ||
555 | rcu_read_unlock(); | ||
556 | |||
557 | batman_if->if_num = -1; | ||
558 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
559 | return 0; | ||
560 | |||
561 | err: | ||
562 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
563 | return -ENOMEM; | ||
564 | } | ||
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h new file mode 100644 index 000000000000..d474ceb2a4eb --- /dev/null +++ b/net/batman-adv/originator.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_ | ||
23 | #define _NET_BATMAN_ADV_ORIGINATOR_H_ | ||
24 | |||
25 | int originator_init(struct bat_priv *bat_priv); | ||
26 | void originator_free(struct bat_priv *bat_priv); | ||
27 | void purge_orig_ref(struct bat_priv *bat_priv); | ||
28 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); | ||
29 | struct neigh_node * | ||
30 | create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, | ||
31 | uint8_t *neigh, struct batman_if *if_incoming); | ||
32 | int orig_seq_print_text(struct seq_file *seq, void *offset); | ||
33 | int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); | ||
34 | int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); | ||
35 | |||
36 | |||
37 | /* returns 1 if they are the same originator */ | ||
38 | static inline int compare_orig(void *data1, void *data2) | ||
39 | { | ||
40 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | ||
41 | } | ||
42 | |||
43 | /* hashfunction to choose an entry in a hash table of given size */ | ||
44 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | ||
45 | static inline int choose_orig(void *data, int32_t size) | ||
46 | { | ||
47 | unsigned char *key = data; | ||
48 | uint32_t hash = 0; | ||
49 | size_t i; | ||
50 | |||
51 | for (i = 0; i < 6; i++) { | ||
52 | hash += key[i]; | ||
53 | hash += (hash << 10); | ||
54 | hash ^= (hash >> 6); | ||
55 | } | ||
56 | |||
57 | hash += (hash << 3); | ||
58 | hash ^= (hash >> 11); | ||
59 | hash += (hash << 15); | ||
60 | |||
61 | return hash % size; | ||
62 | } | ||
63 | |||
64 | #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ | ||
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h new file mode 100644 index 000000000000..b49fdf70a6d5 --- /dev/null +++ b/net/batman-adv/packet.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_PACKET_H_ | ||
23 | #define _NET_BATMAN_ADV_PACKET_H_ | ||
24 | |||
25 | #define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ | ||
26 | |||
27 | #define BAT_PACKET 0x01 | ||
28 | #define BAT_ICMP 0x02 | ||
29 | #define BAT_UNICAST 0x03 | ||
30 | #define BAT_BCAST 0x04 | ||
31 | #define BAT_VIS 0x05 | ||
32 | #define BAT_UNICAST_FRAG 0x06 | ||
33 | |||
34 | /* this file is included by batctl which needs these defines */ | ||
35 | #define COMPAT_VERSION 12 | ||
36 | #define DIRECTLINK 0x40 | ||
37 | #define VIS_SERVER 0x20 | ||
38 | #define PRIMARIES_FIRST_HOP 0x10 | ||
39 | |||
40 | /* ICMP message types */ | ||
41 | #define ECHO_REPLY 0 | ||
42 | #define DESTINATION_UNREACHABLE 3 | ||
43 | #define ECHO_REQUEST 8 | ||
44 | #define TTL_EXCEEDED 11 | ||
45 | #define PARAMETER_PROBLEM 12 | ||
46 | |||
47 | /* vis defines */ | ||
48 | #define VIS_TYPE_SERVER_SYNC 0 | ||
49 | #define VIS_TYPE_CLIENT_UPDATE 1 | ||
50 | |||
51 | /* fragmentation defines */ | ||
52 | #define UNI_FRAG_HEAD 0x01 | ||
53 | |||
54 | struct batman_packet { | ||
55 | uint8_t packet_type; | ||
56 | uint8_t version; /* batman version field */ | ||
57 | uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ | ||
58 | uint8_t tq; | ||
59 | uint32_t seqno; | ||
60 | uint8_t orig[6]; | ||
61 | uint8_t prev_sender[6]; | ||
62 | uint8_t ttl; | ||
63 | uint8_t num_hna; | ||
64 | uint8_t gw_flags; /* flags related to gateway class */ | ||
65 | uint8_t align; | ||
66 | } __attribute__((packed)); | ||
67 | |||
68 | #define BAT_PACKET_LEN sizeof(struct batman_packet) | ||
69 | |||
70 | struct icmp_packet { | ||
71 | uint8_t packet_type; | ||
72 | uint8_t version; /* batman version field */ | ||
73 | uint8_t msg_type; /* see ICMP message types above */ | ||
74 | uint8_t ttl; | ||
75 | uint8_t dst[6]; | ||
76 | uint8_t orig[6]; | ||
77 | uint16_t seqno; | ||
78 | uint8_t uid; | ||
79 | } __attribute__((packed)); | ||
80 | |||
81 | #define BAT_RR_LEN 16 | ||
82 | |||
83 | /* icmp_packet_rr must start with all fields from imcp_packet | ||
84 | * as this is assumed by code that handles ICMP packets */ | ||
85 | struct icmp_packet_rr { | ||
86 | uint8_t packet_type; | ||
87 | uint8_t version; /* batman version field */ | ||
88 | uint8_t msg_type; /* see ICMP message types above */ | ||
89 | uint8_t ttl; | ||
90 | uint8_t dst[6]; | ||
91 | uint8_t orig[6]; | ||
92 | uint16_t seqno; | ||
93 | uint8_t uid; | ||
94 | uint8_t rr_cur; | ||
95 | uint8_t rr[BAT_RR_LEN][ETH_ALEN]; | ||
96 | } __attribute__((packed)); | ||
97 | |||
98 | struct unicast_packet { | ||
99 | uint8_t packet_type; | ||
100 | uint8_t version; /* batman version field */ | ||
101 | uint8_t dest[6]; | ||
102 | uint8_t ttl; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | struct unicast_frag_packet { | ||
106 | uint8_t packet_type; | ||
107 | uint8_t version; /* batman version field */ | ||
108 | uint8_t dest[6]; | ||
109 | uint8_t ttl; | ||
110 | uint8_t flags; | ||
111 | uint8_t orig[6]; | ||
112 | uint16_t seqno; | ||
113 | } __attribute__((packed)); | ||
114 | |||
115 | struct bcast_packet { | ||
116 | uint8_t packet_type; | ||
117 | uint8_t version; /* batman version field */ | ||
118 | uint8_t orig[6]; | ||
119 | uint8_t ttl; | ||
120 | uint32_t seqno; | ||
121 | } __attribute__((packed)); | ||
122 | |||
123 | struct vis_packet { | ||
124 | uint8_t packet_type; | ||
125 | uint8_t version; /* batman version field */ | ||
126 | uint8_t vis_type; /* which type of vis-participant sent this? */ | ||
127 | uint8_t entries; /* number of entries behind this struct */ | ||
128 | uint32_t seqno; /* sequence number */ | ||
129 | uint8_t ttl; /* TTL */ | ||
130 | uint8_t vis_orig[6]; /* originator that informs about its | ||
131 | * neighbors */ | ||
132 | uint8_t target_orig[6]; /* who should receive this packet */ | ||
133 | uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ | ||
134 | } __attribute__((packed)); | ||
135 | |||
136 | #endif /* _NET_BATMAN_ADV_PACKET_H_ */ | ||
diff --git a/net/batman-adv/ring_buffer.c b/net/batman-adv/ring_buffer.c new file mode 100644 index 000000000000..defd37c9be1f --- /dev/null +++ b/net/batman-adv/ring_buffer.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "ring_buffer.h" | ||
24 | |||
25 | void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value) | ||
26 | { | ||
27 | lq_recv[*lq_index] = value; | ||
28 | *lq_index = (*lq_index + 1) % TQ_GLOBAL_WINDOW_SIZE; | ||
29 | } | ||
30 | |||
31 | uint8_t ring_buffer_avg(uint8_t lq_recv[]) | ||
32 | { | ||
33 | uint8_t *ptr; | ||
34 | uint16_t count = 0, i = 0, sum = 0; | ||
35 | |||
36 | ptr = lq_recv; | ||
37 | |||
38 | while (i < TQ_GLOBAL_WINDOW_SIZE) { | ||
39 | if (*ptr != 0) { | ||
40 | count++; | ||
41 | sum += *ptr; | ||
42 | } | ||
43 | |||
44 | i++; | ||
45 | ptr++; | ||
46 | } | ||
47 | |||
48 | if (count == 0) | ||
49 | return 0; | ||
50 | |||
51 | return (uint8_t)(sum / count); | ||
52 | } | ||
diff --git a/net/batman-adv/ring_buffer.h b/net/batman-adv/ring_buffer.h new file mode 100644 index 000000000000..6b0cb9aaeba5 --- /dev/null +++ b/net/batman-adv/ring_buffer.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_RING_BUFFER_H_ | ||
23 | #define _NET_BATMAN_ADV_RING_BUFFER_H_ | ||
24 | |||
25 | void ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, uint8_t value); | ||
26 | uint8_t ring_buffer_avg(uint8_t lq_recv[]); | ||
27 | |||
28 | #endif /* _NET_BATMAN_ADV_RING_BUFFER_H_ */ | ||
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c new file mode 100644 index 000000000000..8828eddd3f72 --- /dev/null +++ b/net/batman-adv/routing.c | |||
@@ -0,0 +1,1397 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "routing.h" | ||
24 | #include "send.h" | ||
25 | #include "hash.h" | ||
26 | #include "soft-interface.h" | ||
27 | #include "hard-interface.h" | ||
28 | #include "icmp_socket.h" | ||
29 | #include "translation-table.h" | ||
30 | #include "originator.h" | ||
31 | #include "types.h" | ||
32 | #include "ring_buffer.h" | ||
33 | #include "vis.h" | ||
34 | #include "aggregation.h" | ||
35 | #include "gateway_common.h" | ||
36 | #include "gateway_client.h" | ||
37 | #include "unicast.h" | ||
38 | |||
39 | void slide_own_bcast_window(struct batman_if *batman_if) | ||
40 | { | ||
41 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
42 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
43 | struct hlist_node *walk; | ||
44 | struct hlist_head *head; | ||
45 | struct element_t *bucket; | ||
46 | struct orig_node *orig_node; | ||
47 | unsigned long *word; | ||
48 | int i; | ||
49 | size_t word_index; | ||
50 | |||
51 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
52 | |||
53 | for (i = 0; i < hash->size; i++) { | ||
54 | head = &hash->table[i]; | ||
55 | |||
56 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
57 | orig_node = bucket->data; | ||
58 | word_index = batman_if->if_num * NUM_WORDS; | ||
59 | word = &(orig_node->bcast_own[word_index]); | ||
60 | |||
61 | bit_get_packet(bat_priv, word, 1, 0); | ||
62 | orig_node->bcast_own_sum[batman_if->if_num] = | ||
63 | bit_packet_count(word); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
68 | } | ||
69 | |||
70 | static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
71 | unsigned char *hna_buff, int hna_buff_len) | ||
72 | { | ||
73 | if ((hna_buff_len != orig_node->hna_buff_len) || | ||
74 | ((hna_buff_len > 0) && | ||
75 | (orig_node->hna_buff_len > 0) && | ||
76 | (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) { | ||
77 | |||
78 | if (orig_node->hna_buff_len > 0) | ||
79 | hna_global_del_orig(bat_priv, orig_node, | ||
80 | "originator changed hna"); | ||
81 | |||
82 | if ((hna_buff_len > 0) && (hna_buff)) | ||
83 | hna_global_add_orig(bat_priv, orig_node, | ||
84 | hna_buff, hna_buff_len); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void update_route(struct bat_priv *bat_priv, | ||
89 | struct orig_node *orig_node, | ||
90 | struct neigh_node *neigh_node, | ||
91 | unsigned char *hna_buff, int hna_buff_len) | ||
92 | { | ||
93 | /* route deleted */ | ||
94 | if ((orig_node->router) && (!neigh_node)) { | ||
95 | |||
96 | bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", | ||
97 | orig_node->orig); | ||
98 | hna_global_del_orig(bat_priv, orig_node, | ||
99 | "originator timed out"); | ||
100 | |||
101 | /* route added */ | ||
102 | } else if ((!orig_node->router) && (neigh_node)) { | ||
103 | |||
104 | bat_dbg(DBG_ROUTES, bat_priv, | ||
105 | "Adding route towards: %pM (via %pM)\n", | ||
106 | orig_node->orig, neigh_node->addr); | ||
107 | hna_global_add_orig(bat_priv, orig_node, | ||
108 | hna_buff, hna_buff_len); | ||
109 | |||
110 | /* route changed */ | ||
111 | } else { | ||
112 | bat_dbg(DBG_ROUTES, bat_priv, | ||
113 | "Changing route towards: %pM " | ||
114 | "(now via %pM - was via %pM)\n", | ||
115 | orig_node->orig, neigh_node->addr, | ||
116 | orig_node->router->addr); | ||
117 | } | ||
118 | |||
119 | orig_node->router = neigh_node; | ||
120 | } | ||
121 | |||
122 | |||
123 | void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
124 | struct neigh_node *neigh_node, unsigned char *hna_buff, | ||
125 | int hna_buff_len) | ||
126 | { | ||
127 | |||
128 | if (!orig_node) | ||
129 | return; | ||
130 | |||
131 | if (orig_node->router != neigh_node) | ||
132 | update_route(bat_priv, orig_node, neigh_node, | ||
133 | hna_buff, hna_buff_len); | ||
134 | /* may be just HNA changed */ | ||
135 | else | ||
136 | update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); | ||
137 | } | ||
138 | |||
139 | static int is_bidirectional_neigh(struct orig_node *orig_node, | ||
140 | struct orig_node *orig_neigh_node, | ||
141 | struct batman_packet *batman_packet, | ||
142 | struct batman_if *if_incoming) | ||
143 | { | ||
144 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
145 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | ||
146 | unsigned char total_count; | ||
147 | |||
148 | if (orig_node == orig_neigh_node) { | ||
149 | list_for_each_entry(tmp_neigh_node, | ||
150 | &orig_node->neigh_list, | ||
151 | list) { | ||
152 | |||
153 | if (compare_orig(tmp_neigh_node->addr, | ||
154 | orig_neigh_node->orig) && | ||
155 | (tmp_neigh_node->if_incoming == if_incoming)) | ||
156 | neigh_node = tmp_neigh_node; | ||
157 | } | ||
158 | |||
159 | if (!neigh_node) | ||
160 | neigh_node = create_neighbor(orig_node, | ||
161 | orig_neigh_node, | ||
162 | orig_neigh_node->orig, | ||
163 | if_incoming); | ||
164 | /* create_neighbor failed, return 0 */ | ||
165 | if (!neigh_node) | ||
166 | return 0; | ||
167 | |||
168 | neigh_node->last_valid = jiffies; | ||
169 | } else { | ||
170 | /* find packet count of corresponding one hop neighbor */ | ||
171 | list_for_each_entry(tmp_neigh_node, | ||
172 | &orig_neigh_node->neigh_list, list) { | ||
173 | |||
174 | if (compare_orig(tmp_neigh_node->addr, | ||
175 | orig_neigh_node->orig) && | ||
176 | (tmp_neigh_node->if_incoming == if_incoming)) | ||
177 | neigh_node = tmp_neigh_node; | ||
178 | } | ||
179 | |||
180 | if (!neigh_node) | ||
181 | neigh_node = create_neighbor(orig_neigh_node, | ||
182 | orig_neigh_node, | ||
183 | orig_neigh_node->orig, | ||
184 | if_incoming); | ||
185 | /* create_neighbor failed, return 0 */ | ||
186 | if (!neigh_node) | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | orig_node->last_valid = jiffies; | ||
191 | |||
192 | /* pay attention to not get a value bigger than 100 % */ | ||
193 | total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] > | ||
194 | neigh_node->real_packet_count ? | ||
195 | neigh_node->real_packet_count : | ||
196 | orig_neigh_node->bcast_own_sum[if_incoming->if_num]); | ||
197 | |||
198 | /* if we have too few packets (too less data) we set tq_own to zero */ | ||
199 | /* if we receive too few packets it is not considered bidirectional */ | ||
200 | if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) || | ||
201 | (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM)) | ||
202 | orig_neigh_node->tq_own = 0; | ||
203 | else | ||
204 | /* neigh_node->real_packet_count is never zero as we | ||
205 | * only purge old information when getting new | ||
206 | * information */ | ||
207 | orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) / | ||
208 | neigh_node->real_packet_count; | ||
209 | |||
210 | /* | ||
211 | * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does | ||
212 | * affect the nearly-symmetric links only a little, but | ||
213 | * punishes asymmetric links more. This will give a value | ||
214 | * between 0 and TQ_MAX_VALUE | ||
215 | */ | ||
216 | orig_neigh_node->tq_asym_penalty = | ||
217 | TQ_MAX_VALUE - | ||
218 | (TQ_MAX_VALUE * | ||
219 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | ||
220 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) * | ||
221 | (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) / | ||
222 | (TQ_LOCAL_WINDOW_SIZE * | ||
223 | TQ_LOCAL_WINDOW_SIZE * | ||
224 | TQ_LOCAL_WINDOW_SIZE); | ||
225 | |||
226 | batman_packet->tq = ((batman_packet->tq * | ||
227 | orig_neigh_node->tq_own * | ||
228 | orig_neigh_node->tq_asym_penalty) / | ||
229 | (TQ_MAX_VALUE * TQ_MAX_VALUE)); | ||
230 | |||
231 | bat_dbg(DBG_BATMAN, bat_priv, | ||
232 | "bidirectional: " | ||
233 | "orig = %-15pM neigh = %-15pM => own_bcast = %2i, " | ||
234 | "real recv = %2i, local tq: %3i, asym_penalty: %3i, " | ||
235 | "total tq: %3i\n", | ||
236 | orig_node->orig, orig_neigh_node->orig, total_count, | ||
237 | neigh_node->real_packet_count, orig_neigh_node->tq_own, | ||
238 | orig_neigh_node->tq_asym_penalty, batman_packet->tq); | ||
239 | |||
240 | /* if link has the minimum required transmission quality | ||
241 | * consider it bidirectional */ | ||
242 | if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT) | ||
243 | return 1; | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static void update_orig(struct bat_priv *bat_priv, | ||
249 | struct orig_node *orig_node, | ||
250 | struct ethhdr *ethhdr, | ||
251 | struct batman_packet *batman_packet, | ||
252 | struct batman_if *if_incoming, | ||
253 | unsigned char *hna_buff, int hna_buff_len, | ||
254 | char is_duplicate) | ||
255 | { | ||
256 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | ||
257 | int tmp_hna_buff_len; | ||
258 | |||
259 | bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " | ||
260 | "Searching and updating originator entry of received packet\n"); | ||
261 | |||
262 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
263 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && | ||
264 | (tmp_neigh_node->if_incoming == if_incoming)) { | ||
265 | neigh_node = tmp_neigh_node; | ||
266 | continue; | ||
267 | } | ||
268 | |||
269 | if (is_duplicate) | ||
270 | continue; | ||
271 | |||
272 | ring_buffer_set(tmp_neigh_node->tq_recv, | ||
273 | &tmp_neigh_node->tq_index, 0); | ||
274 | tmp_neigh_node->tq_avg = | ||
275 | ring_buffer_avg(tmp_neigh_node->tq_recv); | ||
276 | } | ||
277 | |||
278 | if (!neigh_node) { | ||
279 | struct orig_node *orig_tmp; | ||
280 | |||
281 | orig_tmp = get_orig_node(bat_priv, ethhdr->h_source); | ||
282 | if (!orig_tmp) | ||
283 | return; | ||
284 | |||
285 | neigh_node = create_neighbor(orig_node, orig_tmp, | ||
286 | ethhdr->h_source, if_incoming); | ||
287 | if (!neigh_node) | ||
288 | return; | ||
289 | } else | ||
290 | bat_dbg(DBG_BATMAN, bat_priv, | ||
291 | "Updating existing last-hop neighbor of originator\n"); | ||
292 | |||
293 | orig_node->flags = batman_packet->flags; | ||
294 | neigh_node->last_valid = jiffies; | ||
295 | |||
296 | ring_buffer_set(neigh_node->tq_recv, | ||
297 | &neigh_node->tq_index, | ||
298 | batman_packet->tq); | ||
299 | neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); | ||
300 | |||
301 | if (!is_duplicate) { | ||
302 | orig_node->last_ttl = batman_packet->ttl; | ||
303 | neigh_node->last_ttl = batman_packet->ttl; | ||
304 | } | ||
305 | |||
306 | tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ? | ||
307 | batman_packet->num_hna * ETH_ALEN : hna_buff_len); | ||
308 | |||
309 | /* if this neighbor already is our next hop there is nothing | ||
310 | * to change */ | ||
311 | if (orig_node->router == neigh_node) | ||
312 | goto update_hna; | ||
313 | |||
314 | /* if this neighbor does not offer a better TQ we won't consider it */ | ||
315 | if ((orig_node->router) && | ||
316 | (orig_node->router->tq_avg > neigh_node->tq_avg)) | ||
317 | goto update_hna; | ||
318 | |||
319 | /* if the TQ is the same and the link not more symetric we | ||
320 | * won't consider it either */ | ||
321 | if ((orig_node->router) && | ||
322 | ((neigh_node->tq_avg == orig_node->router->tq_avg) && | ||
323 | (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num] | ||
324 | >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num]))) | ||
325 | goto update_hna; | ||
326 | |||
327 | update_routes(bat_priv, orig_node, neigh_node, | ||
328 | hna_buff, tmp_hna_buff_len); | ||
329 | goto update_gw; | ||
330 | |||
331 | update_hna: | ||
332 | update_routes(bat_priv, orig_node, orig_node->router, | ||
333 | hna_buff, tmp_hna_buff_len); | ||
334 | |||
335 | update_gw: | ||
336 | if (orig_node->gw_flags != batman_packet->gw_flags) | ||
337 | gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); | ||
338 | |||
339 | orig_node->gw_flags = batman_packet->gw_flags; | ||
340 | |||
341 | /* restart gateway selection if fast or late switching was enabled */ | ||
342 | if ((orig_node->gw_flags) && | ||
343 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_CLIENT) && | ||
344 | (atomic_read(&bat_priv->gw_sel_class) > 2)) | ||
345 | gw_check_election(bat_priv, orig_node); | ||
346 | } | ||
347 | |||
348 | /* checks whether the host restarted and is in the protection time. | ||
349 | * returns: | ||
350 | * 0 if the packet is to be accepted | ||
351 | * 1 if the packet is to be ignored. | ||
352 | */ | ||
353 | static int window_protected(struct bat_priv *bat_priv, | ||
354 | int32_t seq_num_diff, | ||
355 | unsigned long *last_reset) | ||
356 | { | ||
357 | if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE) | ||
358 | || (seq_num_diff >= EXPECTED_SEQNO_RANGE)) { | ||
359 | if (time_after(jiffies, *last_reset + | ||
360 | msecs_to_jiffies(RESET_PROTECTION_MS))) { | ||
361 | |||
362 | *last_reset = jiffies; | ||
363 | bat_dbg(DBG_BATMAN, bat_priv, | ||
364 | "old packet received, start protection\n"); | ||
365 | |||
366 | return 0; | ||
367 | } else | ||
368 | return 1; | ||
369 | } | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /* processes a batman packet for all interfaces, adjusts the sequence number and | ||
374 | * finds out whether it is a duplicate. | ||
375 | * returns: | ||
376 | * 1 the packet is a duplicate | ||
377 | * 0 the packet has not yet been received | ||
378 | * -1 the packet is old and has been received while the seqno window | ||
379 | * was protected. Caller should drop it. | ||
380 | */ | ||
381 | static char count_real_packets(struct ethhdr *ethhdr, | ||
382 | struct batman_packet *batman_packet, | ||
383 | struct batman_if *if_incoming) | ||
384 | { | ||
385 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
386 | struct orig_node *orig_node; | ||
387 | struct neigh_node *tmp_neigh_node; | ||
388 | char is_duplicate = 0; | ||
389 | int32_t seq_diff; | ||
390 | int need_update = 0; | ||
391 | int set_mark; | ||
392 | |||
393 | orig_node = get_orig_node(bat_priv, batman_packet->orig); | ||
394 | if (!orig_node) | ||
395 | return 0; | ||
396 | |||
397 | seq_diff = batman_packet->seqno - orig_node->last_real_seqno; | ||
398 | |||
399 | /* signalize caller that the packet is to be dropped. */ | ||
400 | if (window_protected(bat_priv, seq_diff, | ||
401 | &orig_node->batman_seqno_reset)) | ||
402 | return -1; | ||
403 | |||
404 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
405 | |||
406 | is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, | ||
407 | orig_node->last_real_seqno, | ||
408 | batman_packet->seqno); | ||
409 | |||
410 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && | ||
411 | (tmp_neigh_node->if_incoming == if_incoming)) | ||
412 | set_mark = 1; | ||
413 | else | ||
414 | set_mark = 0; | ||
415 | |||
416 | /* if the window moved, set the update flag. */ | ||
417 | need_update |= bit_get_packet(bat_priv, | ||
418 | tmp_neigh_node->real_bits, | ||
419 | seq_diff, set_mark); | ||
420 | |||
421 | tmp_neigh_node->real_packet_count = | ||
422 | bit_packet_count(tmp_neigh_node->real_bits); | ||
423 | } | ||
424 | |||
425 | if (need_update) { | ||
426 | bat_dbg(DBG_BATMAN, bat_priv, | ||
427 | "updating last_seqno: old %d, new %d\n", | ||
428 | orig_node->last_real_seqno, batman_packet->seqno); | ||
429 | orig_node->last_real_seqno = batman_packet->seqno; | ||
430 | } | ||
431 | |||
432 | return is_duplicate; | ||
433 | } | ||
434 | |||
435 | /* copy primary address for bonding */ | ||
436 | static void mark_bonding_address(struct bat_priv *bat_priv, | ||
437 | struct orig_node *orig_node, | ||
438 | struct orig_node *orig_neigh_node, | ||
439 | struct batman_packet *batman_packet) | ||
440 | |||
441 | { | ||
442 | if (batman_packet->flags & PRIMARIES_FIRST_HOP) | ||
443 | memcpy(orig_neigh_node->primary_addr, | ||
444 | orig_node->orig, ETH_ALEN); | ||
445 | |||
446 | return; | ||
447 | } | ||
448 | |||
449 | /* mark possible bond.candidates in the neighbor list */ | ||
450 | void update_bonding_candidates(struct bat_priv *bat_priv, | ||
451 | struct orig_node *orig_node) | ||
452 | { | ||
453 | int candidates; | ||
454 | int interference_candidate; | ||
455 | int best_tq; | ||
456 | struct neigh_node *tmp_neigh_node, *tmp_neigh_node2; | ||
457 | struct neigh_node *first_candidate, *last_candidate; | ||
458 | |||
459 | /* update the candidates for this originator */ | ||
460 | if (!orig_node->router) { | ||
461 | orig_node->bond.candidates = 0; | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | best_tq = orig_node->router->tq_avg; | ||
466 | |||
467 | /* update bond.candidates */ | ||
468 | |||
469 | candidates = 0; | ||
470 | |||
471 | /* mark other nodes which also received "PRIMARIES FIRST HOP" packets | ||
472 | * as "bonding partner" */ | ||
473 | |||
474 | /* first, zero the list */ | ||
475 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
476 | tmp_neigh_node->next_bond_candidate = NULL; | ||
477 | } | ||
478 | |||
479 | first_candidate = NULL; | ||
480 | last_candidate = NULL; | ||
481 | list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) { | ||
482 | |||
483 | /* only consider if it has the same primary address ... */ | ||
484 | if (memcmp(orig_node->orig, | ||
485 | tmp_neigh_node->orig_node->primary_addr, | ||
486 | ETH_ALEN) != 0) | ||
487 | continue; | ||
488 | |||
489 | /* ... and is good enough to be considered */ | ||
490 | if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) | ||
491 | continue; | ||
492 | |||
493 | /* check if we have another candidate with the same | ||
494 | * mac address or interface. If we do, we won't | ||
495 | * select this candidate because of possible interference. */ | ||
496 | |||
497 | interference_candidate = 0; | ||
498 | list_for_each_entry(tmp_neigh_node2, | ||
499 | &orig_node->neigh_list, list) { | ||
500 | |||
501 | if (tmp_neigh_node2 == tmp_neigh_node) | ||
502 | continue; | ||
503 | |||
504 | /* we only care if the other candidate is even | ||
505 | * considered as candidate. */ | ||
506 | if (!tmp_neigh_node2->next_bond_candidate) | ||
507 | continue; | ||
508 | |||
509 | |||
510 | if ((tmp_neigh_node->if_incoming == | ||
511 | tmp_neigh_node2->if_incoming) | ||
512 | || (memcmp(tmp_neigh_node->addr, | ||
513 | tmp_neigh_node2->addr, ETH_ALEN) == 0)) { | ||
514 | |||
515 | interference_candidate = 1; | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | /* don't care further if it is an interference candidate */ | ||
520 | if (interference_candidate) | ||
521 | continue; | ||
522 | |||
523 | if (!first_candidate) { | ||
524 | first_candidate = tmp_neigh_node; | ||
525 | tmp_neigh_node->next_bond_candidate = first_candidate; | ||
526 | } else | ||
527 | tmp_neigh_node->next_bond_candidate = last_candidate; | ||
528 | |||
529 | last_candidate = tmp_neigh_node; | ||
530 | |||
531 | candidates++; | ||
532 | } | ||
533 | |||
534 | if (candidates > 0) { | ||
535 | first_candidate->next_bond_candidate = last_candidate; | ||
536 | orig_node->bond.selected = first_candidate; | ||
537 | } | ||
538 | |||
539 | orig_node->bond.candidates = candidates; | ||
540 | } | ||
541 | |||
542 | void receive_bat_packet(struct ethhdr *ethhdr, | ||
543 | struct batman_packet *batman_packet, | ||
544 | unsigned char *hna_buff, int hna_buff_len, | ||
545 | struct batman_if *if_incoming) | ||
546 | { | ||
547 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
548 | struct batman_if *batman_if; | ||
549 | struct orig_node *orig_neigh_node, *orig_node; | ||
550 | char has_directlink_flag; | ||
551 | char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; | ||
552 | char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; | ||
553 | char is_duplicate; | ||
554 | uint32_t if_incoming_seqno; | ||
555 | |||
556 | /* Silently drop when the batman packet is actually not a | ||
557 | * correct packet. | ||
558 | * | ||
559 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
560 | * minimum frame length of 64 byte) and the aggregation interprets | ||
561 | * it as an additional length. | ||
562 | * | ||
563 | * TODO: A more sane solution would be to have a bit in the | ||
564 | * batman_packet to detect whether the packet is the last | ||
565 | * packet in an aggregation. Here we expect that the padding | ||
566 | * is always zero (or not 0x01) | ||
567 | */ | ||
568 | if (batman_packet->packet_type != BAT_PACKET) | ||
569 | return; | ||
570 | |||
571 | /* could be changed by schedule_own_packet() */ | ||
572 | if_incoming_seqno = atomic_read(&if_incoming->seqno); | ||
573 | |||
574 | has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0); | ||
575 | |||
576 | is_single_hop_neigh = (compare_orig(ethhdr->h_source, | ||
577 | batman_packet->orig) ? 1 : 0); | ||
578 | |||
579 | bat_dbg(DBG_BATMAN, bat_priv, | ||
580 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] " | ||
581 | "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " | ||
582 | "TTL %d, V %d, IDF %d)\n", | ||
583 | ethhdr->h_source, if_incoming->net_dev->name, | ||
584 | if_incoming->net_dev->dev_addr, batman_packet->orig, | ||
585 | batman_packet->prev_sender, batman_packet->seqno, | ||
586 | batman_packet->tq, batman_packet->ttl, batman_packet->version, | ||
587 | has_directlink_flag); | ||
588 | |||
589 | rcu_read_lock(); | ||
590 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
591 | if (batman_if->if_status != IF_ACTIVE) | ||
592 | continue; | ||
593 | |||
594 | if (batman_if->soft_iface != if_incoming->soft_iface) | ||
595 | continue; | ||
596 | |||
597 | if (compare_orig(ethhdr->h_source, | ||
598 | batman_if->net_dev->dev_addr)) | ||
599 | is_my_addr = 1; | ||
600 | |||
601 | if (compare_orig(batman_packet->orig, | ||
602 | batman_if->net_dev->dev_addr)) | ||
603 | is_my_orig = 1; | ||
604 | |||
605 | if (compare_orig(batman_packet->prev_sender, | ||
606 | batman_if->net_dev->dev_addr)) | ||
607 | is_my_oldorig = 1; | ||
608 | |||
609 | if (compare_orig(ethhdr->h_source, broadcast_addr)) | ||
610 | is_broadcast = 1; | ||
611 | } | ||
612 | rcu_read_unlock(); | ||
613 | |||
614 | if (batman_packet->version != COMPAT_VERSION) { | ||
615 | bat_dbg(DBG_BATMAN, bat_priv, | ||
616 | "Drop packet: incompatible batman version (%i)\n", | ||
617 | batman_packet->version); | ||
618 | return; | ||
619 | } | ||
620 | |||
621 | if (is_my_addr) { | ||
622 | bat_dbg(DBG_BATMAN, bat_priv, | ||
623 | "Drop packet: received my own broadcast (sender: %pM" | ||
624 | ")\n", | ||
625 | ethhdr->h_source); | ||
626 | return; | ||
627 | } | ||
628 | |||
629 | if (is_broadcast) { | ||
630 | bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " | ||
631 | "ignoring all packets with broadcast source addr (sender: %pM" | ||
632 | ")\n", ethhdr->h_source); | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | if (is_my_orig) { | ||
637 | unsigned long *word; | ||
638 | int offset; | ||
639 | |||
640 | orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source); | ||
641 | |||
642 | if (!orig_neigh_node) | ||
643 | return; | ||
644 | |||
645 | /* neighbor has to indicate direct link and it has to | ||
646 | * come via the corresponding interface */ | ||
647 | /* if received seqno equals last send seqno save new | ||
648 | * seqno for bidirectional check */ | ||
649 | if (has_directlink_flag && | ||
650 | compare_orig(if_incoming->net_dev->dev_addr, | ||
651 | batman_packet->orig) && | ||
652 | (batman_packet->seqno - if_incoming_seqno + 2 == 0)) { | ||
653 | offset = if_incoming->if_num * NUM_WORDS; | ||
654 | word = &(orig_neigh_node->bcast_own[offset]); | ||
655 | bit_mark(word, 0); | ||
656 | orig_neigh_node->bcast_own_sum[if_incoming->if_num] = | ||
657 | bit_packet_count(word); | ||
658 | } | ||
659 | |||
660 | bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: " | ||
661 | "originator packet from myself (via neighbor)\n"); | ||
662 | return; | ||
663 | } | ||
664 | |||
665 | if (is_my_oldorig) { | ||
666 | bat_dbg(DBG_BATMAN, bat_priv, | ||
667 | "Drop packet: ignoring all rebroadcast echos (sender: " | ||
668 | "%pM)\n", ethhdr->h_source); | ||
669 | return; | ||
670 | } | ||
671 | |||
672 | orig_node = get_orig_node(bat_priv, batman_packet->orig); | ||
673 | if (!orig_node) | ||
674 | return; | ||
675 | |||
676 | is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming); | ||
677 | |||
678 | if (is_duplicate == -1) { | ||
679 | bat_dbg(DBG_BATMAN, bat_priv, | ||
680 | "Drop packet: packet within seqno protection time " | ||
681 | "(sender: %pM)\n", ethhdr->h_source); | ||
682 | return; | ||
683 | } | ||
684 | |||
685 | if (batman_packet->tq == 0) { | ||
686 | bat_dbg(DBG_BATMAN, bat_priv, | ||
687 | "Drop packet: originator packet with tq equal 0\n"); | ||
688 | return; | ||
689 | } | ||
690 | |||
691 | /* avoid temporary routing loops */ | ||
692 | if ((orig_node->router) && | ||
693 | (orig_node->router->orig_node->router) && | ||
694 | (compare_orig(orig_node->router->addr, | ||
695 | batman_packet->prev_sender)) && | ||
696 | !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) && | ||
697 | (compare_orig(orig_node->router->addr, | ||
698 | orig_node->router->orig_node->router->addr))) { | ||
699 | bat_dbg(DBG_BATMAN, bat_priv, | ||
700 | "Drop packet: ignoring all rebroadcast packets that " | ||
701 | "may make me loop (sender: %pM)\n", ethhdr->h_source); | ||
702 | return; | ||
703 | } | ||
704 | |||
705 | /* if sender is a direct neighbor the sender mac equals | ||
706 | * originator mac */ | ||
707 | orig_neigh_node = (is_single_hop_neigh ? | ||
708 | orig_node : | ||
709 | get_orig_node(bat_priv, ethhdr->h_source)); | ||
710 | if (!orig_neigh_node) | ||
711 | return; | ||
712 | |||
713 | /* drop packet if sender is not a direct neighbor and if we | ||
714 | * don't route towards it */ | ||
715 | if (!is_single_hop_neigh && (!orig_neigh_node->router)) { | ||
716 | bat_dbg(DBG_BATMAN, bat_priv, | ||
717 | "Drop packet: OGM via unknown neighbor!\n"); | ||
718 | return; | ||
719 | } | ||
720 | |||
721 | is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node, | ||
722 | batman_packet, if_incoming); | ||
723 | |||
724 | /* update ranking if it is not a duplicate or has the same | ||
725 | * seqno and similar ttl as the non-duplicate */ | ||
726 | if (is_bidirectional && | ||
727 | (!is_duplicate || | ||
728 | ((orig_node->last_real_seqno == batman_packet->seqno) && | ||
729 | (orig_node->last_ttl - 3 <= batman_packet->ttl)))) | ||
730 | update_orig(bat_priv, orig_node, ethhdr, batman_packet, | ||
731 | if_incoming, hna_buff, hna_buff_len, is_duplicate); | ||
732 | |||
733 | mark_bonding_address(bat_priv, orig_node, | ||
734 | orig_neigh_node, batman_packet); | ||
735 | update_bonding_candidates(bat_priv, orig_node); | ||
736 | |||
737 | /* is single hop (direct) neighbor */ | ||
738 | if (is_single_hop_neigh) { | ||
739 | |||
740 | /* mark direct link on incoming interface */ | ||
741 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | ||
742 | 1, hna_buff_len, if_incoming); | ||
743 | |||
744 | bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " | ||
745 | "rebroadcast neighbor packet with direct link flag\n"); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | /* multihop originator */ | ||
750 | if (!is_bidirectional) { | ||
751 | bat_dbg(DBG_BATMAN, bat_priv, | ||
752 | "Drop packet: not received via bidirectional link\n"); | ||
753 | return; | ||
754 | } | ||
755 | |||
756 | if (is_duplicate) { | ||
757 | bat_dbg(DBG_BATMAN, bat_priv, | ||
758 | "Drop packet: duplicate packet received\n"); | ||
759 | return; | ||
760 | } | ||
761 | |||
762 | bat_dbg(DBG_BATMAN, bat_priv, | ||
763 | "Forwarding packet: rebroadcast originator packet\n"); | ||
764 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | ||
765 | 0, hna_buff_len, if_incoming); | ||
766 | } | ||
767 | |||
768 | int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) | ||
769 | { | ||
770 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
771 | struct ethhdr *ethhdr; | ||
772 | |||
773 | /* drop packet if it has not necessary minimum size */ | ||
774 | if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet)))) | ||
775 | return NET_RX_DROP; | ||
776 | |||
777 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
778 | |||
779 | /* packet with broadcast indication but unicast recipient */ | ||
780 | if (!is_broadcast_ether_addr(ethhdr->h_dest)) | ||
781 | return NET_RX_DROP; | ||
782 | |||
783 | /* packet with broadcast sender address */ | ||
784 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
785 | return NET_RX_DROP; | ||
786 | |||
787 | /* create a copy of the skb, if needed, to modify it. */ | ||
788 | if (skb_cow(skb, 0) < 0) | ||
789 | return NET_RX_DROP; | ||
790 | |||
791 | /* keep skb linear */ | ||
792 | if (skb_linearize(skb) < 0) | ||
793 | return NET_RX_DROP; | ||
794 | |||
795 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
796 | |||
797 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
798 | receive_aggr_bat_packet(ethhdr, | ||
799 | skb->data, | ||
800 | skb_headlen(skb), | ||
801 | batman_if); | ||
802 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
803 | |||
804 | kfree_skb(skb); | ||
805 | return NET_RX_SUCCESS; | ||
806 | } | ||
807 | |||
808 | static int recv_my_icmp_packet(struct bat_priv *bat_priv, | ||
809 | struct sk_buff *skb, size_t icmp_len) | ||
810 | { | ||
811 | struct orig_node *orig_node; | ||
812 | struct icmp_packet_rr *icmp_packet; | ||
813 | struct ethhdr *ethhdr; | ||
814 | struct batman_if *batman_if; | ||
815 | int ret; | ||
816 | uint8_t dstaddr[ETH_ALEN]; | ||
817 | |||
818 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
819 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
820 | |||
821 | /* add data to device queue */ | ||
822 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
823 | bat_socket_receive_packet(icmp_packet, icmp_len); | ||
824 | return NET_RX_DROP; | ||
825 | } | ||
826 | |||
827 | if (!bat_priv->primary_if) | ||
828 | return NET_RX_DROP; | ||
829 | |||
830 | /* answer echo request (ping) */ | ||
831 | /* get routing information */ | ||
832 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
833 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
834 | compare_orig, choose_orig, | ||
835 | icmp_packet->orig)); | ||
836 | ret = NET_RX_DROP; | ||
837 | |||
838 | if ((orig_node) && (orig_node->router)) { | ||
839 | |||
840 | /* don't lock while sending the packets ... we therefore | ||
841 | * copy the required data before sending */ | ||
842 | batman_if = orig_node->router->if_incoming; | ||
843 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
844 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
845 | |||
846 | /* create a copy of the skb, if needed, to modify it. */ | ||
847 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
848 | return NET_RX_DROP; | ||
849 | |||
850 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
851 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
852 | |||
853 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
854 | memcpy(icmp_packet->orig, | ||
855 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
856 | icmp_packet->msg_type = ECHO_REPLY; | ||
857 | icmp_packet->ttl = TTL; | ||
858 | |||
859 | send_skb_packet(skb, batman_if, dstaddr); | ||
860 | ret = NET_RX_SUCCESS; | ||
861 | |||
862 | } else | ||
863 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
864 | |||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | ||
869 | struct sk_buff *skb, size_t icmp_len) | ||
870 | { | ||
871 | struct orig_node *orig_node; | ||
872 | struct icmp_packet *icmp_packet; | ||
873 | struct ethhdr *ethhdr; | ||
874 | struct batman_if *batman_if; | ||
875 | int ret; | ||
876 | uint8_t dstaddr[ETH_ALEN]; | ||
877 | |||
878 | icmp_packet = (struct icmp_packet *)skb->data; | ||
879 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
880 | |||
881 | /* send TTL exceeded if packet is an echo request (traceroute) */ | ||
882 | if (icmp_packet->msg_type != ECHO_REQUEST) { | ||
883 | pr_debug("Warning - can't forward icmp packet from %pM to " | ||
884 | "%pM: ttl exceeded\n", icmp_packet->orig, | ||
885 | icmp_packet->dst); | ||
886 | return NET_RX_DROP; | ||
887 | } | ||
888 | |||
889 | if (!bat_priv->primary_if) | ||
890 | return NET_RX_DROP; | ||
891 | |||
892 | /* get routing information */ | ||
893 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
894 | orig_node = ((struct orig_node *) | ||
895 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
896 | icmp_packet->orig)); | ||
897 | ret = NET_RX_DROP; | ||
898 | |||
899 | if ((orig_node) && (orig_node->router)) { | ||
900 | |||
901 | /* don't lock while sending the packets ... we therefore | ||
902 | * copy the required data before sending */ | ||
903 | batman_if = orig_node->router->if_incoming; | ||
904 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
905 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
906 | |||
907 | /* create a copy of the skb, if needed, to modify it. */ | ||
908 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
909 | return NET_RX_DROP; | ||
910 | |||
911 | icmp_packet = (struct icmp_packet *) skb->data; | ||
912 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
913 | |||
914 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
915 | memcpy(icmp_packet->orig, | ||
916 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
917 | icmp_packet->msg_type = TTL_EXCEEDED; | ||
918 | icmp_packet->ttl = TTL; | ||
919 | |||
920 | send_skb_packet(skb, batman_if, dstaddr); | ||
921 | ret = NET_RX_SUCCESS; | ||
922 | |||
923 | } else | ||
924 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
925 | |||
926 | return ret; | ||
927 | } | ||
928 | |||
929 | |||
930 | int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
931 | { | ||
932 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
933 | struct icmp_packet_rr *icmp_packet; | ||
934 | struct ethhdr *ethhdr; | ||
935 | struct orig_node *orig_node; | ||
936 | struct batman_if *batman_if; | ||
937 | int hdr_size = sizeof(struct icmp_packet); | ||
938 | int ret; | ||
939 | uint8_t dstaddr[ETH_ALEN]; | ||
940 | |||
941 | /** | ||
942 | * we truncate all incoming icmp packets if they don't match our size | ||
943 | */ | ||
944 | if (skb->len >= sizeof(struct icmp_packet_rr)) | ||
945 | hdr_size = sizeof(struct icmp_packet_rr); | ||
946 | |||
947 | /* drop packet if it has not necessary minimum size */ | ||
948 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
949 | return NET_RX_DROP; | ||
950 | |||
951 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
952 | |||
953 | /* packet with unicast indication but broadcast recipient */ | ||
954 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | ||
955 | return NET_RX_DROP; | ||
956 | |||
957 | /* packet with broadcast sender address */ | ||
958 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
959 | return NET_RX_DROP; | ||
960 | |||
961 | /* not for me */ | ||
962 | if (!is_my_mac(ethhdr->h_dest)) | ||
963 | return NET_RX_DROP; | ||
964 | |||
965 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
966 | |||
967 | /* add record route information if not full */ | ||
968 | if ((hdr_size == sizeof(struct icmp_packet_rr)) && | ||
969 | (icmp_packet->rr_cur < BAT_RR_LEN)) { | ||
970 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), | ||
971 | ethhdr->h_dest, ETH_ALEN); | ||
972 | icmp_packet->rr_cur++; | ||
973 | } | ||
974 | |||
975 | /* packet for me */ | ||
976 | if (is_my_mac(icmp_packet->dst)) | ||
977 | return recv_my_icmp_packet(bat_priv, skb, hdr_size); | ||
978 | |||
979 | /* TTL exceeded */ | ||
980 | if (icmp_packet->ttl < 2) | ||
981 | return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size); | ||
982 | |||
983 | ret = NET_RX_DROP; | ||
984 | |||
985 | /* get routing information */ | ||
986 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
987 | orig_node = ((struct orig_node *) | ||
988 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
989 | icmp_packet->dst)); | ||
990 | |||
991 | if ((orig_node) && (orig_node->router)) { | ||
992 | |||
993 | /* don't lock while sending the packets ... we therefore | ||
994 | * copy the required data before sending */ | ||
995 | batman_if = orig_node->router->if_incoming; | ||
996 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
997 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
998 | |||
999 | /* create a copy of the skb, if needed, to modify it. */ | ||
1000 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
1001 | return NET_RX_DROP; | ||
1002 | |||
1003 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
1004 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1005 | |||
1006 | /* decrement ttl */ | ||
1007 | icmp_packet->ttl--; | ||
1008 | |||
1009 | /* route it */ | ||
1010 | send_skb_packet(skb, batman_if, dstaddr); | ||
1011 | ret = NET_RX_SUCCESS; | ||
1012 | |||
1013 | } else | ||
1014 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1015 | |||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | /* find a suitable router for this originator, and use | ||
1020 | * bonding if possible. */ | ||
1021 | struct neigh_node *find_router(struct bat_priv *bat_priv, | ||
1022 | struct orig_node *orig_node, | ||
1023 | struct batman_if *recv_if) | ||
1024 | { | ||
1025 | struct orig_node *primary_orig_node; | ||
1026 | struct orig_node *router_orig; | ||
1027 | struct neigh_node *router, *first_candidate, *best_router; | ||
1028 | static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; | ||
1029 | int bonding_enabled; | ||
1030 | |||
1031 | if (!orig_node) | ||
1032 | return NULL; | ||
1033 | |||
1034 | if (!orig_node->router) | ||
1035 | return NULL; | ||
1036 | |||
1037 | /* without bonding, the first node should | ||
1038 | * always choose the default router. */ | ||
1039 | |||
1040 | bonding_enabled = atomic_read(&bat_priv->bonding); | ||
1041 | |||
1042 | if ((!recv_if) && (!bonding_enabled)) | ||
1043 | return orig_node->router; | ||
1044 | |||
1045 | router_orig = orig_node->router->orig_node; | ||
1046 | |||
1047 | /* if we have something in the primary_addr, we can search | ||
1048 | * for a potential bonding candidate. */ | ||
1049 | if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0) | ||
1050 | return orig_node->router; | ||
1051 | |||
1052 | /* find the orig_node which has the primary interface. might | ||
1053 | * even be the same as our router_orig in many cases */ | ||
1054 | |||
1055 | if (memcmp(router_orig->primary_addr, | ||
1056 | router_orig->orig, ETH_ALEN) == 0) { | ||
1057 | primary_orig_node = router_orig; | ||
1058 | } else { | ||
1059 | primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, | ||
1060 | choose_orig, | ||
1061 | router_orig->primary_addr); | ||
1062 | |||
1063 | if (!primary_orig_node) | ||
1064 | return orig_node->router; | ||
1065 | } | ||
1066 | |||
1067 | /* with less than 2 candidates, we can't do any | ||
1068 | * bonding and prefer the original router. */ | ||
1069 | |||
1070 | if (primary_orig_node->bond.candidates < 2) | ||
1071 | return orig_node->router; | ||
1072 | |||
1073 | |||
1074 | /* all nodes between should choose a candidate which | ||
1075 | * is is not on the interface where the packet came | ||
1076 | * in. */ | ||
1077 | first_candidate = primary_orig_node->bond.selected; | ||
1078 | router = first_candidate; | ||
1079 | |||
1080 | if (bonding_enabled) { | ||
1081 | /* in the bonding case, send the packets in a round | ||
1082 | * robin fashion over the remaining interfaces. */ | ||
1083 | do { | ||
1084 | /* recv_if == NULL on the first node. */ | ||
1085 | if (router->if_incoming != recv_if) | ||
1086 | break; | ||
1087 | |||
1088 | router = router->next_bond_candidate; | ||
1089 | } while (router != first_candidate); | ||
1090 | |||
1091 | primary_orig_node->bond.selected = router->next_bond_candidate; | ||
1092 | |||
1093 | } else { | ||
1094 | /* if bonding is disabled, use the best of the | ||
1095 | * remaining candidates which are not using | ||
1096 | * this interface. */ | ||
1097 | best_router = first_candidate; | ||
1098 | |||
1099 | do { | ||
1100 | /* recv_if == NULL on the first node. */ | ||
1101 | if ((router->if_incoming != recv_if) && | ||
1102 | (router->tq_avg > best_router->tq_avg)) | ||
1103 | best_router = router; | ||
1104 | |||
1105 | router = router->next_bond_candidate; | ||
1106 | } while (router != first_candidate); | ||
1107 | |||
1108 | router = best_router; | ||
1109 | } | ||
1110 | |||
1111 | return router; | ||
1112 | } | ||
1113 | |||
1114 | static int check_unicast_packet(struct sk_buff *skb, int hdr_size) | ||
1115 | { | ||
1116 | struct ethhdr *ethhdr; | ||
1117 | |||
1118 | /* drop packet if it has not necessary minimum size */ | ||
1119 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1120 | return -1; | ||
1121 | |||
1122 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1123 | |||
1124 | /* packet with unicast indication but broadcast recipient */ | ||
1125 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | ||
1126 | return -1; | ||
1127 | |||
1128 | /* packet with broadcast sender address */ | ||
1129 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
1130 | return -1; | ||
1131 | |||
1132 | /* not for me */ | ||
1133 | if (!is_my_mac(ethhdr->h_dest)) | ||
1134 | return -1; | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | ||
1140 | int hdr_size) | ||
1141 | { | ||
1142 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1143 | struct orig_node *orig_node; | ||
1144 | struct neigh_node *router; | ||
1145 | struct batman_if *batman_if; | ||
1146 | uint8_t dstaddr[ETH_ALEN]; | ||
1147 | struct unicast_packet *unicast_packet; | ||
1148 | struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1149 | int ret; | ||
1150 | struct sk_buff *new_skb; | ||
1151 | |||
1152 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1153 | |||
1154 | /* TTL exceeded */ | ||
1155 | if (unicast_packet->ttl < 2) { | ||
1156 | pr_debug("Warning - can't forward unicast packet from %pM to " | ||
1157 | "%pM: ttl exceeded\n", ethhdr->h_source, | ||
1158 | unicast_packet->dest); | ||
1159 | return NET_RX_DROP; | ||
1160 | } | ||
1161 | |||
1162 | /* get routing information */ | ||
1163 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
1164 | orig_node = ((struct orig_node *) | ||
1165 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
1166 | unicast_packet->dest)); | ||
1167 | |||
1168 | router = find_router(bat_priv, orig_node, recv_if); | ||
1169 | |||
1170 | if (!router) { | ||
1171 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1172 | return NET_RX_DROP; | ||
1173 | } | ||
1174 | |||
1175 | /* don't lock while sending the packets ... we therefore | ||
1176 | * copy the required data before sending */ | ||
1177 | |||
1178 | batman_if = router->if_incoming; | ||
1179 | memcpy(dstaddr, router->addr, ETH_ALEN); | ||
1180 | |||
1181 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1182 | |||
1183 | /* create a copy of the skb, if needed, to modify it. */ | ||
1184 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | ||
1185 | return NET_RX_DROP; | ||
1186 | |||
1187 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1188 | |||
1189 | if (unicast_packet->packet_type == BAT_UNICAST && | ||
1190 | atomic_read(&bat_priv->fragmentation) && | ||
1191 | skb->len > batman_if->net_dev->mtu) | ||
1192 | return frag_send_skb(skb, bat_priv, batman_if, | ||
1193 | dstaddr); | ||
1194 | |||
1195 | if (unicast_packet->packet_type == BAT_UNICAST_FRAG && | ||
1196 | 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) { | ||
1197 | |||
1198 | ret = frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
1199 | |||
1200 | if (ret == NET_RX_DROP) | ||
1201 | return NET_RX_DROP; | ||
1202 | |||
1203 | /* packet was buffered for late merge */ | ||
1204 | if (!new_skb) | ||
1205 | return NET_RX_SUCCESS; | ||
1206 | |||
1207 | skb = new_skb; | ||
1208 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1209 | } | ||
1210 | |||
1211 | /* decrement ttl */ | ||
1212 | unicast_packet->ttl--; | ||
1213 | |||
1214 | /* route it */ | ||
1215 | send_skb_packet(skb, batman_if, dstaddr); | ||
1216 | |||
1217 | return NET_RX_SUCCESS; | ||
1218 | } | ||
1219 | |||
1220 | int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1221 | { | ||
1222 | struct unicast_packet *unicast_packet; | ||
1223 | int hdr_size = sizeof(struct unicast_packet); | ||
1224 | |||
1225 | if (check_unicast_packet(skb, hdr_size) < 0) | ||
1226 | return NET_RX_DROP; | ||
1227 | |||
1228 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1229 | |||
1230 | /* packet for me */ | ||
1231 | if (is_my_mac(unicast_packet->dest)) { | ||
1232 | interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); | ||
1233 | return NET_RX_SUCCESS; | ||
1234 | } | ||
1235 | |||
1236 | return route_unicast_packet(skb, recv_if, hdr_size); | ||
1237 | } | ||
1238 | |||
1239 | int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1240 | { | ||
1241 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1242 | struct unicast_frag_packet *unicast_packet; | ||
1243 | int hdr_size = sizeof(struct unicast_frag_packet); | ||
1244 | struct sk_buff *new_skb = NULL; | ||
1245 | int ret; | ||
1246 | |||
1247 | if (check_unicast_packet(skb, hdr_size) < 0) | ||
1248 | return NET_RX_DROP; | ||
1249 | |||
1250 | unicast_packet = (struct unicast_frag_packet *)skb->data; | ||
1251 | |||
1252 | /* packet for me */ | ||
1253 | if (is_my_mac(unicast_packet->dest)) { | ||
1254 | |||
1255 | ret = frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
1256 | |||
1257 | if (ret == NET_RX_DROP) | ||
1258 | return NET_RX_DROP; | ||
1259 | |||
1260 | /* packet was buffered for late merge */ | ||
1261 | if (!new_skb) | ||
1262 | return NET_RX_SUCCESS; | ||
1263 | |||
1264 | interface_rx(recv_if->soft_iface, new_skb, recv_if, | ||
1265 | sizeof(struct unicast_packet)); | ||
1266 | return NET_RX_SUCCESS; | ||
1267 | } | ||
1268 | |||
1269 | return route_unicast_packet(skb, recv_if, hdr_size); | ||
1270 | } | ||
1271 | |||
1272 | |||
1273 | int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1274 | { | ||
1275 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1276 | struct orig_node *orig_node; | ||
1277 | struct bcast_packet *bcast_packet; | ||
1278 | struct ethhdr *ethhdr; | ||
1279 | int hdr_size = sizeof(struct bcast_packet); | ||
1280 | int32_t seq_diff; | ||
1281 | |||
1282 | /* drop packet if it has not necessary minimum size */ | ||
1283 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1284 | return NET_RX_DROP; | ||
1285 | |||
1286 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1287 | |||
1288 | /* packet with broadcast indication but unicast recipient */ | ||
1289 | if (!is_broadcast_ether_addr(ethhdr->h_dest)) | ||
1290 | return NET_RX_DROP; | ||
1291 | |||
1292 | /* packet with broadcast sender address */ | ||
1293 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
1294 | return NET_RX_DROP; | ||
1295 | |||
1296 | /* ignore broadcasts sent by myself */ | ||
1297 | if (is_my_mac(ethhdr->h_source)) | ||
1298 | return NET_RX_DROP; | ||
1299 | |||
1300 | bcast_packet = (struct bcast_packet *)skb->data; | ||
1301 | |||
1302 | /* ignore broadcasts originated by myself */ | ||
1303 | if (is_my_mac(bcast_packet->orig)) | ||
1304 | return NET_RX_DROP; | ||
1305 | |||
1306 | if (bcast_packet->ttl < 2) | ||
1307 | return NET_RX_DROP; | ||
1308 | |||
1309 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
1310 | orig_node = ((struct orig_node *) | ||
1311 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
1312 | bcast_packet->orig)); | ||
1313 | |||
1314 | if (!orig_node) { | ||
1315 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1316 | return NET_RX_DROP; | ||
1317 | } | ||
1318 | |||
1319 | /* check whether the packet is a duplicate */ | ||
1320 | if (get_bit_status(orig_node->bcast_bits, | ||
1321 | orig_node->last_bcast_seqno, | ||
1322 | ntohl(bcast_packet->seqno))) { | ||
1323 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1324 | return NET_RX_DROP; | ||
1325 | } | ||
1326 | |||
1327 | seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno; | ||
1328 | |||
1329 | /* check whether the packet is old and the host just restarted. */ | ||
1330 | if (window_protected(bat_priv, seq_diff, | ||
1331 | &orig_node->bcast_seqno_reset)) { | ||
1332 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1333 | return NET_RX_DROP; | ||
1334 | } | ||
1335 | |||
1336 | /* mark broadcast in flood history, update window position | ||
1337 | * if required. */ | ||
1338 | if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) | ||
1339 | orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); | ||
1340 | |||
1341 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1342 | /* rebroadcast packet */ | ||
1343 | add_bcast_packet_to_list(bat_priv, skb); | ||
1344 | |||
1345 | /* broadcast for me */ | ||
1346 | interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); | ||
1347 | |||
1348 | return NET_RX_SUCCESS; | ||
1349 | } | ||
1350 | |||
1351 | int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if) | ||
1352 | { | ||
1353 | struct vis_packet *vis_packet; | ||
1354 | struct ethhdr *ethhdr; | ||
1355 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1356 | int hdr_size = sizeof(struct vis_packet); | ||
1357 | |||
1358 | /* keep skb linear */ | ||
1359 | if (skb_linearize(skb) < 0) | ||
1360 | return NET_RX_DROP; | ||
1361 | |||
1362 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1363 | return NET_RX_DROP; | ||
1364 | |||
1365 | vis_packet = (struct vis_packet *)skb->data; | ||
1366 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1367 | |||
1368 | /* not for me */ | ||
1369 | if (!is_my_mac(ethhdr->h_dest)) | ||
1370 | return NET_RX_DROP; | ||
1371 | |||
1372 | /* ignore own packets */ | ||
1373 | if (is_my_mac(vis_packet->vis_orig)) | ||
1374 | return NET_RX_DROP; | ||
1375 | |||
1376 | if (is_my_mac(vis_packet->sender_orig)) | ||
1377 | return NET_RX_DROP; | ||
1378 | |||
1379 | switch (vis_packet->vis_type) { | ||
1380 | case VIS_TYPE_SERVER_SYNC: | ||
1381 | receive_server_sync_packet(bat_priv, vis_packet, | ||
1382 | skb_headlen(skb)); | ||
1383 | break; | ||
1384 | |||
1385 | case VIS_TYPE_CLIENT_UPDATE: | ||
1386 | receive_client_update_packet(bat_priv, vis_packet, | ||
1387 | skb_headlen(skb)); | ||
1388 | break; | ||
1389 | |||
1390 | default: /* ignore unknown packet */ | ||
1391 | break; | ||
1392 | } | ||
1393 | |||
1394 | /* We take a copy of the data in the packet, so we should | ||
1395 | always free the skbuf. */ | ||
1396 | return NET_RX_DROP; | ||
1397 | } | ||
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h new file mode 100644 index 000000000000..f108f230bfdb --- /dev/null +++ b/net/batman-adv/routing.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_ROUTING_H_ | ||
23 | #define _NET_BATMAN_ADV_ROUTING_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | void slide_own_bcast_window(struct batman_if *batman_if); | ||
28 | void receive_bat_packet(struct ethhdr *ethhdr, | ||
29 | struct batman_packet *batman_packet, | ||
30 | unsigned char *hna_buff, int hna_buff_len, | ||
31 | struct batman_if *if_incoming); | ||
32 | void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
33 | struct neigh_node *neigh_node, unsigned char *hna_buff, | ||
34 | int hna_buff_len); | ||
35 | int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | ||
36 | int hdr_size); | ||
37 | int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
38 | int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
39 | int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
40 | int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
41 | int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
42 | int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if); | ||
43 | struct neigh_node *find_router(struct bat_priv *bat_priv, | ||
44 | struct orig_node *orig_node, struct batman_if *recv_if); | ||
45 | void update_bonding_candidates(struct bat_priv *bat_priv, | ||
46 | struct orig_node *orig_node); | ||
47 | |||
48 | #endif /* _NET_BATMAN_ADV_ROUTING_H_ */ | ||
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c new file mode 100644 index 000000000000..b89b9f7709ae --- /dev/null +++ b/net/batman-adv/send.c | |||
@@ -0,0 +1,585 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "send.h" | ||
24 | #include "routing.h" | ||
25 | #include "translation-table.h" | ||
26 | #include "soft-interface.h" | ||
27 | #include "hard-interface.h" | ||
28 | #include "types.h" | ||
29 | #include "vis.h" | ||
30 | #include "aggregation.h" | ||
31 | #include "gateway_common.h" | ||
32 | #include "originator.h" | ||
33 | |||
34 | static void send_outstanding_bcast_packet(struct work_struct *work); | ||
35 | |||
36 | /* apply hop penalty for a normal link */ | ||
37 | static uint8_t hop_penalty(const uint8_t tq, struct bat_priv *bat_priv) | ||
38 | { | ||
39 | int hop_penalty = atomic_read(&bat_priv->hop_penalty); | ||
40 | return (tq * (TQ_MAX_VALUE - hop_penalty)) / (TQ_MAX_VALUE); | ||
41 | } | ||
42 | |||
43 | /* when do we schedule our own packet to be sent */ | ||
44 | static unsigned long own_send_time(struct bat_priv *bat_priv) | ||
45 | { | ||
46 | return jiffies + msecs_to_jiffies( | ||
47 | atomic_read(&bat_priv->orig_interval) - | ||
48 | JITTER + (random32() % 2*JITTER)); | ||
49 | } | ||
50 | |||
51 | /* when do we schedule a forwarded packet to be sent */ | ||
52 | static unsigned long forward_send_time(struct bat_priv *bat_priv) | ||
53 | { | ||
54 | return jiffies + msecs_to_jiffies(random32() % (JITTER/2)); | ||
55 | } | ||
56 | |||
57 | /* send out an already prepared packet to the given address via the | ||
58 | * specified batman interface */ | ||
59 | int send_skb_packet(struct sk_buff *skb, | ||
60 | struct batman_if *batman_if, | ||
61 | uint8_t *dst_addr) | ||
62 | { | ||
63 | struct ethhdr *ethhdr; | ||
64 | |||
65 | if (batman_if->if_status != IF_ACTIVE) | ||
66 | goto send_skb_err; | ||
67 | |||
68 | if (unlikely(!batman_if->net_dev)) | ||
69 | goto send_skb_err; | ||
70 | |||
71 | if (!(batman_if->net_dev->flags & IFF_UP)) { | ||
72 | pr_warning("Interface %s is not up - can't send packet via " | ||
73 | "that interface!\n", batman_if->net_dev->name); | ||
74 | goto send_skb_err; | ||
75 | } | ||
76 | |||
77 | /* push to the ethernet header. */ | ||
78 | if (my_skb_head_push(skb, sizeof(struct ethhdr)) < 0) | ||
79 | goto send_skb_err; | ||
80 | |||
81 | skb_reset_mac_header(skb); | ||
82 | |||
83 | ethhdr = (struct ethhdr *) skb_mac_header(skb); | ||
84 | memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN); | ||
85 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); | ||
86 | ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); | ||
87 | |||
88 | skb_set_network_header(skb, ETH_HLEN); | ||
89 | skb->priority = TC_PRIO_CONTROL; | ||
90 | skb->protocol = __constant_htons(ETH_P_BATMAN); | ||
91 | |||
92 | skb->dev = batman_if->net_dev; | ||
93 | |||
94 | /* dev_queue_xmit() returns a negative result on error. However on | ||
95 | * congestion and traffic shaping, it drops and returns NET_XMIT_DROP | ||
96 | * (which is > 0). This will not be treated as an error. */ | ||
97 | |||
98 | return dev_queue_xmit(skb); | ||
99 | send_skb_err: | ||
100 | kfree_skb(skb); | ||
101 | return NET_XMIT_DROP; | ||
102 | } | ||
103 | |||
104 | /* Send a packet to a given interface */ | ||
105 | static void send_packet_to_if(struct forw_packet *forw_packet, | ||
106 | struct batman_if *batman_if) | ||
107 | { | ||
108 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
109 | char *fwd_str; | ||
110 | uint8_t packet_num; | ||
111 | int16_t buff_pos; | ||
112 | struct batman_packet *batman_packet; | ||
113 | struct sk_buff *skb; | ||
114 | |||
115 | if (batman_if->if_status != IF_ACTIVE) | ||
116 | return; | ||
117 | |||
118 | packet_num = 0; | ||
119 | buff_pos = 0; | ||
120 | batman_packet = (struct batman_packet *)forw_packet->skb->data; | ||
121 | |||
122 | /* adjust all flags and log packets */ | ||
123 | while (aggregated_packet(buff_pos, | ||
124 | forw_packet->packet_len, | ||
125 | batman_packet->num_hna)) { | ||
126 | |||
127 | /* we might have aggregated direct link packets with an | ||
128 | * ordinary base packet */ | ||
129 | if ((forw_packet->direct_link_flags & (1 << packet_num)) && | ||
130 | (forw_packet->if_incoming == batman_if)) | ||
131 | batman_packet->flags |= DIRECTLINK; | ||
132 | else | ||
133 | batman_packet->flags &= ~DIRECTLINK; | ||
134 | |||
135 | fwd_str = (packet_num > 0 ? "Forwarding" : (forw_packet->own ? | ||
136 | "Sending own" : | ||
137 | "Forwarding")); | ||
138 | bat_dbg(DBG_BATMAN, bat_priv, | ||
139 | "%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d," | ||
140 | " IDF %s) on interface %s [%pM]\n", | ||
141 | fwd_str, (packet_num > 0 ? "aggregated " : ""), | ||
142 | batman_packet->orig, ntohl(batman_packet->seqno), | ||
143 | batman_packet->tq, batman_packet->ttl, | ||
144 | (batman_packet->flags & DIRECTLINK ? | ||
145 | "on" : "off"), | ||
146 | batman_if->net_dev->name, batman_if->net_dev->dev_addr); | ||
147 | |||
148 | buff_pos += sizeof(struct batman_packet) + | ||
149 | (batman_packet->num_hna * ETH_ALEN); | ||
150 | packet_num++; | ||
151 | batman_packet = (struct batman_packet *) | ||
152 | (forw_packet->skb->data + buff_pos); | ||
153 | } | ||
154 | |||
155 | /* create clone because function is called more than once */ | ||
156 | skb = skb_clone(forw_packet->skb, GFP_ATOMIC); | ||
157 | if (skb) | ||
158 | send_skb_packet(skb, batman_if, broadcast_addr); | ||
159 | } | ||
160 | |||
161 | /* send a batman packet */ | ||
162 | static void send_packet(struct forw_packet *forw_packet) | ||
163 | { | ||
164 | struct batman_if *batman_if; | ||
165 | struct net_device *soft_iface; | ||
166 | struct bat_priv *bat_priv; | ||
167 | struct batman_packet *batman_packet = | ||
168 | (struct batman_packet *)(forw_packet->skb->data); | ||
169 | unsigned char directlink = (batman_packet->flags & DIRECTLINK ? 1 : 0); | ||
170 | |||
171 | if (!forw_packet->if_incoming) { | ||
172 | pr_err("Error - can't forward packet: incoming iface not " | ||
173 | "specified\n"); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | soft_iface = forw_packet->if_incoming->soft_iface; | ||
178 | bat_priv = netdev_priv(soft_iface); | ||
179 | |||
180 | if (forw_packet->if_incoming->if_status != IF_ACTIVE) | ||
181 | return; | ||
182 | |||
183 | /* multihomed peer assumed */ | ||
184 | /* non-primary OGMs are only broadcasted on their interface */ | ||
185 | if ((directlink && (batman_packet->ttl == 1)) || | ||
186 | (forw_packet->own && (forw_packet->if_incoming->if_num > 0))) { | ||
187 | |||
188 | /* FIXME: what about aggregated packets ? */ | ||
189 | bat_dbg(DBG_BATMAN, bat_priv, | ||
190 | "%s packet (originator %pM, seqno %d, TTL %d) " | ||
191 | "on interface %s [%pM]\n", | ||
192 | (forw_packet->own ? "Sending own" : "Forwarding"), | ||
193 | batman_packet->orig, ntohl(batman_packet->seqno), | ||
194 | batman_packet->ttl, | ||
195 | forw_packet->if_incoming->net_dev->name, | ||
196 | forw_packet->if_incoming->net_dev->dev_addr); | ||
197 | |||
198 | /* skb is only used once and than forw_packet is free'd */ | ||
199 | send_skb_packet(forw_packet->skb, forw_packet->if_incoming, | ||
200 | broadcast_addr); | ||
201 | forw_packet->skb = NULL; | ||
202 | |||
203 | return; | ||
204 | } | ||
205 | |||
206 | /* broadcast on every interface */ | ||
207 | rcu_read_lock(); | ||
208 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
209 | if (batman_if->soft_iface != soft_iface) | ||
210 | continue; | ||
211 | |||
212 | send_packet_to_if(forw_packet, batman_if); | ||
213 | } | ||
214 | rcu_read_unlock(); | ||
215 | } | ||
216 | |||
217 | static void rebuild_batman_packet(struct bat_priv *bat_priv, | ||
218 | struct batman_if *batman_if) | ||
219 | { | ||
220 | int new_len; | ||
221 | unsigned char *new_buff; | ||
222 | struct batman_packet *batman_packet; | ||
223 | |||
224 | new_len = sizeof(struct batman_packet) + | ||
225 | (bat_priv->num_local_hna * ETH_ALEN); | ||
226 | new_buff = kmalloc(new_len, GFP_ATOMIC); | ||
227 | |||
228 | /* keep old buffer if kmalloc should fail */ | ||
229 | if (new_buff) { | ||
230 | memcpy(new_buff, batman_if->packet_buff, | ||
231 | sizeof(struct batman_packet)); | ||
232 | batman_packet = (struct batman_packet *)new_buff; | ||
233 | |||
234 | batman_packet->num_hna = hna_local_fill_buffer(bat_priv, | ||
235 | new_buff + sizeof(struct batman_packet), | ||
236 | new_len - sizeof(struct batman_packet)); | ||
237 | |||
238 | kfree(batman_if->packet_buff); | ||
239 | batman_if->packet_buff = new_buff; | ||
240 | batman_if->packet_len = new_len; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | void schedule_own_packet(struct batman_if *batman_if) | ||
245 | { | ||
246 | struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); | ||
247 | unsigned long send_time; | ||
248 | struct batman_packet *batman_packet; | ||
249 | int vis_server; | ||
250 | |||
251 | if ((batman_if->if_status == IF_NOT_IN_USE) || | ||
252 | (batman_if->if_status == IF_TO_BE_REMOVED)) | ||
253 | return; | ||
254 | |||
255 | vis_server = atomic_read(&bat_priv->vis_mode); | ||
256 | |||
257 | /** | ||
258 | * the interface gets activated here to avoid race conditions between | ||
259 | * the moment of activating the interface in | ||
260 | * hardif_activate_interface() where the originator mac is set and | ||
261 | * outdated packets (especially uninitialized mac addresses) in the | ||
262 | * packet queue | ||
263 | */ | ||
264 | if (batman_if->if_status == IF_TO_BE_ACTIVATED) | ||
265 | batman_if->if_status = IF_ACTIVE; | ||
266 | |||
267 | /* if local hna has changed and interface is a primary interface */ | ||
268 | if ((atomic_read(&bat_priv->hna_local_changed)) && | ||
269 | (batman_if == bat_priv->primary_if)) | ||
270 | rebuild_batman_packet(bat_priv, batman_if); | ||
271 | |||
272 | /** | ||
273 | * NOTE: packet_buff might just have been re-allocated in | ||
274 | * rebuild_batman_packet() | ||
275 | */ | ||
276 | batman_packet = (struct batman_packet *)batman_if->packet_buff; | ||
277 | |||
278 | /* change sequence number to network order */ | ||
279 | batman_packet->seqno = | ||
280 | htonl((uint32_t)atomic_read(&batman_if->seqno)); | ||
281 | |||
282 | if (vis_server == VIS_TYPE_SERVER_SYNC) | ||
283 | batman_packet->flags |= VIS_SERVER; | ||
284 | else | ||
285 | batman_packet->flags &= ~VIS_SERVER; | ||
286 | |||
287 | if ((batman_if == bat_priv->primary_if) && | ||
288 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) | ||
289 | batman_packet->gw_flags = | ||
290 | (uint8_t)atomic_read(&bat_priv->gw_bandwidth); | ||
291 | else | ||
292 | batman_packet->gw_flags = 0; | ||
293 | |||
294 | atomic_inc(&batman_if->seqno); | ||
295 | |||
296 | slide_own_bcast_window(batman_if); | ||
297 | send_time = own_send_time(bat_priv); | ||
298 | add_bat_packet_to_list(bat_priv, | ||
299 | batman_if->packet_buff, | ||
300 | batman_if->packet_len, | ||
301 | batman_if, 1, send_time); | ||
302 | } | ||
303 | |||
304 | void schedule_forward_packet(struct orig_node *orig_node, | ||
305 | struct ethhdr *ethhdr, | ||
306 | struct batman_packet *batman_packet, | ||
307 | uint8_t directlink, int hna_buff_len, | ||
308 | struct batman_if *if_incoming) | ||
309 | { | ||
310 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
311 | unsigned char in_tq, in_ttl, tq_avg = 0; | ||
312 | unsigned long send_time; | ||
313 | |||
314 | if (batman_packet->ttl <= 1) { | ||
315 | bat_dbg(DBG_BATMAN, bat_priv, "ttl exceeded\n"); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | in_tq = batman_packet->tq; | ||
320 | in_ttl = batman_packet->ttl; | ||
321 | |||
322 | batman_packet->ttl--; | ||
323 | memcpy(batman_packet->prev_sender, ethhdr->h_source, ETH_ALEN); | ||
324 | |||
325 | /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast | ||
326 | * of our best tq value */ | ||
327 | if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { | ||
328 | |||
329 | /* rebroadcast ogm of best ranking neighbor as is */ | ||
330 | if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) { | ||
331 | batman_packet->tq = orig_node->router->tq_avg; | ||
332 | |||
333 | if (orig_node->router->last_ttl) | ||
334 | batman_packet->ttl = orig_node->router->last_ttl | ||
335 | - 1; | ||
336 | } | ||
337 | |||
338 | tq_avg = orig_node->router->tq_avg; | ||
339 | } | ||
340 | |||
341 | /* apply hop penalty */ | ||
342 | batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); | ||
343 | |||
344 | bat_dbg(DBG_BATMAN, bat_priv, | ||
345 | "Forwarding packet: tq_orig: %i, tq_avg: %i, " | ||
346 | "tq_forw: %i, ttl_orig: %i, ttl_forw: %i\n", | ||
347 | in_tq, tq_avg, batman_packet->tq, in_ttl - 1, | ||
348 | batman_packet->ttl); | ||
349 | |||
350 | batman_packet->seqno = htonl(batman_packet->seqno); | ||
351 | |||
352 | /* switch of primaries first hop flag when forwarding */ | ||
353 | batman_packet->flags &= ~PRIMARIES_FIRST_HOP; | ||
354 | if (directlink) | ||
355 | batman_packet->flags |= DIRECTLINK; | ||
356 | else | ||
357 | batman_packet->flags &= ~DIRECTLINK; | ||
358 | |||
359 | send_time = forward_send_time(bat_priv); | ||
360 | add_bat_packet_to_list(bat_priv, | ||
361 | (unsigned char *)batman_packet, | ||
362 | sizeof(struct batman_packet) + hna_buff_len, | ||
363 | if_incoming, 0, send_time); | ||
364 | } | ||
365 | |||
366 | static void forw_packet_free(struct forw_packet *forw_packet) | ||
367 | { | ||
368 | if (forw_packet->skb) | ||
369 | kfree_skb(forw_packet->skb); | ||
370 | kfree(forw_packet); | ||
371 | } | ||
372 | |||
373 | static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, | ||
374 | struct forw_packet *forw_packet, | ||
375 | unsigned long send_time) | ||
376 | { | ||
377 | INIT_HLIST_NODE(&forw_packet->list); | ||
378 | |||
379 | /* add new packet to packet list */ | ||
380 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
381 | hlist_add_head(&forw_packet->list, &bat_priv->forw_bcast_list); | ||
382 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
383 | |||
384 | /* start timer for this packet */ | ||
385 | INIT_DELAYED_WORK(&forw_packet->delayed_work, | ||
386 | send_outstanding_bcast_packet); | ||
387 | queue_delayed_work(bat_event_workqueue, &forw_packet->delayed_work, | ||
388 | send_time); | ||
389 | } | ||
390 | |||
391 | #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) | ||
392 | /* add a broadcast packet to the queue and setup timers. broadcast packets | ||
393 | * are sent multiple times to increase probability for beeing received. | ||
394 | * | ||
395 | * This function returns NETDEV_TX_OK on success and NETDEV_TX_BUSY on | ||
396 | * errors. | ||
397 | * | ||
398 | * The skb is not consumed, so the caller should make sure that the | ||
399 | * skb is freed. */ | ||
400 | int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) | ||
401 | { | ||
402 | struct forw_packet *forw_packet; | ||
403 | struct bcast_packet *bcast_packet; | ||
404 | |||
405 | if (!atomic_dec_not_zero(&bat_priv->bcast_queue_left)) { | ||
406 | bat_dbg(DBG_BATMAN, bat_priv, "bcast packet queue full\n"); | ||
407 | goto out; | ||
408 | } | ||
409 | |||
410 | if (!bat_priv->primary_if) | ||
411 | goto out; | ||
412 | |||
413 | forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | ||
414 | |||
415 | if (!forw_packet) | ||
416 | goto out_and_inc; | ||
417 | |||
418 | skb = skb_copy(skb, GFP_ATOMIC); | ||
419 | if (!skb) | ||
420 | goto packet_free; | ||
421 | |||
422 | /* as we have a copy now, it is safe to decrease the TTL */ | ||
423 | bcast_packet = (struct bcast_packet *)skb->data; | ||
424 | bcast_packet->ttl--; | ||
425 | |||
426 | skb_reset_mac_header(skb); | ||
427 | |||
428 | forw_packet->skb = skb; | ||
429 | forw_packet->if_incoming = bat_priv->primary_if; | ||
430 | |||
431 | /* how often did we send the bcast packet ? */ | ||
432 | forw_packet->num_packets = 0; | ||
433 | |||
434 | _add_bcast_packet_to_list(bat_priv, forw_packet, 1); | ||
435 | return NETDEV_TX_OK; | ||
436 | |||
437 | packet_free: | ||
438 | kfree(forw_packet); | ||
439 | out_and_inc: | ||
440 | atomic_inc(&bat_priv->bcast_queue_left); | ||
441 | out: | ||
442 | return NETDEV_TX_BUSY; | ||
443 | } | ||
444 | |||
445 | static void send_outstanding_bcast_packet(struct work_struct *work) | ||
446 | { | ||
447 | struct batman_if *batman_if; | ||
448 | struct delayed_work *delayed_work = | ||
449 | container_of(work, struct delayed_work, work); | ||
450 | struct forw_packet *forw_packet = | ||
451 | container_of(delayed_work, struct forw_packet, delayed_work); | ||
452 | struct sk_buff *skb1; | ||
453 | struct net_device *soft_iface = forw_packet->if_incoming->soft_iface; | ||
454 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
455 | |||
456 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
457 | hlist_del(&forw_packet->list); | ||
458 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
459 | |||
460 | if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) | ||
461 | goto out; | ||
462 | |||
463 | /* rebroadcast packet */ | ||
464 | rcu_read_lock(); | ||
465 | list_for_each_entry_rcu(batman_if, &if_list, list) { | ||
466 | if (batman_if->soft_iface != soft_iface) | ||
467 | continue; | ||
468 | |||
469 | /* send a copy of the saved skb */ | ||
470 | skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC); | ||
471 | if (skb1) | ||
472 | send_skb_packet(skb1, batman_if, broadcast_addr); | ||
473 | } | ||
474 | rcu_read_unlock(); | ||
475 | |||
476 | forw_packet->num_packets++; | ||
477 | |||
478 | /* if we still have some more bcasts to send */ | ||
479 | if (forw_packet->num_packets < 3) { | ||
480 | _add_bcast_packet_to_list(bat_priv, forw_packet, | ||
481 | ((5 * HZ) / 1000)); | ||
482 | return; | ||
483 | } | ||
484 | |||
485 | out: | ||
486 | forw_packet_free(forw_packet); | ||
487 | atomic_inc(&bat_priv->bcast_queue_left); | ||
488 | } | ||
489 | |||
490 | void send_outstanding_bat_packet(struct work_struct *work) | ||
491 | { | ||
492 | struct delayed_work *delayed_work = | ||
493 | container_of(work, struct delayed_work, work); | ||
494 | struct forw_packet *forw_packet = | ||
495 | container_of(delayed_work, struct forw_packet, delayed_work); | ||
496 | struct bat_priv *bat_priv; | ||
497 | |||
498 | bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface); | ||
499 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
500 | hlist_del(&forw_packet->list); | ||
501 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
502 | |||
503 | if (atomic_read(&bat_priv->mesh_state) == MESH_DEACTIVATING) | ||
504 | goto out; | ||
505 | |||
506 | send_packet(forw_packet); | ||
507 | |||
508 | /** | ||
509 | * we have to have at least one packet in the queue | ||
510 | * to determine the queues wake up time unless we are | ||
511 | * shutting down | ||
512 | */ | ||
513 | if (forw_packet->own) | ||
514 | schedule_own_packet(forw_packet->if_incoming); | ||
515 | |||
516 | out: | ||
517 | /* don't count own packet */ | ||
518 | if (!forw_packet->own) | ||
519 | atomic_inc(&bat_priv->batman_queue_left); | ||
520 | |||
521 | forw_packet_free(forw_packet); | ||
522 | } | ||
523 | |||
524 | void purge_outstanding_packets(struct bat_priv *bat_priv, | ||
525 | struct batman_if *batman_if) | ||
526 | { | ||
527 | struct forw_packet *forw_packet; | ||
528 | struct hlist_node *tmp_node, *safe_tmp_node; | ||
529 | |||
530 | if (batman_if) | ||
531 | bat_dbg(DBG_BATMAN, bat_priv, | ||
532 | "purge_outstanding_packets(): %s\n", | ||
533 | batman_if->net_dev->name); | ||
534 | else | ||
535 | bat_dbg(DBG_BATMAN, bat_priv, | ||
536 | "purge_outstanding_packets()\n"); | ||
537 | |||
538 | /* free bcast list */ | ||
539 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
540 | hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, | ||
541 | &bat_priv->forw_bcast_list, list) { | ||
542 | |||
543 | /** | ||
544 | * if purge_outstanding_packets() was called with an argmument | ||
545 | * we delete only packets belonging to the given interface | ||
546 | */ | ||
547 | if ((batman_if) && | ||
548 | (forw_packet->if_incoming != batman_if)) | ||
549 | continue; | ||
550 | |||
551 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
552 | |||
553 | /** | ||
554 | * send_outstanding_bcast_packet() will lock the list to | ||
555 | * delete the item from the list | ||
556 | */ | ||
557 | cancel_delayed_work_sync(&forw_packet->delayed_work); | ||
558 | spin_lock_bh(&bat_priv->forw_bcast_list_lock); | ||
559 | } | ||
560 | spin_unlock_bh(&bat_priv->forw_bcast_list_lock); | ||
561 | |||
562 | /* free batman packet list */ | ||
563 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
564 | hlist_for_each_entry_safe(forw_packet, tmp_node, safe_tmp_node, | ||
565 | &bat_priv->forw_bat_list, list) { | ||
566 | |||
567 | /** | ||
568 | * if purge_outstanding_packets() was called with an argmument | ||
569 | * we delete only packets belonging to the given interface | ||
570 | */ | ||
571 | if ((batman_if) && | ||
572 | (forw_packet->if_incoming != batman_if)) | ||
573 | continue; | ||
574 | |||
575 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
576 | |||
577 | /** | ||
578 | * send_outstanding_bat_packet() will lock the list to | ||
579 | * delete the item from the list | ||
580 | */ | ||
581 | cancel_delayed_work_sync(&forw_packet->delayed_work); | ||
582 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
583 | } | ||
584 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
585 | } | ||
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h new file mode 100644 index 000000000000..c4cefa8e4f85 --- /dev/null +++ b/net/batman-adv/send.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_SEND_H_ | ||
23 | #define _NET_BATMAN_ADV_SEND_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | int send_skb_packet(struct sk_buff *skb, | ||
28 | struct batman_if *batman_if, | ||
29 | uint8_t *dst_addr); | ||
30 | void schedule_own_packet(struct batman_if *batman_if); | ||
31 | void schedule_forward_packet(struct orig_node *orig_node, | ||
32 | struct ethhdr *ethhdr, | ||
33 | struct batman_packet *batman_packet, | ||
34 | uint8_t directlink, int hna_buff_len, | ||
35 | struct batman_if *if_outgoing); | ||
36 | int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb); | ||
37 | void send_outstanding_bat_packet(struct work_struct *work); | ||
38 | void purge_outstanding_packets(struct bat_priv *bat_priv, | ||
39 | struct batman_if *batman_if); | ||
40 | |||
41 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ | ||
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c new file mode 100644 index 000000000000..e89ede192ed0 --- /dev/null +++ b/net/batman-adv/soft-interface.c | |||
@@ -0,0 +1,697 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "soft-interface.h" | ||
24 | #include "hard-interface.h" | ||
25 | #include "routing.h" | ||
26 | #include "send.h" | ||
27 | #include "bat_debugfs.h" | ||
28 | #include "translation-table.h" | ||
29 | #include "types.h" | ||
30 | #include "hash.h" | ||
31 | #include "gateway_common.h" | ||
32 | #include "gateway_client.h" | ||
33 | #include "send.h" | ||
34 | #include "bat_sysfs.h" | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/ethtool.h> | ||
37 | #include <linux/etherdevice.h> | ||
38 | #include <linux/if_vlan.h> | ||
39 | #include "unicast.h" | ||
40 | #include "routing.h" | ||
41 | |||
42 | |||
43 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); | ||
44 | static void bat_get_drvinfo(struct net_device *dev, | ||
45 | struct ethtool_drvinfo *info); | ||
46 | static u32 bat_get_msglevel(struct net_device *dev); | ||
47 | static void bat_set_msglevel(struct net_device *dev, u32 value); | ||
48 | static u32 bat_get_link(struct net_device *dev); | ||
49 | static u32 bat_get_rx_csum(struct net_device *dev); | ||
50 | static int bat_set_rx_csum(struct net_device *dev, u32 data); | ||
51 | |||
52 | static const struct ethtool_ops bat_ethtool_ops = { | ||
53 | .get_settings = bat_get_settings, | ||
54 | .get_drvinfo = bat_get_drvinfo, | ||
55 | .get_msglevel = bat_get_msglevel, | ||
56 | .set_msglevel = bat_set_msglevel, | ||
57 | .get_link = bat_get_link, | ||
58 | .get_rx_csum = bat_get_rx_csum, | ||
59 | .set_rx_csum = bat_set_rx_csum | ||
60 | }; | ||
61 | |||
62 | int my_skb_head_push(struct sk_buff *skb, unsigned int len) | ||
63 | { | ||
64 | int result; | ||
65 | |||
66 | /** | ||
67 | * TODO: We must check if we can release all references to non-payload | ||
68 | * data using skb_header_release in our skbs to allow skb_cow_header to | ||
69 | * work optimally. This means that those skbs are not allowed to read | ||
70 | * or write any data which is before the current position of skb->data | ||
71 | * after that call and thus allow other skbs with the same data buffer | ||
72 | * to write freely in that area. | ||
73 | */ | ||
74 | result = skb_cow_head(skb, len); | ||
75 | if (result < 0) | ||
76 | return result; | ||
77 | |||
78 | skb_push(skb, len); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static void softif_neigh_free_ref(struct kref *refcount) | ||
83 | { | ||
84 | struct softif_neigh *softif_neigh; | ||
85 | |||
86 | softif_neigh = container_of(refcount, struct softif_neigh, refcount); | ||
87 | kfree(softif_neigh); | ||
88 | } | ||
89 | |||
90 | static void softif_neigh_free_rcu(struct rcu_head *rcu) | ||
91 | { | ||
92 | struct softif_neigh *softif_neigh; | ||
93 | |||
94 | softif_neigh = container_of(rcu, struct softif_neigh, rcu); | ||
95 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
96 | } | ||
97 | |||
98 | void softif_neigh_purge(struct bat_priv *bat_priv) | ||
99 | { | ||
100 | struct softif_neigh *softif_neigh, *softif_neigh_tmp; | ||
101 | struct hlist_node *node, *node_tmp; | ||
102 | |||
103 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
104 | |||
105 | hlist_for_each_entry_safe(softif_neigh, node, node_tmp, | ||
106 | &bat_priv->softif_neigh_list, list) { | ||
107 | |||
108 | if ((!time_after(jiffies, softif_neigh->last_seen + | ||
109 | msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && | ||
110 | (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) | ||
111 | continue; | ||
112 | |||
113 | hlist_del_rcu(&softif_neigh->list); | ||
114 | |||
115 | if (bat_priv->softif_neigh == softif_neigh) { | ||
116 | bat_dbg(DBG_ROUTES, bat_priv, | ||
117 | "Current mesh exit point '%pM' vanished " | ||
118 | "(vid: %d).\n", | ||
119 | softif_neigh->addr, softif_neigh->vid); | ||
120 | softif_neigh_tmp = bat_priv->softif_neigh; | ||
121 | bat_priv->softif_neigh = NULL; | ||
122 | kref_put(&softif_neigh_tmp->refcount, | ||
123 | softif_neigh_free_ref); | ||
124 | } | ||
125 | |||
126 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); | ||
127 | } | ||
128 | |||
129 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
130 | } | ||
131 | |||
132 | static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, | ||
133 | uint8_t *addr, short vid) | ||
134 | { | ||
135 | struct softif_neigh *softif_neigh; | ||
136 | struct hlist_node *node; | ||
137 | |||
138 | rcu_read_lock(); | ||
139 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
140 | &bat_priv->softif_neigh_list, list) { | ||
141 | if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) | ||
142 | continue; | ||
143 | |||
144 | if (softif_neigh->vid != vid) | ||
145 | continue; | ||
146 | |||
147 | softif_neigh->last_seen = jiffies; | ||
148 | goto found; | ||
149 | } | ||
150 | |||
151 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); | ||
152 | if (!softif_neigh) | ||
153 | goto out; | ||
154 | |||
155 | memcpy(softif_neigh->addr, addr, ETH_ALEN); | ||
156 | softif_neigh->vid = vid; | ||
157 | softif_neigh->last_seen = jiffies; | ||
158 | kref_init(&softif_neigh->refcount); | ||
159 | |||
160 | INIT_HLIST_NODE(&softif_neigh->list); | ||
161 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
162 | hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); | ||
163 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
164 | |||
165 | found: | ||
166 | kref_get(&softif_neigh->refcount); | ||
167 | out: | ||
168 | rcu_read_unlock(); | ||
169 | return softif_neigh; | ||
170 | } | ||
171 | |||
172 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | ||
173 | { | ||
174 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
175 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
176 | struct softif_neigh *softif_neigh; | ||
177 | struct hlist_node *node; | ||
178 | size_t buf_size, pos; | ||
179 | char *buff; | ||
180 | |||
181 | if (!bat_priv->primary_if) { | ||
182 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
183 | "please specify interfaces to enable it\n", | ||
184 | net_dev->name); | ||
185 | } | ||
186 | |||
187 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | ||
188 | |||
189 | buf_size = 1; | ||
190 | /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ | ||
191 | rcu_read_lock(); | ||
192 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
193 | &bat_priv->softif_neigh_list, list) | ||
194 | buf_size += 30; | ||
195 | rcu_read_unlock(); | ||
196 | |||
197 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
198 | if (!buff) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | buff[0] = '\0'; | ||
202 | pos = 0; | ||
203 | |||
204 | rcu_read_lock(); | ||
205 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
206 | &bat_priv->softif_neigh_list, list) { | ||
207 | pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", | ||
208 | bat_priv->softif_neigh == softif_neigh | ||
209 | ? "=>" : " ", softif_neigh->addr, | ||
210 | softif_neigh->vid); | ||
211 | } | ||
212 | rcu_read_unlock(); | ||
213 | |||
214 | seq_printf(seq, "%s", buff); | ||
215 | kfree(buff); | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | ||
220 | short vid) | ||
221 | { | ||
222 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
223 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
224 | struct batman_packet *batman_packet; | ||
225 | struct softif_neigh *softif_neigh, *softif_neigh_tmp; | ||
226 | |||
227 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) | ||
228 | batman_packet = (struct batman_packet *) | ||
229 | (skb->data + ETH_HLEN + VLAN_HLEN); | ||
230 | else | ||
231 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); | ||
232 | |||
233 | if (batman_packet->version != COMPAT_VERSION) | ||
234 | goto err; | ||
235 | |||
236 | if (batman_packet->packet_type != BAT_PACKET) | ||
237 | goto err; | ||
238 | |||
239 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) | ||
240 | goto err; | ||
241 | |||
242 | if (is_my_mac(batman_packet->orig)) | ||
243 | goto err; | ||
244 | |||
245 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); | ||
246 | |||
247 | if (!softif_neigh) | ||
248 | goto err; | ||
249 | |||
250 | if (bat_priv->softif_neigh == softif_neigh) | ||
251 | goto out; | ||
252 | |||
253 | /* we got a neighbor but its mac is 'bigger' than ours */ | ||
254 | if (memcmp(bat_priv->primary_if->net_dev->dev_addr, | ||
255 | softif_neigh->addr, ETH_ALEN) < 0) | ||
256 | goto out; | ||
257 | |||
258 | /* switch to new 'smallest neighbor' */ | ||
259 | if ((bat_priv->softif_neigh) && | ||
260 | (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, | ||
261 | ETH_ALEN) < 0)) { | ||
262 | bat_dbg(DBG_ROUTES, bat_priv, | ||
263 | "Changing mesh exit point from %pM (vid: %d) " | ||
264 | "to %pM (vid: %d).\n", | ||
265 | bat_priv->softif_neigh->addr, | ||
266 | bat_priv->softif_neigh->vid, | ||
267 | softif_neigh->addr, softif_neigh->vid); | ||
268 | softif_neigh_tmp = bat_priv->softif_neigh; | ||
269 | bat_priv->softif_neigh = softif_neigh; | ||
270 | kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); | ||
271 | /* we need to hold the additional reference */ | ||
272 | goto err; | ||
273 | } | ||
274 | |||
275 | /* close own batX device and use softif_neigh as exit node */ | ||
276 | if ((!bat_priv->softif_neigh) && | ||
277 | (memcmp(softif_neigh->addr, | ||
278 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { | ||
279 | bat_dbg(DBG_ROUTES, bat_priv, | ||
280 | "Setting mesh exit point to %pM (vid: %d).\n", | ||
281 | softif_neigh->addr, softif_neigh->vid); | ||
282 | bat_priv->softif_neigh = softif_neigh; | ||
283 | /* we need to hold the additional reference */ | ||
284 | goto err; | ||
285 | } | ||
286 | |||
287 | out: | ||
288 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
289 | err: | ||
290 | kfree_skb(skb); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | static int interface_open(struct net_device *dev) | ||
295 | { | ||
296 | netif_start_queue(dev); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int interface_release(struct net_device *dev) | ||
301 | { | ||
302 | netif_stop_queue(dev); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static struct net_device_stats *interface_stats(struct net_device *dev) | ||
307 | { | ||
308 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
309 | return &bat_priv->stats; | ||
310 | } | ||
311 | |||
312 | static int interface_set_mac_addr(struct net_device *dev, void *p) | ||
313 | { | ||
314 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
315 | struct sockaddr *addr = p; | ||
316 | |||
317 | if (!is_valid_ether_addr(addr->sa_data)) | ||
318 | return -EADDRNOTAVAIL; | ||
319 | |||
320 | /* only modify hna-table if it has been initialised before */ | ||
321 | if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { | ||
322 | hna_local_remove(bat_priv, dev->dev_addr, | ||
323 | "mac address changed"); | ||
324 | hna_local_add(dev, addr->sa_data); | ||
325 | } | ||
326 | |||
327 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int interface_change_mtu(struct net_device *dev, int new_mtu) | ||
332 | { | ||
333 | /* check ranges */ | ||
334 | if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev))) | ||
335 | return -EINVAL; | ||
336 | |||
337 | dev->mtu = new_mtu; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | ||
343 | { | ||
344 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
345 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
346 | struct bcast_packet *bcast_packet; | ||
347 | struct vlan_ethhdr *vhdr; | ||
348 | int data_len = skb->len, ret; | ||
349 | short vid = -1; | ||
350 | bool do_bcast = false; | ||
351 | |||
352 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
353 | goto dropped; | ||
354 | |||
355 | soft_iface->trans_start = jiffies; | ||
356 | |||
357 | switch (ntohs(ethhdr->h_proto)) { | ||
358 | case ETH_P_8021Q: | ||
359 | vhdr = (struct vlan_ethhdr *)skb->data; | ||
360 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
361 | |||
362 | if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) | ||
363 | break; | ||
364 | |||
365 | /* fall through */ | ||
366 | case ETH_P_BATMAN: | ||
367 | softif_batman_recv(skb, soft_iface, vid); | ||
368 | goto end; | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * if we have a another chosen mesh exit node in range | ||
373 | * it will transport the packets to the mesh | ||
374 | */ | ||
375 | if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) | ||
376 | goto dropped; | ||
377 | |||
378 | /* TODO: check this for locks */ | ||
379 | hna_local_add(soft_iface, ethhdr->h_source); | ||
380 | |||
381 | if (is_multicast_ether_addr(ethhdr->h_dest)) { | ||
382 | ret = gw_is_target(bat_priv, skb); | ||
383 | |||
384 | if (ret < 0) | ||
385 | goto dropped; | ||
386 | |||
387 | if (ret == 0) | ||
388 | do_bcast = true; | ||
389 | } | ||
390 | |||
391 | /* ethernet packet should be broadcasted */ | ||
392 | if (do_bcast) { | ||
393 | if (!bat_priv->primary_if) | ||
394 | goto dropped; | ||
395 | |||
396 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) | ||
397 | goto dropped; | ||
398 | |||
399 | bcast_packet = (struct bcast_packet *)skb->data; | ||
400 | bcast_packet->version = COMPAT_VERSION; | ||
401 | bcast_packet->ttl = TTL; | ||
402 | |||
403 | /* batman packet type: broadcast */ | ||
404 | bcast_packet->packet_type = BAT_BCAST; | ||
405 | |||
406 | /* hw address of first interface is the orig mac because only | ||
407 | * this mac is known throughout the mesh */ | ||
408 | memcpy(bcast_packet->orig, | ||
409 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
410 | |||
411 | /* set broadcast sequence number */ | ||
412 | bcast_packet->seqno = | ||
413 | htonl(atomic_inc_return(&bat_priv->bcast_seqno)); | ||
414 | |||
415 | add_bcast_packet_to_list(bat_priv, skb); | ||
416 | |||
417 | /* a copy is stored in the bcast list, therefore removing | ||
418 | * the original skb. */ | ||
419 | kfree_skb(skb); | ||
420 | |||
421 | /* unicast packet */ | ||
422 | } else { | ||
423 | ret = unicast_send_skb(skb, bat_priv); | ||
424 | if (ret != 0) | ||
425 | goto dropped_freed; | ||
426 | } | ||
427 | |||
428 | bat_priv->stats.tx_packets++; | ||
429 | bat_priv->stats.tx_bytes += data_len; | ||
430 | goto end; | ||
431 | |||
432 | dropped: | ||
433 | kfree_skb(skb); | ||
434 | dropped_freed: | ||
435 | bat_priv->stats.tx_dropped++; | ||
436 | end: | ||
437 | return NETDEV_TX_OK; | ||
438 | } | ||
439 | |||
440 | void interface_rx(struct net_device *soft_iface, | ||
441 | struct sk_buff *skb, struct batman_if *recv_if, | ||
442 | int hdr_size) | ||
443 | { | ||
444 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
445 | struct unicast_packet *unicast_packet; | ||
446 | struct ethhdr *ethhdr; | ||
447 | struct vlan_ethhdr *vhdr; | ||
448 | short vid = -1; | ||
449 | int ret; | ||
450 | |||
451 | /* check if enough space is available for pulling, and pull */ | ||
452 | if (!pskb_may_pull(skb, hdr_size)) | ||
453 | goto dropped; | ||
454 | |||
455 | skb_pull_rcsum(skb, hdr_size); | ||
456 | skb_reset_mac_header(skb); | ||
457 | |||
458 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
459 | |||
460 | switch (ntohs(ethhdr->h_proto)) { | ||
461 | case ETH_P_8021Q: | ||
462 | vhdr = (struct vlan_ethhdr *)skb->data; | ||
463 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
464 | |||
465 | if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) | ||
466 | break; | ||
467 | |||
468 | /* fall through */ | ||
469 | case ETH_P_BATMAN: | ||
470 | goto dropped; | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * if we have a another chosen mesh exit node in range | ||
475 | * it will transport the packets to the non-mesh network | ||
476 | */ | ||
477 | if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { | ||
478 | skb_push(skb, hdr_size); | ||
479 | unicast_packet = (struct unicast_packet *)skb->data; | ||
480 | |||
481 | if ((unicast_packet->packet_type != BAT_UNICAST) && | ||
482 | (unicast_packet->packet_type != BAT_UNICAST_FRAG)) | ||
483 | goto dropped; | ||
484 | |||
485 | skb_reset_mac_header(skb); | ||
486 | |||
487 | memcpy(unicast_packet->dest, | ||
488 | bat_priv->softif_neigh->addr, ETH_ALEN); | ||
489 | ret = route_unicast_packet(skb, recv_if, hdr_size); | ||
490 | if (ret == NET_RX_DROP) | ||
491 | goto dropped; | ||
492 | |||
493 | goto out; | ||
494 | } | ||
495 | |||
496 | /* skb->dev & skb->pkt_type are set here */ | ||
497 | if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) | ||
498 | goto dropped; | ||
499 | skb->protocol = eth_type_trans(skb, soft_iface); | ||
500 | |||
501 | /* should not be neccesary anymore as we use skb_pull_rcsum() | ||
502 | * TODO: please verify this and remove this TODO | ||
503 | * -- Dec 21st 2009, Simon Wunderlich */ | ||
504 | |||
505 | /* skb->ip_summed = CHECKSUM_UNNECESSARY;*/ | ||
506 | |||
507 | bat_priv->stats.rx_packets++; | ||
508 | bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr); | ||
509 | |||
510 | soft_iface->last_rx = jiffies; | ||
511 | |||
512 | netif_rx(skb); | ||
513 | return; | ||
514 | |||
515 | dropped: | ||
516 | kfree_skb(skb); | ||
517 | out: | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | #ifdef HAVE_NET_DEVICE_OPS | ||
522 | static const struct net_device_ops bat_netdev_ops = { | ||
523 | .ndo_open = interface_open, | ||
524 | .ndo_stop = interface_release, | ||
525 | .ndo_get_stats = interface_stats, | ||
526 | .ndo_set_mac_address = interface_set_mac_addr, | ||
527 | .ndo_change_mtu = interface_change_mtu, | ||
528 | .ndo_start_xmit = interface_tx, | ||
529 | .ndo_validate_addr = eth_validate_addr | ||
530 | }; | ||
531 | #endif | ||
532 | |||
533 | static void interface_setup(struct net_device *dev) | ||
534 | { | ||
535 | struct bat_priv *priv = netdev_priv(dev); | ||
536 | char dev_addr[ETH_ALEN]; | ||
537 | |||
538 | ether_setup(dev); | ||
539 | |||
540 | #ifdef HAVE_NET_DEVICE_OPS | ||
541 | dev->netdev_ops = &bat_netdev_ops; | ||
542 | #else | ||
543 | dev->open = interface_open; | ||
544 | dev->stop = interface_release; | ||
545 | dev->get_stats = interface_stats; | ||
546 | dev->set_mac_address = interface_set_mac_addr; | ||
547 | dev->change_mtu = interface_change_mtu; | ||
548 | dev->hard_start_xmit = interface_tx; | ||
549 | #endif | ||
550 | dev->destructor = free_netdev; | ||
551 | |||
552 | /** | ||
553 | * can't call min_mtu, because the needed variables | ||
554 | * have not been initialized yet | ||
555 | */ | ||
556 | dev->mtu = ETH_DATA_LEN; | ||
557 | dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the | ||
558 | * skbuff for our header */ | ||
559 | |||
560 | /* generate random address */ | ||
561 | random_ether_addr(dev_addr); | ||
562 | memcpy(dev->dev_addr, dev_addr, ETH_ALEN); | ||
563 | |||
564 | SET_ETHTOOL_OPS(dev, &bat_ethtool_ops); | ||
565 | |||
566 | memset(priv, 0, sizeof(struct bat_priv)); | ||
567 | } | ||
568 | |||
569 | struct net_device *softif_create(char *name) | ||
570 | { | ||
571 | struct net_device *soft_iface; | ||
572 | struct bat_priv *bat_priv; | ||
573 | int ret; | ||
574 | |||
575 | soft_iface = alloc_netdev(sizeof(struct bat_priv) , name, | ||
576 | interface_setup); | ||
577 | |||
578 | if (!soft_iface) { | ||
579 | pr_err("Unable to allocate the batman interface: %s\n", name); | ||
580 | goto out; | ||
581 | } | ||
582 | |||
583 | ret = register_netdev(soft_iface); | ||
584 | if (ret < 0) { | ||
585 | pr_err("Unable to register the batman interface '%s': %i\n", | ||
586 | name, ret); | ||
587 | goto free_soft_iface; | ||
588 | } | ||
589 | |||
590 | bat_priv = netdev_priv(soft_iface); | ||
591 | |||
592 | atomic_set(&bat_priv->aggregated_ogms, 1); | ||
593 | atomic_set(&bat_priv->bonding, 0); | ||
594 | atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); | ||
595 | atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); | ||
596 | atomic_set(&bat_priv->gw_sel_class, 20); | ||
597 | atomic_set(&bat_priv->gw_bandwidth, 41); | ||
598 | atomic_set(&bat_priv->orig_interval, 1000); | ||
599 | atomic_set(&bat_priv->hop_penalty, 10); | ||
600 | atomic_set(&bat_priv->log_level, 0); | ||
601 | atomic_set(&bat_priv->fragmentation, 1); | ||
602 | atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN); | ||
603 | atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN); | ||
604 | |||
605 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); | ||
606 | atomic_set(&bat_priv->bcast_seqno, 1); | ||
607 | atomic_set(&bat_priv->hna_local_changed, 0); | ||
608 | |||
609 | bat_priv->primary_if = NULL; | ||
610 | bat_priv->num_ifaces = 0; | ||
611 | bat_priv->softif_neigh = NULL; | ||
612 | |||
613 | ret = sysfs_add_meshif(soft_iface); | ||
614 | if (ret < 0) | ||
615 | goto unreg_soft_iface; | ||
616 | |||
617 | ret = debugfs_add_meshif(soft_iface); | ||
618 | if (ret < 0) | ||
619 | goto unreg_sysfs; | ||
620 | |||
621 | ret = mesh_init(soft_iface); | ||
622 | if (ret < 0) | ||
623 | goto unreg_debugfs; | ||
624 | |||
625 | return soft_iface; | ||
626 | |||
627 | unreg_debugfs: | ||
628 | debugfs_del_meshif(soft_iface); | ||
629 | unreg_sysfs: | ||
630 | sysfs_del_meshif(soft_iface); | ||
631 | unreg_soft_iface: | ||
632 | unregister_netdev(soft_iface); | ||
633 | return NULL; | ||
634 | |||
635 | free_soft_iface: | ||
636 | free_netdev(soft_iface); | ||
637 | out: | ||
638 | return NULL; | ||
639 | } | ||
640 | |||
641 | void softif_destroy(struct net_device *soft_iface) | ||
642 | { | ||
643 | debugfs_del_meshif(soft_iface); | ||
644 | sysfs_del_meshif(soft_iface); | ||
645 | mesh_free(soft_iface); | ||
646 | unregister_netdevice(soft_iface); | ||
647 | } | ||
648 | |||
649 | /* ethtool */ | ||
650 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
651 | { | ||
652 | cmd->supported = 0; | ||
653 | cmd->advertising = 0; | ||
654 | cmd->speed = SPEED_10; | ||
655 | cmd->duplex = DUPLEX_FULL; | ||
656 | cmd->port = PORT_TP; | ||
657 | cmd->phy_address = 0; | ||
658 | cmd->transceiver = XCVR_INTERNAL; | ||
659 | cmd->autoneg = AUTONEG_DISABLE; | ||
660 | cmd->maxtxpkt = 0; | ||
661 | cmd->maxrxpkt = 0; | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static void bat_get_drvinfo(struct net_device *dev, | ||
667 | struct ethtool_drvinfo *info) | ||
668 | { | ||
669 | strcpy(info->driver, "B.A.T.M.A.N. advanced"); | ||
670 | strcpy(info->version, SOURCE_VERSION); | ||
671 | strcpy(info->fw_version, "N/A"); | ||
672 | strcpy(info->bus_info, "batman"); | ||
673 | } | ||
674 | |||
675 | static u32 bat_get_msglevel(struct net_device *dev) | ||
676 | { | ||
677 | return -EOPNOTSUPP; | ||
678 | } | ||
679 | |||
680 | static void bat_set_msglevel(struct net_device *dev, u32 value) | ||
681 | { | ||
682 | } | ||
683 | |||
684 | static u32 bat_get_link(struct net_device *dev) | ||
685 | { | ||
686 | return 1; | ||
687 | } | ||
688 | |||
689 | static u32 bat_get_rx_csum(struct net_device *dev) | ||
690 | { | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int bat_set_rx_csum(struct net_device *dev, u32 data) | ||
695 | { | ||
696 | return -EOPNOTSUPP; | ||
697 | } | ||
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h new file mode 100644 index 000000000000..02b77334d10d --- /dev/null +++ b/net/batman-adv/soft-interface.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_ | ||
23 | #define _NET_BATMAN_ADV_SOFT_INTERFACE_H_ | ||
24 | |||
25 | int my_skb_head_push(struct sk_buff *skb, unsigned int len); | ||
26 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset); | ||
27 | void softif_neigh_purge(struct bat_priv *bat_priv); | ||
28 | int interface_tx(struct sk_buff *skb, struct net_device *soft_iface); | ||
29 | void interface_rx(struct net_device *soft_iface, | ||
30 | struct sk_buff *skb, struct batman_if *recv_if, | ||
31 | int hdr_size); | ||
32 | struct net_device *softif_create(char *name); | ||
33 | void softif_destroy(struct net_device *soft_iface); | ||
34 | |||
35 | #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ | ||
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c new file mode 100644 index 000000000000..a633b5a435e2 --- /dev/null +++ b/net/batman-adv/translation-table.c | |||
@@ -0,0 +1,534 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "translation-table.h" | ||
24 | #include "soft-interface.h" | ||
25 | #include "types.h" | ||
26 | #include "hash.h" | ||
27 | #include "originator.h" | ||
28 | |||
29 | static void hna_local_purge(struct work_struct *work); | ||
30 | static void _hna_global_del_orig(struct bat_priv *bat_priv, | ||
31 | struct hna_global_entry *hna_global_entry, | ||
32 | char *message); | ||
33 | |||
34 | static void hna_local_start_timer(struct bat_priv *bat_priv) | ||
35 | { | ||
36 | INIT_DELAYED_WORK(&bat_priv->hna_work, hna_local_purge); | ||
37 | queue_delayed_work(bat_event_workqueue, &bat_priv->hna_work, 10 * HZ); | ||
38 | } | ||
39 | |||
40 | int hna_local_init(struct bat_priv *bat_priv) | ||
41 | { | ||
42 | if (bat_priv->hna_local_hash) | ||
43 | return 1; | ||
44 | |||
45 | bat_priv->hna_local_hash = hash_new(1024); | ||
46 | |||
47 | if (!bat_priv->hna_local_hash) | ||
48 | return 0; | ||
49 | |||
50 | atomic_set(&bat_priv->hna_local_changed, 0); | ||
51 | hna_local_start_timer(bat_priv); | ||
52 | |||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | void hna_local_add(struct net_device *soft_iface, uint8_t *addr) | ||
57 | { | ||
58 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | ||
59 | struct hna_local_entry *hna_local_entry; | ||
60 | struct hna_global_entry *hna_global_entry; | ||
61 | int required_bytes; | ||
62 | |||
63 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
64 | hna_local_entry = | ||
65 | ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, | ||
66 | compare_orig, choose_orig, | ||
67 | addr)); | ||
68 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
69 | |||
70 | if (hna_local_entry) { | ||
71 | hna_local_entry->last_seen = jiffies; | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | /* only announce as many hosts as possible in the batman-packet and | ||
76 | space in batman_packet->num_hna That also should give a limit to | ||
77 | MAC-flooding. */ | ||
78 | required_bytes = (bat_priv->num_local_hna + 1) * ETH_ALEN; | ||
79 | required_bytes += BAT_PACKET_LEN; | ||
80 | |||
81 | if ((required_bytes > ETH_DATA_LEN) || | ||
82 | (atomic_read(&bat_priv->aggregated_ogms) && | ||
83 | required_bytes > MAX_AGGREGATION_BYTES) || | ||
84 | (bat_priv->num_local_hna + 1 > 255)) { | ||
85 | bat_dbg(DBG_ROUTES, bat_priv, | ||
86 | "Can't add new local hna entry (%pM): " | ||
87 | "number of local hna entries exceeds packet size\n", | ||
88 | addr); | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | bat_dbg(DBG_ROUTES, bat_priv, | ||
93 | "Creating new local hna entry: %pM\n", addr); | ||
94 | |||
95 | hna_local_entry = kmalloc(sizeof(struct hna_local_entry), GFP_ATOMIC); | ||
96 | if (!hna_local_entry) | ||
97 | return; | ||
98 | |||
99 | memcpy(hna_local_entry->addr, addr, ETH_ALEN); | ||
100 | hna_local_entry->last_seen = jiffies; | ||
101 | |||
102 | /* the batman interface mac address should never be purged */ | ||
103 | if (compare_orig(addr, soft_iface->dev_addr)) | ||
104 | hna_local_entry->never_purge = 1; | ||
105 | else | ||
106 | hna_local_entry->never_purge = 0; | ||
107 | |||
108 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
109 | |||
110 | hash_add(bat_priv->hna_local_hash, compare_orig, choose_orig, | ||
111 | hna_local_entry); | ||
112 | bat_priv->num_local_hna++; | ||
113 | atomic_set(&bat_priv->hna_local_changed, 1); | ||
114 | |||
115 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
116 | |||
117 | /* remove address from global hash if present */ | ||
118 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
119 | |||
120 | hna_global_entry = ((struct hna_global_entry *) | ||
121 | hash_find(bat_priv->hna_global_hash, | ||
122 | compare_orig, choose_orig, addr)); | ||
123 | |||
124 | if (hna_global_entry) | ||
125 | _hna_global_del_orig(bat_priv, hna_global_entry, | ||
126 | "local hna received"); | ||
127 | |||
128 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
129 | } | ||
130 | |||
131 | int hna_local_fill_buffer(struct bat_priv *bat_priv, | ||
132 | unsigned char *buff, int buff_len) | ||
133 | { | ||
134 | struct hashtable_t *hash = bat_priv->hna_local_hash; | ||
135 | struct hna_local_entry *hna_local_entry; | ||
136 | struct element_t *bucket; | ||
137 | int i; | ||
138 | struct hlist_node *walk; | ||
139 | struct hlist_head *head; | ||
140 | int count = 0; | ||
141 | |||
142 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
143 | |||
144 | for (i = 0; i < hash->size; i++) { | ||
145 | head = &hash->table[i]; | ||
146 | |||
147 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
148 | |||
149 | if (buff_len < (count + 1) * ETH_ALEN) | ||
150 | break; | ||
151 | |||
152 | hna_local_entry = bucket->data; | ||
153 | memcpy(buff + (count * ETH_ALEN), hna_local_entry->addr, | ||
154 | ETH_ALEN); | ||
155 | |||
156 | count++; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /* if we did not get all new local hnas see you next time ;-) */ | ||
161 | if (count == bat_priv->num_local_hna) | ||
162 | atomic_set(&bat_priv->hna_local_changed, 0); | ||
163 | |||
164 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
165 | return count; | ||
166 | } | ||
167 | |||
168 | int hna_local_seq_print_text(struct seq_file *seq, void *offset) | ||
169 | { | ||
170 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
171 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
172 | struct hashtable_t *hash = bat_priv->hna_local_hash; | ||
173 | struct hna_local_entry *hna_local_entry; | ||
174 | int i; | ||
175 | struct hlist_node *walk; | ||
176 | struct hlist_head *head; | ||
177 | struct element_t *bucket; | ||
178 | size_t buf_size, pos; | ||
179 | char *buff; | ||
180 | |||
181 | if (!bat_priv->primary_if) { | ||
182 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
183 | "please specify interfaces to enable it\n", | ||
184 | net_dev->name); | ||
185 | } | ||
186 | |||
187 | seq_printf(seq, "Locally retrieved addresses (from %s) " | ||
188 | "announced via HNA:\n", | ||
189 | net_dev->name); | ||
190 | |||
191 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
192 | |||
193 | buf_size = 1; | ||
194 | /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ | ||
195 | for (i = 0; i < hash->size; i++) { | ||
196 | head = &hash->table[i]; | ||
197 | |||
198 | hlist_for_each(walk, head) | ||
199 | buf_size += 21; | ||
200 | } | ||
201 | |||
202 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
203 | if (!buff) { | ||
204 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | buff[0] = '\0'; | ||
208 | pos = 0; | ||
209 | |||
210 | for (i = 0; i < hash->size; i++) { | ||
211 | head = &hash->table[i]; | ||
212 | |||
213 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
214 | hna_local_entry = bucket->data; | ||
215 | |||
216 | pos += snprintf(buff + pos, 22, " * %pM\n", | ||
217 | hna_local_entry->addr); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
222 | |||
223 | seq_printf(seq, "%s", buff); | ||
224 | kfree(buff); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static void _hna_local_del(void *data, void *arg) | ||
229 | { | ||
230 | struct bat_priv *bat_priv = (struct bat_priv *)arg; | ||
231 | |||
232 | kfree(data); | ||
233 | bat_priv->num_local_hna--; | ||
234 | atomic_set(&bat_priv->hna_local_changed, 1); | ||
235 | } | ||
236 | |||
237 | static void hna_local_del(struct bat_priv *bat_priv, | ||
238 | struct hna_local_entry *hna_local_entry, | ||
239 | char *message) | ||
240 | { | ||
241 | bat_dbg(DBG_ROUTES, bat_priv, "Deleting local hna entry (%pM): %s\n", | ||
242 | hna_local_entry->addr, message); | ||
243 | |||
244 | hash_remove(bat_priv->hna_local_hash, compare_orig, choose_orig, | ||
245 | hna_local_entry->addr); | ||
246 | _hna_local_del(hna_local_entry, bat_priv); | ||
247 | } | ||
248 | |||
249 | void hna_local_remove(struct bat_priv *bat_priv, | ||
250 | uint8_t *addr, char *message) | ||
251 | { | ||
252 | struct hna_local_entry *hna_local_entry; | ||
253 | |||
254 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
255 | |||
256 | hna_local_entry = (struct hna_local_entry *) | ||
257 | hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, | ||
258 | addr); | ||
259 | |||
260 | if (hna_local_entry) | ||
261 | hna_local_del(bat_priv, hna_local_entry, message); | ||
262 | |||
263 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
264 | } | ||
265 | |||
266 | static void hna_local_purge(struct work_struct *work) | ||
267 | { | ||
268 | struct delayed_work *delayed_work = | ||
269 | container_of(work, struct delayed_work, work); | ||
270 | struct bat_priv *bat_priv = | ||
271 | container_of(delayed_work, struct bat_priv, hna_work); | ||
272 | struct hashtable_t *hash = bat_priv->hna_local_hash; | ||
273 | struct hna_local_entry *hna_local_entry; | ||
274 | int i; | ||
275 | struct hlist_node *walk, *safe; | ||
276 | struct hlist_head *head; | ||
277 | struct element_t *bucket; | ||
278 | unsigned long timeout; | ||
279 | |||
280 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
281 | |||
282 | for (i = 0; i < hash->size; i++) { | ||
283 | head = &hash->table[i]; | ||
284 | |||
285 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | ||
286 | hna_local_entry = bucket->data; | ||
287 | |||
288 | timeout = hna_local_entry->last_seen; | ||
289 | timeout += LOCAL_HNA_TIMEOUT * HZ; | ||
290 | |||
291 | if ((!hna_local_entry->never_purge) && | ||
292 | time_after(jiffies, timeout)) | ||
293 | hna_local_del(bat_priv, hna_local_entry, | ||
294 | "address timed out"); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
299 | hna_local_start_timer(bat_priv); | ||
300 | } | ||
301 | |||
302 | void hna_local_free(struct bat_priv *bat_priv) | ||
303 | { | ||
304 | if (!bat_priv->hna_local_hash) | ||
305 | return; | ||
306 | |||
307 | cancel_delayed_work_sync(&bat_priv->hna_work); | ||
308 | hash_delete(bat_priv->hna_local_hash, _hna_local_del, bat_priv); | ||
309 | bat_priv->hna_local_hash = NULL; | ||
310 | } | ||
311 | |||
312 | int hna_global_init(struct bat_priv *bat_priv) | ||
313 | { | ||
314 | if (bat_priv->hna_global_hash) | ||
315 | return 1; | ||
316 | |||
317 | bat_priv->hna_global_hash = hash_new(1024); | ||
318 | |||
319 | if (!bat_priv->hna_global_hash) | ||
320 | return 0; | ||
321 | |||
322 | return 1; | ||
323 | } | ||
324 | |||
325 | void hna_global_add_orig(struct bat_priv *bat_priv, | ||
326 | struct orig_node *orig_node, | ||
327 | unsigned char *hna_buff, int hna_buff_len) | ||
328 | { | ||
329 | struct hna_global_entry *hna_global_entry; | ||
330 | struct hna_local_entry *hna_local_entry; | ||
331 | int hna_buff_count = 0; | ||
332 | unsigned char *hna_ptr; | ||
333 | |||
334 | while ((hna_buff_count + 1) * ETH_ALEN <= hna_buff_len) { | ||
335 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
336 | |||
337 | hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); | ||
338 | hna_global_entry = (struct hna_global_entry *) | ||
339 | hash_find(bat_priv->hna_global_hash, compare_orig, | ||
340 | choose_orig, hna_ptr); | ||
341 | |||
342 | if (!hna_global_entry) { | ||
343 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
344 | |||
345 | hna_global_entry = | ||
346 | kmalloc(sizeof(struct hna_global_entry), | ||
347 | GFP_ATOMIC); | ||
348 | |||
349 | if (!hna_global_entry) | ||
350 | break; | ||
351 | |||
352 | memcpy(hna_global_entry->addr, hna_ptr, ETH_ALEN); | ||
353 | |||
354 | bat_dbg(DBG_ROUTES, bat_priv, | ||
355 | "Creating new global hna entry: " | ||
356 | "%pM (via %pM)\n", | ||
357 | hna_global_entry->addr, orig_node->orig); | ||
358 | |||
359 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
360 | hash_add(bat_priv->hna_global_hash, compare_orig, | ||
361 | choose_orig, hna_global_entry); | ||
362 | |||
363 | } | ||
364 | |||
365 | hna_global_entry->orig_node = orig_node; | ||
366 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
367 | |||
368 | /* remove address from local hash if present */ | ||
369 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
370 | |||
371 | hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); | ||
372 | hna_local_entry = (struct hna_local_entry *) | ||
373 | hash_find(bat_priv->hna_local_hash, compare_orig, | ||
374 | choose_orig, hna_ptr); | ||
375 | |||
376 | if (hna_local_entry) | ||
377 | hna_local_del(bat_priv, hna_local_entry, | ||
378 | "global hna received"); | ||
379 | |||
380 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
381 | |||
382 | hna_buff_count++; | ||
383 | } | ||
384 | |||
385 | /* initialize, and overwrite if malloc succeeds */ | ||
386 | orig_node->hna_buff = NULL; | ||
387 | orig_node->hna_buff_len = 0; | ||
388 | |||
389 | if (hna_buff_len > 0) { | ||
390 | orig_node->hna_buff = kmalloc(hna_buff_len, GFP_ATOMIC); | ||
391 | if (orig_node->hna_buff) { | ||
392 | memcpy(orig_node->hna_buff, hna_buff, hna_buff_len); | ||
393 | orig_node->hna_buff_len = hna_buff_len; | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | |||
398 | int hna_global_seq_print_text(struct seq_file *seq, void *offset) | ||
399 | { | ||
400 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
401 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
402 | struct hashtable_t *hash = bat_priv->hna_global_hash; | ||
403 | struct hna_global_entry *hna_global_entry; | ||
404 | int i; | ||
405 | struct hlist_node *walk; | ||
406 | struct hlist_head *head; | ||
407 | struct element_t *bucket; | ||
408 | size_t buf_size, pos; | ||
409 | char *buff; | ||
410 | |||
411 | if (!bat_priv->primary_if) { | ||
412 | return seq_printf(seq, "BATMAN mesh %s disabled - " | ||
413 | "please specify interfaces to enable it\n", | ||
414 | net_dev->name); | ||
415 | } | ||
416 | |||
417 | seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", | ||
418 | net_dev->name); | ||
419 | |||
420 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
421 | |||
422 | buf_size = 1; | ||
423 | /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ | ||
424 | for (i = 0; i < hash->size; i++) { | ||
425 | head = &hash->table[i]; | ||
426 | |||
427 | hlist_for_each(walk, head) | ||
428 | buf_size += 43; | ||
429 | } | ||
430 | |||
431 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
432 | if (!buff) { | ||
433 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
434 | return -ENOMEM; | ||
435 | } | ||
436 | buff[0] = '\0'; | ||
437 | pos = 0; | ||
438 | |||
439 | for (i = 0; i < hash->size; i++) { | ||
440 | head = &hash->table[i]; | ||
441 | |||
442 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
443 | hna_global_entry = bucket->data; | ||
444 | |||
445 | pos += snprintf(buff + pos, 44, | ||
446 | " * %pM via %pM\n", | ||
447 | hna_global_entry->addr, | ||
448 | hna_global_entry->orig_node->orig); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
453 | |||
454 | seq_printf(seq, "%s", buff); | ||
455 | kfree(buff); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void _hna_global_del_orig(struct bat_priv *bat_priv, | ||
460 | struct hna_global_entry *hna_global_entry, | ||
461 | char *message) | ||
462 | { | ||
463 | bat_dbg(DBG_ROUTES, bat_priv, | ||
464 | "Deleting global hna entry %pM (via %pM): %s\n", | ||
465 | hna_global_entry->addr, hna_global_entry->orig_node->orig, | ||
466 | message); | ||
467 | |||
468 | hash_remove(bat_priv->hna_global_hash, compare_orig, choose_orig, | ||
469 | hna_global_entry->addr); | ||
470 | kfree(hna_global_entry); | ||
471 | } | ||
472 | |||
473 | void hna_global_del_orig(struct bat_priv *bat_priv, | ||
474 | struct orig_node *orig_node, char *message) | ||
475 | { | ||
476 | struct hna_global_entry *hna_global_entry; | ||
477 | int hna_buff_count = 0; | ||
478 | unsigned char *hna_ptr; | ||
479 | |||
480 | if (orig_node->hna_buff_len == 0) | ||
481 | return; | ||
482 | |||
483 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
484 | |||
485 | while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { | ||
486 | hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); | ||
487 | hna_global_entry = (struct hna_global_entry *) | ||
488 | hash_find(bat_priv->hna_global_hash, compare_orig, | ||
489 | choose_orig, hna_ptr); | ||
490 | |||
491 | if ((hna_global_entry) && | ||
492 | (hna_global_entry->orig_node == orig_node)) | ||
493 | _hna_global_del_orig(bat_priv, hna_global_entry, | ||
494 | message); | ||
495 | |||
496 | hna_buff_count++; | ||
497 | } | ||
498 | |||
499 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
500 | |||
501 | orig_node->hna_buff_len = 0; | ||
502 | kfree(orig_node->hna_buff); | ||
503 | orig_node->hna_buff = NULL; | ||
504 | } | ||
505 | |||
506 | static void hna_global_del(void *data, void *arg) | ||
507 | { | ||
508 | kfree(data); | ||
509 | } | ||
510 | |||
511 | void hna_global_free(struct bat_priv *bat_priv) | ||
512 | { | ||
513 | if (!bat_priv->hna_global_hash) | ||
514 | return; | ||
515 | |||
516 | hash_delete(bat_priv->hna_global_hash, hna_global_del, NULL); | ||
517 | bat_priv->hna_global_hash = NULL; | ||
518 | } | ||
519 | |||
520 | struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr) | ||
521 | { | ||
522 | struct hna_global_entry *hna_global_entry; | ||
523 | |||
524 | spin_lock_bh(&bat_priv->hna_ghash_lock); | ||
525 | hna_global_entry = (struct hna_global_entry *) | ||
526 | hash_find(bat_priv->hna_global_hash, | ||
527 | compare_orig, choose_orig, addr); | ||
528 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | ||
529 | |||
530 | if (!hna_global_entry) | ||
531 | return NULL; | ||
532 | |||
533 | return hna_global_entry->orig_node; | ||
534 | } | ||
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h new file mode 100644 index 000000000000..10c4c5c319b6 --- /dev/null +++ b/net/batman-adv/translation-table.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | ||
23 | #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | ||
24 | |||
25 | #include "types.h" | ||
26 | |||
27 | int hna_local_init(struct bat_priv *bat_priv); | ||
28 | void hna_local_add(struct net_device *soft_iface, uint8_t *addr); | ||
29 | void hna_local_remove(struct bat_priv *bat_priv, | ||
30 | uint8_t *addr, char *message); | ||
31 | int hna_local_fill_buffer(struct bat_priv *bat_priv, | ||
32 | unsigned char *buff, int buff_len); | ||
33 | int hna_local_seq_print_text(struct seq_file *seq, void *offset); | ||
34 | void hna_local_free(struct bat_priv *bat_priv); | ||
35 | int hna_global_init(struct bat_priv *bat_priv); | ||
36 | void hna_global_add_orig(struct bat_priv *bat_priv, | ||
37 | struct orig_node *orig_node, | ||
38 | unsigned char *hna_buff, int hna_buff_len); | ||
39 | int hna_global_seq_print_text(struct seq_file *seq, void *offset); | ||
40 | void hna_global_del_orig(struct bat_priv *bat_priv, | ||
41 | struct orig_node *orig_node, char *message); | ||
42 | void hna_global_free(struct bat_priv *bat_priv); | ||
43 | struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr); | ||
44 | |||
45 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ | ||
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h new file mode 100644 index 000000000000..97cb23dd3e69 --- /dev/null +++ b/net/batman-adv/types.h | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner, Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | |||
23 | |||
24 | #ifndef _NET_BATMAN_ADV_TYPES_H_ | ||
25 | #define _NET_BATMAN_ADV_TYPES_H_ | ||
26 | |||
27 | #include "packet.h" | ||
28 | #include "bitarray.h" | ||
29 | |||
30 | #define BAT_HEADER_LEN (sizeof(struct ethhdr) + \ | ||
31 | ((sizeof(struct unicast_packet) > sizeof(struct bcast_packet) ? \ | ||
32 | sizeof(struct unicast_packet) : \ | ||
33 | sizeof(struct bcast_packet)))) | ||
34 | |||
35 | |||
36 | struct batman_if { | ||
37 | struct list_head list; | ||
38 | int16_t if_num; | ||
39 | char if_status; | ||
40 | struct net_device *net_dev; | ||
41 | atomic_t seqno; | ||
42 | atomic_t frag_seqno; | ||
43 | unsigned char *packet_buff; | ||
44 | int packet_len; | ||
45 | struct kobject *hardif_obj; | ||
46 | struct kref refcount; | ||
47 | struct packet_type batman_adv_ptype; | ||
48 | struct net_device *soft_iface; | ||
49 | struct rcu_head rcu; | ||
50 | }; | ||
51 | |||
52 | /** | ||
53 | * orig_node - structure for orig_list maintaining nodes of mesh | ||
54 | * @primary_addr: hosts primary interface address | ||
55 | * @last_valid: when last packet from this node was received | ||
56 | * @bcast_seqno_reset: time when the broadcast seqno window was reset | ||
57 | * @batman_seqno_reset: time when the batman seqno window was reset | ||
58 | * @gw_flags: flags related to gateway class | ||
59 | * @flags: for now only VIS_SERVER flag | ||
60 | * @last_real_seqno: last and best known squence number | ||
61 | * @last_ttl: ttl of last received packet | ||
62 | * @last_bcast_seqno: last broadcast sequence number received by this host | ||
63 | * | ||
64 | * @candidates: how many candidates are available | ||
65 | * @selected: next bonding candidate | ||
66 | */ | ||
67 | struct orig_node { | ||
68 | uint8_t orig[ETH_ALEN]; | ||
69 | uint8_t primary_addr[ETH_ALEN]; | ||
70 | struct neigh_node *router; | ||
71 | unsigned long *bcast_own; | ||
72 | uint8_t *bcast_own_sum; | ||
73 | uint8_t tq_own; | ||
74 | int tq_asym_penalty; | ||
75 | unsigned long last_valid; | ||
76 | unsigned long bcast_seqno_reset; | ||
77 | unsigned long batman_seqno_reset; | ||
78 | uint8_t gw_flags; | ||
79 | uint8_t flags; | ||
80 | unsigned char *hna_buff; | ||
81 | int16_t hna_buff_len; | ||
82 | uint32_t last_real_seqno; | ||
83 | uint8_t last_ttl; | ||
84 | unsigned long bcast_bits[NUM_WORDS]; | ||
85 | uint32_t last_bcast_seqno; | ||
86 | struct list_head neigh_list; | ||
87 | struct list_head frag_list; | ||
88 | unsigned long last_frag_packet; | ||
89 | struct { | ||
90 | uint8_t candidates; | ||
91 | struct neigh_node *selected; | ||
92 | } bond; | ||
93 | }; | ||
94 | |||
95 | struct gw_node { | ||
96 | struct hlist_node list; | ||
97 | struct orig_node *orig_node; | ||
98 | unsigned long deleted; | ||
99 | struct kref refcount; | ||
100 | struct rcu_head rcu; | ||
101 | }; | ||
102 | |||
103 | /** | ||
104 | * neigh_node | ||
105 | * @last_valid: when last packet via this neighbor was received | ||
106 | */ | ||
107 | struct neigh_node { | ||
108 | struct list_head list; | ||
109 | uint8_t addr[ETH_ALEN]; | ||
110 | uint8_t real_packet_count; | ||
111 | uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE]; | ||
112 | uint8_t tq_index; | ||
113 | uint8_t tq_avg; | ||
114 | uint8_t last_ttl; | ||
115 | struct neigh_node *next_bond_candidate; | ||
116 | unsigned long last_valid; | ||
117 | unsigned long real_bits[NUM_WORDS]; | ||
118 | struct orig_node *orig_node; | ||
119 | struct batman_if *if_incoming; | ||
120 | }; | ||
121 | |||
122 | |||
123 | struct bat_priv { | ||
124 | atomic_t mesh_state; | ||
125 | struct net_device_stats stats; | ||
126 | atomic_t aggregated_ogms; /* boolean */ | ||
127 | atomic_t bonding; /* boolean */ | ||
128 | atomic_t fragmentation; /* boolean */ | ||
129 | atomic_t vis_mode; /* VIS_TYPE_* */ | ||
130 | atomic_t gw_mode; /* GW_MODE_* */ | ||
131 | atomic_t gw_sel_class; /* uint */ | ||
132 | atomic_t gw_bandwidth; /* gw bandwidth */ | ||
133 | atomic_t orig_interval; /* uint */ | ||
134 | atomic_t hop_penalty; /* uint */ | ||
135 | atomic_t log_level; /* uint */ | ||
136 | atomic_t bcast_seqno; | ||
137 | atomic_t bcast_queue_left; | ||
138 | atomic_t batman_queue_left; | ||
139 | char num_ifaces; | ||
140 | struct hlist_head softif_neigh_list; | ||
141 | struct softif_neigh *softif_neigh; | ||
142 | struct debug_log *debug_log; | ||
143 | struct batman_if *primary_if; | ||
144 | struct kobject *mesh_obj; | ||
145 | struct dentry *debug_dir; | ||
146 | struct hlist_head forw_bat_list; | ||
147 | struct hlist_head forw_bcast_list; | ||
148 | struct hlist_head gw_list; | ||
149 | struct list_head vis_send_list; | ||
150 | struct hashtable_t *orig_hash; | ||
151 | struct hashtable_t *hna_local_hash; | ||
152 | struct hashtable_t *hna_global_hash; | ||
153 | struct hashtable_t *vis_hash; | ||
154 | spinlock_t orig_hash_lock; /* protects orig_hash */ | ||
155 | spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ | ||
156 | spinlock_t forw_bcast_list_lock; /* protects */ | ||
157 | spinlock_t hna_lhash_lock; /* protects hna_local_hash */ | ||
158 | spinlock_t hna_ghash_lock; /* protects hna_global_hash */ | ||
159 | spinlock_t gw_list_lock; /* protects gw_list */ | ||
160 | spinlock_t vis_hash_lock; /* protects vis_hash */ | ||
161 | spinlock_t vis_list_lock; /* protects vis_info::recv_list */ | ||
162 | spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ | ||
163 | int16_t num_local_hna; | ||
164 | atomic_t hna_local_changed; | ||
165 | struct delayed_work hna_work; | ||
166 | struct delayed_work orig_work; | ||
167 | struct delayed_work vis_work; | ||
168 | struct gw_node *curr_gw; | ||
169 | struct vis_info *my_vis_info; | ||
170 | }; | ||
171 | |||
172 | struct socket_client { | ||
173 | struct list_head queue_list; | ||
174 | unsigned int queue_len; | ||
175 | unsigned char index; | ||
176 | spinlock_t lock; /* protects queue_list, queue_len, index */ | ||
177 | wait_queue_head_t queue_wait; | ||
178 | struct bat_priv *bat_priv; | ||
179 | }; | ||
180 | |||
181 | struct socket_packet { | ||
182 | struct list_head list; | ||
183 | size_t icmp_len; | ||
184 | struct icmp_packet_rr icmp_packet; | ||
185 | }; | ||
186 | |||
187 | struct hna_local_entry { | ||
188 | uint8_t addr[ETH_ALEN]; | ||
189 | unsigned long last_seen; | ||
190 | char never_purge; | ||
191 | }; | ||
192 | |||
193 | struct hna_global_entry { | ||
194 | uint8_t addr[ETH_ALEN]; | ||
195 | struct orig_node *orig_node; | ||
196 | }; | ||
197 | |||
198 | /** | ||
199 | * forw_packet - structure for forw_list maintaining packets to be | ||
200 | * send/forwarded | ||
201 | */ | ||
202 | struct forw_packet { | ||
203 | struct hlist_node list; | ||
204 | unsigned long send_time; | ||
205 | uint8_t own; | ||
206 | struct sk_buff *skb; | ||
207 | uint16_t packet_len; | ||
208 | uint32_t direct_link_flags; | ||
209 | uint8_t num_packets; | ||
210 | struct delayed_work delayed_work; | ||
211 | struct batman_if *if_incoming; | ||
212 | }; | ||
213 | |||
214 | /* While scanning for vis-entries of a particular vis-originator | ||
215 | * this list collects its interfaces to create a subgraph/cluster | ||
216 | * out of them later | ||
217 | */ | ||
218 | struct if_list_entry { | ||
219 | uint8_t addr[ETH_ALEN]; | ||
220 | bool primary; | ||
221 | struct hlist_node list; | ||
222 | }; | ||
223 | |||
224 | struct debug_log { | ||
225 | char log_buff[LOG_BUF_LEN]; | ||
226 | unsigned long log_start; | ||
227 | unsigned long log_end; | ||
228 | spinlock_t lock; /* protects log_buff, log_start and log_end */ | ||
229 | wait_queue_head_t queue_wait; | ||
230 | }; | ||
231 | |||
232 | struct frag_packet_list_entry { | ||
233 | struct list_head list; | ||
234 | uint16_t seqno; | ||
235 | struct sk_buff *skb; | ||
236 | }; | ||
237 | |||
238 | struct vis_info { | ||
239 | unsigned long first_seen; | ||
240 | struct list_head recv_list; | ||
241 | /* list of server-neighbors we received a vis-packet | ||
242 | * from. we should not reply to them. */ | ||
243 | struct list_head send_list; | ||
244 | struct kref refcount; | ||
245 | struct bat_priv *bat_priv; | ||
246 | /* this packet might be part of the vis send queue. */ | ||
247 | struct sk_buff *skb_packet; | ||
248 | /* vis_info may follow here*/ | ||
249 | } __attribute__((packed)); | ||
250 | |||
251 | struct vis_info_entry { | ||
252 | uint8_t src[ETH_ALEN]; | ||
253 | uint8_t dest[ETH_ALEN]; | ||
254 | uint8_t quality; /* quality = 0 means HNA */ | ||
255 | } __attribute__((packed)); | ||
256 | |||
257 | struct recvlist_node { | ||
258 | struct list_head list; | ||
259 | uint8_t mac[ETH_ALEN]; | ||
260 | }; | ||
261 | |||
262 | struct softif_neigh { | ||
263 | struct hlist_node list; | ||
264 | uint8_t addr[ETH_ALEN]; | ||
265 | unsigned long last_seen; | ||
266 | short vid; | ||
267 | struct kref refcount; | ||
268 | struct rcu_head rcu; | ||
269 | }; | ||
270 | |||
271 | #endif /* _NET_BATMAN_ADV_TYPES_H_ */ | ||
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c new file mode 100644 index 000000000000..dc2e28bed844 --- /dev/null +++ b/net/batman-adv/unicast.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Andreas Langer | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "unicast.h" | ||
24 | #include "send.h" | ||
25 | #include "soft-interface.h" | ||
26 | #include "gateway_client.h" | ||
27 | #include "originator.h" | ||
28 | #include "hash.h" | ||
29 | #include "translation-table.h" | ||
30 | #include "routing.h" | ||
31 | #include "hard-interface.h" | ||
32 | |||
33 | |||
34 | static struct sk_buff *frag_merge_packet(struct list_head *head, | ||
35 | struct frag_packet_list_entry *tfp, | ||
36 | struct sk_buff *skb) | ||
37 | { | ||
38 | struct unicast_frag_packet *up = | ||
39 | (struct unicast_frag_packet *)skb->data; | ||
40 | struct sk_buff *tmp_skb; | ||
41 | struct unicast_packet *unicast_packet; | ||
42 | int hdr_len = sizeof(struct unicast_packet), | ||
43 | uni_diff = sizeof(struct unicast_frag_packet) - hdr_len; | ||
44 | |||
45 | /* set skb to the first part and tmp_skb to the second part */ | ||
46 | if (up->flags & UNI_FRAG_HEAD) { | ||
47 | tmp_skb = tfp->skb; | ||
48 | } else { | ||
49 | tmp_skb = skb; | ||
50 | skb = tfp->skb; | ||
51 | } | ||
52 | |||
53 | skb_pull(tmp_skb, sizeof(struct unicast_frag_packet)); | ||
54 | if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) { | ||
55 | /* free buffered skb, skb will be freed later */ | ||
56 | kfree_skb(tfp->skb); | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | /* move free entry to end */ | ||
61 | tfp->skb = NULL; | ||
62 | tfp->seqno = 0; | ||
63 | list_move_tail(&tfp->list, head); | ||
64 | |||
65 | memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len); | ||
66 | kfree_skb(tmp_skb); | ||
67 | |||
68 | memmove(skb->data + uni_diff, skb->data, hdr_len); | ||
69 | unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff); | ||
70 | unicast_packet->packet_type = BAT_UNICAST; | ||
71 | |||
72 | return skb; | ||
73 | } | ||
74 | |||
75 | static void frag_create_entry(struct list_head *head, struct sk_buff *skb) | ||
76 | { | ||
77 | struct frag_packet_list_entry *tfp; | ||
78 | struct unicast_frag_packet *up = | ||
79 | (struct unicast_frag_packet *)skb->data; | ||
80 | |||
81 | /* free and oldest packets stand at the end */ | ||
82 | tfp = list_entry((head)->prev, typeof(*tfp), list); | ||
83 | kfree_skb(tfp->skb); | ||
84 | |||
85 | tfp->seqno = ntohs(up->seqno); | ||
86 | tfp->skb = skb; | ||
87 | list_move(&tfp->list, head); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | static int frag_create_buffer(struct list_head *head) | ||
92 | { | ||
93 | int i; | ||
94 | struct frag_packet_list_entry *tfp; | ||
95 | |||
96 | for (i = 0; i < FRAG_BUFFER_SIZE; i++) { | ||
97 | tfp = kmalloc(sizeof(struct frag_packet_list_entry), | ||
98 | GFP_ATOMIC); | ||
99 | if (!tfp) { | ||
100 | frag_list_free(head); | ||
101 | return -ENOMEM; | ||
102 | } | ||
103 | tfp->skb = NULL; | ||
104 | tfp->seqno = 0; | ||
105 | INIT_LIST_HEAD(&tfp->list); | ||
106 | list_add(&tfp->list, head); | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static struct frag_packet_list_entry *frag_search_packet(struct list_head *head, | ||
113 | struct unicast_frag_packet *up) | ||
114 | { | ||
115 | struct frag_packet_list_entry *tfp; | ||
116 | struct unicast_frag_packet *tmp_up = NULL; | ||
117 | uint16_t search_seqno; | ||
118 | |||
119 | if (up->flags & UNI_FRAG_HEAD) | ||
120 | search_seqno = ntohs(up->seqno)+1; | ||
121 | else | ||
122 | search_seqno = ntohs(up->seqno)-1; | ||
123 | |||
124 | list_for_each_entry(tfp, head, list) { | ||
125 | |||
126 | if (!tfp->skb) | ||
127 | continue; | ||
128 | |||
129 | if (tfp->seqno == ntohs(up->seqno)) | ||
130 | goto mov_tail; | ||
131 | |||
132 | tmp_up = (struct unicast_frag_packet *)tfp->skb->data; | ||
133 | |||
134 | if (tfp->seqno == search_seqno) { | ||
135 | |||
136 | if ((tmp_up->flags & UNI_FRAG_HEAD) != | ||
137 | (up->flags & UNI_FRAG_HEAD)) | ||
138 | return tfp; | ||
139 | else | ||
140 | goto mov_tail; | ||
141 | } | ||
142 | } | ||
143 | return NULL; | ||
144 | |||
145 | mov_tail: | ||
146 | list_move_tail(&tfp->list, head); | ||
147 | return NULL; | ||
148 | } | ||
149 | |||
150 | void frag_list_free(struct list_head *head) | ||
151 | { | ||
152 | struct frag_packet_list_entry *pf, *tmp_pf; | ||
153 | |||
154 | if (!list_empty(head)) { | ||
155 | |||
156 | list_for_each_entry_safe(pf, tmp_pf, head, list) { | ||
157 | kfree_skb(pf->skb); | ||
158 | list_del(&pf->list); | ||
159 | kfree(pf); | ||
160 | } | ||
161 | } | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | /* frag_reassemble_skb(): | ||
166 | * returns NET_RX_DROP if the operation failed - skb is left intact | ||
167 | * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL) | ||
168 | * or the skb could be reassembled (skb_new will point to the new packet and | ||
169 | * skb was freed) | ||
170 | */ | ||
171 | int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
172 | struct sk_buff **new_skb) | ||
173 | { | ||
174 | struct orig_node *orig_node; | ||
175 | struct frag_packet_list_entry *tmp_frag_entry; | ||
176 | int ret = NET_RX_DROP; | ||
177 | struct unicast_frag_packet *unicast_packet = | ||
178 | (struct unicast_frag_packet *)skb->data; | ||
179 | |||
180 | *new_skb = NULL; | ||
181 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
182 | orig_node = ((struct orig_node *) | ||
183 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | ||
184 | unicast_packet->orig)); | ||
185 | |||
186 | if (!orig_node) { | ||
187 | pr_debug("couldn't find originator in orig_hash\n"); | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | orig_node->last_frag_packet = jiffies; | ||
192 | |||
193 | if (list_empty(&orig_node->frag_list) && | ||
194 | frag_create_buffer(&orig_node->frag_list)) { | ||
195 | pr_debug("couldn't create frag buffer\n"); | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | tmp_frag_entry = frag_search_packet(&orig_node->frag_list, | ||
200 | unicast_packet); | ||
201 | |||
202 | if (!tmp_frag_entry) { | ||
203 | frag_create_entry(&orig_node->frag_list, skb); | ||
204 | ret = NET_RX_SUCCESS; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | *new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry, | ||
209 | skb); | ||
210 | /* if not, merge failed */ | ||
211 | if (*new_skb) | ||
212 | ret = NET_RX_SUCCESS; | ||
213 | out: | ||
214 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
220 | struct batman_if *batman_if, uint8_t dstaddr[]) | ||
221 | { | ||
222 | struct unicast_packet tmp_uc, *unicast_packet; | ||
223 | struct sk_buff *frag_skb; | ||
224 | struct unicast_frag_packet *frag1, *frag2; | ||
225 | int uc_hdr_len = sizeof(struct unicast_packet); | ||
226 | int ucf_hdr_len = sizeof(struct unicast_frag_packet); | ||
227 | int data_len = skb->len; | ||
228 | |||
229 | if (!bat_priv->primary_if) | ||
230 | goto dropped; | ||
231 | |||
232 | unicast_packet = (struct unicast_packet *) skb->data; | ||
233 | |||
234 | memcpy(&tmp_uc, unicast_packet, uc_hdr_len); | ||
235 | frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); | ||
236 | skb_split(skb, frag_skb, data_len / 2); | ||
237 | |||
238 | if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || | ||
239 | my_skb_head_push(frag_skb, ucf_hdr_len) < 0) | ||
240 | goto drop_frag; | ||
241 | |||
242 | frag1 = (struct unicast_frag_packet *)skb->data; | ||
243 | frag2 = (struct unicast_frag_packet *)frag_skb->data; | ||
244 | |||
245 | memcpy(frag1, &tmp_uc, sizeof(struct unicast_packet)); | ||
246 | |||
247 | frag1->ttl--; | ||
248 | frag1->version = COMPAT_VERSION; | ||
249 | frag1->packet_type = BAT_UNICAST_FRAG; | ||
250 | |||
251 | memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
252 | memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); | ||
253 | |||
254 | frag1->flags |= UNI_FRAG_HEAD; | ||
255 | frag2->flags &= ~UNI_FRAG_HEAD; | ||
256 | |||
257 | frag1->seqno = htons((uint16_t)atomic_inc_return( | ||
258 | &batman_if->frag_seqno)); | ||
259 | frag2->seqno = htons((uint16_t)atomic_inc_return( | ||
260 | &batman_if->frag_seqno)); | ||
261 | |||
262 | send_skb_packet(skb, batman_if, dstaddr); | ||
263 | send_skb_packet(frag_skb, batman_if, dstaddr); | ||
264 | return NET_RX_SUCCESS; | ||
265 | |||
266 | drop_frag: | ||
267 | kfree_skb(frag_skb); | ||
268 | dropped: | ||
269 | kfree_skb(skb); | ||
270 | return NET_RX_DROP; | ||
271 | } | ||
272 | |||
273 | int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) | ||
274 | { | ||
275 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
276 | struct unicast_packet *unicast_packet; | ||
277 | struct orig_node *orig_node; | ||
278 | struct batman_if *batman_if; | ||
279 | struct neigh_node *router; | ||
280 | int data_len = skb->len; | ||
281 | uint8_t dstaddr[6]; | ||
282 | |||
283 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
284 | |||
285 | /* get routing information */ | ||
286 | if (is_multicast_ether_addr(ethhdr->h_dest)) | ||
287 | orig_node = (struct orig_node *)gw_get_selected(bat_priv); | ||
288 | else | ||
289 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
290 | compare_orig, | ||
291 | choose_orig, | ||
292 | ethhdr->h_dest)); | ||
293 | |||
294 | /* check for hna host */ | ||
295 | if (!orig_node) | ||
296 | orig_node = transtable_search(bat_priv, ethhdr->h_dest); | ||
297 | |||
298 | router = find_router(bat_priv, orig_node, NULL); | ||
299 | |||
300 | if (!router) | ||
301 | goto unlock; | ||
302 | |||
303 | /* don't lock while sending the packets ... we therefore | ||
304 | * copy the required data before sending */ | ||
305 | |||
306 | batman_if = router->if_incoming; | ||
307 | memcpy(dstaddr, router->addr, ETH_ALEN); | ||
308 | |||
309 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
310 | |||
311 | if (batman_if->if_status != IF_ACTIVE) | ||
312 | goto dropped; | ||
313 | |||
314 | if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) | ||
315 | goto dropped; | ||
316 | |||
317 | unicast_packet = (struct unicast_packet *)skb->data; | ||
318 | |||
319 | unicast_packet->version = COMPAT_VERSION; | ||
320 | /* batman packet type: unicast */ | ||
321 | unicast_packet->packet_type = BAT_UNICAST; | ||
322 | /* set unicast ttl */ | ||
323 | unicast_packet->ttl = TTL; | ||
324 | /* copy the destination for faster routing */ | ||
325 | memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); | ||
326 | |||
327 | if (atomic_read(&bat_priv->fragmentation) && | ||
328 | data_len + sizeof(struct unicast_packet) > | ||
329 | batman_if->net_dev->mtu) { | ||
330 | /* send frag skb decreases ttl */ | ||
331 | unicast_packet->ttl++; | ||
332 | return frag_send_skb(skb, bat_priv, batman_if, | ||
333 | dstaddr); | ||
334 | } | ||
335 | send_skb_packet(skb, batman_if, dstaddr); | ||
336 | return 0; | ||
337 | |||
338 | unlock: | ||
339 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
340 | dropped: | ||
341 | kfree_skb(skb); | ||
342 | return 1; | ||
343 | } | ||
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h new file mode 100644 index 000000000000..e32b7867a9a4 --- /dev/null +++ b/net/batman-adv/unicast.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Andreas Langer | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_UNICAST_H_ | ||
23 | #define _NET_BATMAN_ADV_UNICAST_H_ | ||
24 | |||
25 | #define FRAG_TIMEOUT 10000 /* purge frag list entrys after time in ms */ | ||
26 | #define FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */ | ||
27 | |||
28 | int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
29 | struct sk_buff **new_skb); | ||
30 | void frag_list_free(struct list_head *head); | ||
31 | int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); | ||
32 | int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | ||
33 | struct batman_if *batman_if, uint8_t dstaddr[]); | ||
34 | |||
35 | #endif /* _NET_BATMAN_ADV_UNICAST_H_ */ | ||
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c new file mode 100644 index 000000000000..cd4c4231fa48 --- /dev/null +++ b/net/batman-adv/vis.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Simon Wunderlich | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include "main.h" | ||
23 | #include "send.h" | ||
24 | #include "translation-table.h" | ||
25 | #include "vis.h" | ||
26 | #include "soft-interface.h" | ||
27 | #include "hard-interface.h" | ||
28 | #include "hash.h" | ||
29 | #include "originator.h" | ||
30 | |||
31 | #define MAX_VIS_PACKET_SIZE 1000 | ||
32 | |||
33 | /* Returns the smallest signed integer in two's complement with the sizeof x */ | ||
34 | #define smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u))) | ||
35 | |||
36 | /* Checks if a sequence number x is a predecessor/successor of y. | ||
37 | * they handle overflows/underflows and can correctly check for a | ||
38 | * predecessor/successor unless the variable sequence number has grown by | ||
39 | * more then 2**(bitwidth(x)-1)-1. | ||
40 | * This means that for a uint8_t with the maximum value 255, it would think: | ||
41 | * - when adding nothing - it is neither a predecessor nor a successor | ||
42 | * - before adding more than 127 to the starting value - it is a predecessor, | ||
43 | * - when adding 128 - it is neither a predecessor nor a successor, | ||
44 | * - after adding more than 127 to the starting value - it is a successor */ | ||
45 | #define seq_before(x, y) ({typeof(x) _dummy = (x - y); \ | ||
46 | _dummy > smallest_signed_int(_dummy); }) | ||
47 | #define seq_after(x, y) seq_before(y, x) | ||
48 | |||
49 | static void start_vis_timer(struct bat_priv *bat_priv); | ||
50 | |||
51 | /* free the info */ | ||
52 | static void free_info(struct kref *ref) | ||
53 | { | ||
54 | struct vis_info *info = container_of(ref, struct vis_info, refcount); | ||
55 | struct bat_priv *bat_priv = info->bat_priv; | ||
56 | struct recvlist_node *entry, *tmp; | ||
57 | |||
58 | list_del_init(&info->send_list); | ||
59 | spin_lock_bh(&bat_priv->vis_list_lock); | ||
60 | list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { | ||
61 | list_del(&entry->list); | ||
62 | kfree(entry); | ||
63 | } | ||
64 | |||
65 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
66 | kfree_skb(info->skb_packet); | ||
67 | } | ||
68 | |||
69 | /* Compare two vis packets, used by the hashing algorithm */ | ||
70 | static int vis_info_cmp(void *data1, void *data2) | ||
71 | { | ||
72 | struct vis_info *d1, *d2; | ||
73 | struct vis_packet *p1, *p2; | ||
74 | d1 = data1; | ||
75 | d2 = data2; | ||
76 | p1 = (struct vis_packet *)d1->skb_packet->data; | ||
77 | p2 = (struct vis_packet *)d2->skb_packet->data; | ||
78 | return compare_orig(p1->vis_orig, p2->vis_orig); | ||
79 | } | ||
80 | |||
81 | /* hash function to choose an entry in a hash table of given size */ | ||
82 | /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ | ||
83 | static int vis_info_choose(void *data, int size) | ||
84 | { | ||
85 | struct vis_info *vis_info = data; | ||
86 | struct vis_packet *packet; | ||
87 | unsigned char *key; | ||
88 | uint32_t hash = 0; | ||
89 | size_t i; | ||
90 | |||
91 | packet = (struct vis_packet *)vis_info->skb_packet->data; | ||
92 | key = packet->vis_orig; | ||
93 | for (i = 0; i < ETH_ALEN; i++) { | ||
94 | hash += key[i]; | ||
95 | hash += (hash << 10); | ||
96 | hash ^= (hash >> 6); | ||
97 | } | ||
98 | |||
99 | hash += (hash << 3); | ||
100 | hash ^= (hash >> 11); | ||
101 | hash += (hash << 15); | ||
102 | |||
103 | return hash % size; | ||
104 | } | ||
105 | |||
106 | /* insert interface to the list of interfaces of one originator, if it | ||
107 | * does not already exist in the list */ | ||
108 | static void vis_data_insert_interface(const uint8_t *interface, | ||
109 | struct hlist_head *if_list, | ||
110 | bool primary) | ||
111 | { | ||
112 | struct if_list_entry *entry; | ||
113 | struct hlist_node *pos; | ||
114 | |||
115 | hlist_for_each_entry(entry, pos, if_list, list) { | ||
116 | if (compare_orig(entry->addr, (void *)interface)) | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | /* its a new address, add it to the list */ | ||
121 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
122 | if (!entry) | ||
123 | return; | ||
124 | memcpy(entry->addr, interface, ETH_ALEN); | ||
125 | entry->primary = primary; | ||
126 | hlist_add_head(&entry->list, if_list); | ||
127 | } | ||
128 | |||
129 | static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list) | ||
130 | { | ||
131 | struct if_list_entry *entry; | ||
132 | struct hlist_node *pos; | ||
133 | size_t len = 0; | ||
134 | |||
135 | hlist_for_each_entry(entry, pos, if_list, list) { | ||
136 | if (entry->primary) | ||
137 | len += sprintf(buff + len, "PRIMARY, "); | ||
138 | else | ||
139 | len += sprintf(buff + len, "SEC %pM, ", entry->addr); | ||
140 | } | ||
141 | |||
142 | return len; | ||
143 | } | ||
144 | |||
145 | static size_t vis_data_count_prim_sec(struct hlist_head *if_list) | ||
146 | { | ||
147 | struct if_list_entry *entry; | ||
148 | struct hlist_node *pos; | ||
149 | size_t count = 0; | ||
150 | |||
151 | hlist_for_each_entry(entry, pos, if_list, list) { | ||
152 | if (entry->primary) | ||
153 | count += 9; | ||
154 | else | ||
155 | count += 23; | ||
156 | } | ||
157 | |||
158 | return count; | ||
159 | } | ||
160 | |||
161 | /* read an entry */ | ||
162 | static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, | ||
163 | uint8_t *src, bool primary) | ||
164 | { | ||
165 | /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ | ||
166 | if (primary && entry->quality == 0) | ||
167 | return sprintf(buff, "HNA %pM, ", entry->dest); | ||
168 | else if (compare_orig(entry->src, src)) | ||
169 | return sprintf(buff, "TQ %pM %d, ", entry->dest, | ||
170 | entry->quality); | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int vis_seq_print_text(struct seq_file *seq, void *offset) | ||
176 | { | ||
177 | struct hlist_node *walk; | ||
178 | struct hlist_head *head; | ||
179 | struct element_t *bucket; | ||
180 | struct vis_info *info; | ||
181 | struct vis_packet *packet; | ||
182 | struct vis_info_entry *entries; | ||
183 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
184 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
185 | struct hashtable_t *hash = bat_priv->vis_hash; | ||
186 | HLIST_HEAD(vis_if_list); | ||
187 | struct if_list_entry *entry; | ||
188 | struct hlist_node *pos, *n; | ||
189 | int i, j; | ||
190 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
191 | size_t buff_pos, buf_size; | ||
192 | char *buff; | ||
193 | int compare; | ||
194 | |||
195 | if ((!bat_priv->primary_if) || | ||
196 | (vis_server == VIS_TYPE_CLIENT_UPDATE)) | ||
197 | return 0; | ||
198 | |||
199 | buf_size = 1; | ||
200 | /* Estimate length */ | ||
201 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
202 | for (i = 0; i < hash->size; i++) { | ||
203 | head = &hash->table[i]; | ||
204 | |||
205 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
206 | info = bucket->data; | ||
207 | packet = (struct vis_packet *)info->skb_packet->data; | ||
208 | entries = (struct vis_info_entry *) | ||
209 | ((char *)packet + sizeof(struct vis_packet)); | ||
210 | |||
211 | for (j = 0; j < packet->entries; j++) { | ||
212 | if (entries[j].quality == 0) | ||
213 | continue; | ||
214 | compare = | ||
215 | compare_orig(entries[j].src, packet->vis_orig); | ||
216 | vis_data_insert_interface(entries[j].src, | ||
217 | &vis_if_list, | ||
218 | compare); | ||
219 | } | ||
220 | |||
221 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | ||
222 | buf_size += 18 + 26 * packet->entries; | ||
223 | |||
224 | /* add primary/secondary records */ | ||
225 | if (compare_orig(entry->addr, packet->vis_orig)) | ||
226 | buf_size += | ||
227 | vis_data_count_prim_sec(&vis_if_list); | ||
228 | |||
229 | buf_size += 1; | ||
230 | } | ||
231 | |||
232 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | ||
233 | list) { | ||
234 | hlist_del(&entry->list); | ||
235 | kfree(entry); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
241 | if (!buff) { | ||
242 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
243 | return -ENOMEM; | ||
244 | } | ||
245 | buff[0] = '\0'; | ||
246 | buff_pos = 0; | ||
247 | |||
248 | for (i = 0; i < hash->size; i++) { | ||
249 | head = &hash->table[i]; | ||
250 | |||
251 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
252 | info = bucket->data; | ||
253 | packet = (struct vis_packet *)info->skb_packet->data; | ||
254 | entries = (struct vis_info_entry *) | ||
255 | ((char *)packet + sizeof(struct vis_packet)); | ||
256 | |||
257 | for (j = 0; j < packet->entries; j++) { | ||
258 | if (entries[j].quality == 0) | ||
259 | continue; | ||
260 | compare = | ||
261 | compare_orig(entries[j].src, packet->vis_orig); | ||
262 | vis_data_insert_interface(entries[j].src, | ||
263 | &vis_if_list, | ||
264 | compare); | ||
265 | } | ||
266 | |||
267 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | ||
268 | buff_pos += sprintf(buff + buff_pos, "%pM,", | ||
269 | entry->addr); | ||
270 | |||
271 | for (i = 0; i < packet->entries; i++) | ||
272 | buff_pos += vis_data_read_entry( | ||
273 | buff + buff_pos, | ||
274 | &entries[i], | ||
275 | entry->addr, | ||
276 | entry->primary); | ||
277 | |||
278 | /* add primary/secondary records */ | ||
279 | if (compare_orig(entry->addr, packet->vis_orig)) | ||
280 | buff_pos += | ||
281 | vis_data_read_prim_sec(buff + buff_pos, | ||
282 | &vis_if_list); | ||
283 | |||
284 | buff_pos += sprintf(buff + buff_pos, "\n"); | ||
285 | } | ||
286 | |||
287 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | ||
288 | list) { | ||
289 | hlist_del(&entry->list); | ||
290 | kfree(entry); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
296 | |||
297 | seq_printf(seq, "%s", buff); | ||
298 | kfree(buff); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* add the info packet to the send list, if it was not | ||
304 | * already linked in. */ | ||
305 | static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info) | ||
306 | { | ||
307 | if (list_empty(&info->send_list)) { | ||
308 | kref_get(&info->refcount); | ||
309 | list_add_tail(&info->send_list, &bat_priv->vis_send_list); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /* delete the info packet from the send list, if it was | ||
314 | * linked in. */ | ||
315 | static void send_list_del(struct vis_info *info) | ||
316 | { | ||
317 | if (!list_empty(&info->send_list)) { | ||
318 | list_del_init(&info->send_list); | ||
319 | kref_put(&info->refcount, free_info); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | /* tries to add one entry to the receive list. */ | ||
324 | static void recv_list_add(struct bat_priv *bat_priv, | ||
325 | struct list_head *recv_list, char *mac) | ||
326 | { | ||
327 | struct recvlist_node *entry; | ||
328 | |||
329 | entry = kmalloc(sizeof(struct recvlist_node), GFP_ATOMIC); | ||
330 | if (!entry) | ||
331 | return; | ||
332 | |||
333 | memcpy(entry->mac, mac, ETH_ALEN); | ||
334 | spin_lock_bh(&bat_priv->vis_list_lock); | ||
335 | list_add_tail(&entry->list, recv_list); | ||
336 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
337 | } | ||
338 | |||
339 | /* returns 1 if this mac is in the recv_list */ | ||
340 | static int recv_list_is_in(struct bat_priv *bat_priv, | ||
341 | struct list_head *recv_list, char *mac) | ||
342 | { | ||
343 | struct recvlist_node *entry; | ||
344 | |||
345 | spin_lock_bh(&bat_priv->vis_list_lock); | ||
346 | list_for_each_entry(entry, recv_list, list) { | ||
347 | if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { | ||
348 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
349 | return 1; | ||
350 | } | ||
351 | } | ||
352 | spin_unlock_bh(&bat_priv->vis_list_lock); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, | ||
357 | * broken.. ). vis hash must be locked outside. is_new is set when the packet | ||
358 | * is newer than old entries in the hash. */ | ||
359 | static struct vis_info *add_packet(struct bat_priv *bat_priv, | ||
360 | struct vis_packet *vis_packet, | ||
361 | int vis_info_len, int *is_new, | ||
362 | int make_broadcast) | ||
363 | { | ||
364 | struct vis_info *info, *old_info; | ||
365 | struct vis_packet *search_packet, *old_packet; | ||
366 | struct vis_info search_elem; | ||
367 | struct vis_packet *packet; | ||
368 | int hash_added; | ||
369 | |||
370 | *is_new = 0; | ||
371 | /* sanity check */ | ||
372 | if (!bat_priv->vis_hash) | ||
373 | return NULL; | ||
374 | |||
375 | /* see if the packet is already in vis_hash */ | ||
376 | search_elem.skb_packet = dev_alloc_skb(sizeof(struct vis_packet)); | ||
377 | if (!search_elem.skb_packet) | ||
378 | return NULL; | ||
379 | search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet, | ||
380 | sizeof(struct vis_packet)); | ||
381 | |||
382 | memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); | ||
383 | old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
384 | &search_elem); | ||
385 | kfree_skb(search_elem.skb_packet); | ||
386 | |||
387 | if (old_info) { | ||
388 | old_packet = (struct vis_packet *)old_info->skb_packet->data; | ||
389 | if (!seq_after(ntohl(vis_packet->seqno), | ||
390 | ntohl(old_packet->seqno))) { | ||
391 | if (old_packet->seqno == vis_packet->seqno) { | ||
392 | recv_list_add(bat_priv, &old_info->recv_list, | ||
393 | vis_packet->sender_orig); | ||
394 | return old_info; | ||
395 | } else { | ||
396 | /* newer packet is already in hash. */ | ||
397 | return NULL; | ||
398 | } | ||
399 | } | ||
400 | /* remove old entry */ | ||
401 | hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
402 | old_info); | ||
403 | send_list_del(old_info); | ||
404 | kref_put(&old_info->refcount, free_info); | ||
405 | } | ||
406 | |||
407 | info = kmalloc(sizeof(struct vis_info), GFP_ATOMIC); | ||
408 | if (!info) | ||
409 | return NULL; | ||
410 | |||
411 | info->skb_packet = dev_alloc_skb(sizeof(struct vis_packet) + | ||
412 | vis_info_len + sizeof(struct ethhdr)); | ||
413 | if (!info->skb_packet) { | ||
414 | kfree(info); | ||
415 | return NULL; | ||
416 | } | ||
417 | skb_reserve(info->skb_packet, sizeof(struct ethhdr)); | ||
418 | packet = (struct vis_packet *)skb_put(info->skb_packet, | ||
419 | sizeof(struct vis_packet) + | ||
420 | vis_info_len); | ||
421 | |||
422 | kref_init(&info->refcount); | ||
423 | INIT_LIST_HEAD(&info->send_list); | ||
424 | INIT_LIST_HEAD(&info->recv_list); | ||
425 | info->first_seen = jiffies; | ||
426 | info->bat_priv = bat_priv; | ||
427 | memcpy(packet, vis_packet, sizeof(struct vis_packet) + vis_info_len); | ||
428 | |||
429 | /* initialize and add new packet. */ | ||
430 | *is_new = 1; | ||
431 | |||
432 | /* Make it a broadcast packet, if required */ | ||
433 | if (make_broadcast) | ||
434 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); | ||
435 | |||
436 | /* repair if entries is longer than packet. */ | ||
437 | if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len) | ||
438 | packet->entries = vis_info_len / sizeof(struct vis_info_entry); | ||
439 | |||
440 | recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); | ||
441 | |||
442 | /* try to add it */ | ||
443 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
444 | info); | ||
445 | if (hash_added < 0) { | ||
446 | /* did not work (for some reason) */ | ||
447 | kref_put(&old_info->refcount, free_info); | ||
448 | info = NULL; | ||
449 | } | ||
450 | |||
451 | return info; | ||
452 | } | ||
453 | |||
454 | /* handle the server sync packet, forward if needed. */ | ||
455 | void receive_server_sync_packet(struct bat_priv *bat_priv, | ||
456 | struct vis_packet *vis_packet, | ||
457 | int vis_info_len) | ||
458 | { | ||
459 | struct vis_info *info; | ||
460 | int is_new, make_broadcast; | ||
461 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
462 | |||
463 | make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC); | ||
464 | |||
465 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
466 | info = add_packet(bat_priv, vis_packet, vis_info_len, | ||
467 | &is_new, make_broadcast); | ||
468 | if (!info) | ||
469 | goto end; | ||
470 | |||
471 | /* only if we are server ourselves and packet is newer than the one in | ||
472 | * hash.*/ | ||
473 | if (vis_server == VIS_TYPE_SERVER_SYNC && is_new) | ||
474 | send_list_add(bat_priv, info); | ||
475 | end: | ||
476 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
477 | } | ||
478 | |||
479 | /* handle an incoming client update packet and schedule forward if needed. */ | ||
480 | void receive_client_update_packet(struct bat_priv *bat_priv, | ||
481 | struct vis_packet *vis_packet, | ||
482 | int vis_info_len) | ||
483 | { | ||
484 | struct vis_info *info; | ||
485 | struct vis_packet *packet; | ||
486 | int is_new; | ||
487 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
488 | int are_target = 0; | ||
489 | |||
490 | /* clients shall not broadcast. */ | ||
491 | if (is_broadcast_ether_addr(vis_packet->target_orig)) | ||
492 | return; | ||
493 | |||
494 | /* Are we the target for this VIS packet? */ | ||
495 | if (vis_server == VIS_TYPE_SERVER_SYNC && | ||
496 | is_my_mac(vis_packet->target_orig)) | ||
497 | are_target = 1; | ||
498 | |||
499 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
500 | info = add_packet(bat_priv, vis_packet, vis_info_len, | ||
501 | &is_new, are_target); | ||
502 | |||
503 | if (!info) | ||
504 | goto end; | ||
505 | /* note that outdated packets will be dropped at this point. */ | ||
506 | |||
507 | packet = (struct vis_packet *)info->skb_packet->data; | ||
508 | |||
509 | /* send only if we're the target server or ... */ | ||
510 | if (are_target && is_new) { | ||
511 | packet->vis_type = VIS_TYPE_SERVER_SYNC; /* upgrade! */ | ||
512 | send_list_add(bat_priv, info); | ||
513 | |||
514 | /* ... we're not the recipient (and thus need to forward). */ | ||
515 | } else if (!is_my_mac(packet->target_orig)) { | ||
516 | send_list_add(bat_priv, info); | ||
517 | } | ||
518 | |||
519 | end: | ||
520 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
521 | } | ||
522 | |||
523 | /* Walk the originators and find the VIS server with the best tq. Set the packet | ||
524 | * address to its address and return the best_tq. | ||
525 | * | ||
526 | * Must be called with the originator hash locked */ | ||
527 | static int find_best_vis_server(struct bat_priv *bat_priv, | ||
528 | struct vis_info *info) | ||
529 | { | ||
530 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
531 | struct hlist_node *walk; | ||
532 | struct hlist_head *head; | ||
533 | struct element_t *bucket; | ||
534 | struct orig_node *orig_node; | ||
535 | struct vis_packet *packet; | ||
536 | int best_tq = -1, i; | ||
537 | |||
538 | packet = (struct vis_packet *)info->skb_packet->data; | ||
539 | |||
540 | for (i = 0; i < hash->size; i++) { | ||
541 | head = &hash->table[i]; | ||
542 | |||
543 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
544 | orig_node = bucket->data; | ||
545 | if ((orig_node) && (orig_node->router) && | ||
546 | (orig_node->flags & VIS_SERVER) && | ||
547 | (orig_node->router->tq_avg > best_tq)) { | ||
548 | best_tq = orig_node->router->tq_avg; | ||
549 | memcpy(packet->target_orig, orig_node->orig, | ||
550 | ETH_ALEN); | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | |||
555 | return best_tq; | ||
556 | } | ||
557 | |||
558 | /* Return true if the vis packet is full. */ | ||
559 | static bool vis_packet_full(struct vis_info *info) | ||
560 | { | ||
561 | struct vis_packet *packet; | ||
562 | packet = (struct vis_packet *)info->skb_packet->data; | ||
563 | |||
564 | if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry) | ||
565 | < packet->entries + 1) | ||
566 | return true; | ||
567 | return false; | ||
568 | } | ||
569 | |||
570 | /* generates a packet of own vis data, | ||
571 | * returns 0 on success, -1 if no packet could be generated */ | ||
572 | static int generate_vis_packet(struct bat_priv *bat_priv) | ||
573 | { | ||
574 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
575 | struct hlist_node *walk; | ||
576 | struct hlist_head *head; | ||
577 | struct element_t *bucket; | ||
578 | struct orig_node *orig_node; | ||
579 | struct neigh_node *neigh_node; | ||
580 | struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; | ||
581 | struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; | ||
582 | struct vis_info_entry *entry; | ||
583 | struct hna_local_entry *hna_local_entry; | ||
584 | int best_tq = -1, i; | ||
585 | |||
586 | info->first_seen = jiffies; | ||
587 | packet->vis_type = atomic_read(&bat_priv->vis_mode); | ||
588 | |||
589 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
590 | memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); | ||
591 | packet->ttl = TTL; | ||
592 | packet->seqno = htonl(ntohl(packet->seqno) + 1); | ||
593 | packet->entries = 0; | ||
594 | skb_trim(info->skb_packet, sizeof(struct vis_packet)); | ||
595 | |||
596 | if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { | ||
597 | best_tq = find_best_vis_server(bat_priv, info); | ||
598 | |||
599 | if (best_tq < 0) { | ||
600 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
601 | return -1; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | for (i = 0; i < hash->size; i++) { | ||
606 | head = &hash->table[i]; | ||
607 | |||
608 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
609 | orig_node = bucket->data; | ||
610 | neigh_node = orig_node->router; | ||
611 | |||
612 | if (!neigh_node) | ||
613 | continue; | ||
614 | |||
615 | if (!compare_orig(neigh_node->addr, orig_node->orig)) | ||
616 | continue; | ||
617 | |||
618 | if (neigh_node->if_incoming->if_status != IF_ACTIVE) | ||
619 | continue; | ||
620 | |||
621 | if (neigh_node->tq_avg < 1) | ||
622 | continue; | ||
623 | |||
624 | /* fill one entry into buffer. */ | ||
625 | entry = (struct vis_info_entry *) | ||
626 | skb_put(info->skb_packet, sizeof(*entry)); | ||
627 | memcpy(entry->src, | ||
628 | neigh_node->if_incoming->net_dev->dev_addr, | ||
629 | ETH_ALEN); | ||
630 | memcpy(entry->dest, orig_node->orig, ETH_ALEN); | ||
631 | entry->quality = neigh_node->tq_avg; | ||
632 | packet->entries++; | ||
633 | |||
634 | if (vis_packet_full(info)) { | ||
635 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
636 | return 0; | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | |||
641 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
642 | |||
643 | hash = bat_priv->hna_local_hash; | ||
644 | |||
645 | spin_lock_bh(&bat_priv->hna_lhash_lock); | ||
646 | for (i = 0; i < hash->size; i++) { | ||
647 | head = &hash->table[i]; | ||
648 | |||
649 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
650 | hna_local_entry = bucket->data; | ||
651 | entry = (struct vis_info_entry *) | ||
652 | skb_put(info->skb_packet, | ||
653 | sizeof(*entry)); | ||
654 | memset(entry->src, 0, ETH_ALEN); | ||
655 | memcpy(entry->dest, hna_local_entry->addr, ETH_ALEN); | ||
656 | entry->quality = 0; /* 0 means HNA */ | ||
657 | packet->entries++; | ||
658 | |||
659 | if (vis_packet_full(info)) { | ||
660 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
661 | return 0; | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
666 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | /* free old vis packets. Must be called with this vis_hash_lock | ||
671 | * held */ | ||
672 | static void purge_vis_packets(struct bat_priv *bat_priv) | ||
673 | { | ||
674 | int i; | ||
675 | struct hashtable_t *hash = bat_priv->vis_hash; | ||
676 | struct hlist_node *walk, *safe; | ||
677 | struct hlist_head *head; | ||
678 | struct element_t *bucket; | ||
679 | struct vis_info *info; | ||
680 | |||
681 | for (i = 0; i < hash->size; i++) { | ||
682 | head = &hash->table[i]; | ||
683 | |||
684 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | ||
685 | info = bucket->data; | ||
686 | |||
687 | /* never purge own data. */ | ||
688 | if (info == bat_priv->my_vis_info) | ||
689 | continue; | ||
690 | |||
691 | if (time_after(jiffies, | ||
692 | info->first_seen + VIS_TIMEOUT * HZ)) { | ||
693 | hlist_del(walk); | ||
694 | kfree(bucket); | ||
695 | send_list_del(info); | ||
696 | kref_put(&info->refcount, free_info); | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | |||
702 | static void broadcast_vis_packet(struct bat_priv *bat_priv, | ||
703 | struct vis_info *info) | ||
704 | { | ||
705 | struct hashtable_t *hash = bat_priv->orig_hash; | ||
706 | struct hlist_node *walk; | ||
707 | struct hlist_head *head; | ||
708 | struct element_t *bucket; | ||
709 | struct orig_node *orig_node; | ||
710 | struct vis_packet *packet; | ||
711 | struct sk_buff *skb; | ||
712 | struct batman_if *batman_if; | ||
713 | uint8_t dstaddr[ETH_ALEN]; | ||
714 | int i; | ||
715 | |||
716 | |||
717 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
718 | packet = (struct vis_packet *)info->skb_packet->data; | ||
719 | |||
720 | /* send to all routers in range. */ | ||
721 | for (i = 0; i < hash->size; i++) { | ||
722 | head = &hash->table[i]; | ||
723 | |||
724 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
725 | orig_node = bucket->data; | ||
726 | |||
727 | /* if it's a vis server and reachable, send it. */ | ||
728 | if ((!orig_node) || (!orig_node->router)) | ||
729 | continue; | ||
730 | if (!(orig_node->flags & VIS_SERVER)) | ||
731 | continue; | ||
732 | /* don't send it if we already received the packet from | ||
733 | * this node. */ | ||
734 | if (recv_list_is_in(bat_priv, &info->recv_list, | ||
735 | orig_node->orig)) | ||
736 | continue; | ||
737 | |||
738 | memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); | ||
739 | batman_if = orig_node->router->if_incoming; | ||
740 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
741 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
742 | |||
743 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | ||
744 | if (skb) | ||
745 | send_skb_packet(skb, batman_if, dstaddr); | ||
746 | |||
747 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
748 | } | ||
749 | |||
750 | } | ||
751 | |||
752 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
753 | } | ||
754 | |||
755 | static void unicast_vis_packet(struct bat_priv *bat_priv, | ||
756 | struct vis_info *info) | ||
757 | { | ||
758 | struct orig_node *orig_node; | ||
759 | struct sk_buff *skb; | ||
760 | struct vis_packet *packet; | ||
761 | struct batman_if *batman_if; | ||
762 | uint8_t dstaddr[ETH_ALEN]; | ||
763 | |||
764 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
765 | packet = (struct vis_packet *)info->skb_packet->data; | ||
766 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | ||
767 | compare_orig, choose_orig, | ||
768 | packet->target_orig)); | ||
769 | |||
770 | if ((!orig_node) || (!orig_node->router)) | ||
771 | goto out; | ||
772 | |||
773 | /* don't lock while sending the packets ... we therefore | ||
774 | * copy the required data before sending */ | ||
775 | batman_if = orig_node->router->if_incoming; | ||
776 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
777 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
778 | |||
779 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | ||
780 | if (skb) | ||
781 | send_skb_packet(skb, batman_if, dstaddr); | ||
782 | |||
783 | return; | ||
784 | |||
785 | out: | ||
786 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
787 | } | ||
788 | |||
789 | /* only send one vis packet. called from send_vis_packets() */ | ||
790 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | ||
791 | { | ||
792 | struct vis_packet *packet; | ||
793 | |||
794 | packet = (struct vis_packet *)info->skb_packet->data; | ||
795 | if (packet->ttl < 2) { | ||
796 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); | ||
797 | return; | ||
798 | } | ||
799 | |||
800 | memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, | ||
801 | ETH_ALEN); | ||
802 | packet->ttl--; | ||
803 | |||
804 | if (is_broadcast_ether_addr(packet->target_orig)) | ||
805 | broadcast_vis_packet(bat_priv, info); | ||
806 | else | ||
807 | unicast_vis_packet(bat_priv, info); | ||
808 | packet->ttl++; /* restore TTL */ | ||
809 | } | ||
810 | |||
811 | /* called from timer; send (and maybe generate) vis packet. */ | ||
812 | static void send_vis_packets(struct work_struct *work) | ||
813 | { | ||
814 | struct delayed_work *delayed_work = | ||
815 | container_of(work, struct delayed_work, work); | ||
816 | struct bat_priv *bat_priv = | ||
817 | container_of(delayed_work, struct bat_priv, vis_work); | ||
818 | struct vis_info *info, *temp; | ||
819 | |||
820 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
821 | purge_vis_packets(bat_priv); | ||
822 | |||
823 | if (generate_vis_packet(bat_priv) == 0) { | ||
824 | /* schedule if generation was successful */ | ||
825 | send_list_add(bat_priv, bat_priv->my_vis_info); | ||
826 | } | ||
827 | |||
828 | list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list, | ||
829 | send_list) { | ||
830 | |||
831 | kref_get(&info->refcount); | ||
832 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
833 | |||
834 | if (bat_priv->primary_if) | ||
835 | send_vis_packet(bat_priv, info); | ||
836 | |||
837 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
838 | send_list_del(info); | ||
839 | kref_put(&info->refcount, free_info); | ||
840 | } | ||
841 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
842 | start_vis_timer(bat_priv); | ||
843 | } | ||
844 | |||
845 | /* init the vis server. this may only be called when if_list is already | ||
846 | * initialized (e.g. bat0 is initialized, interfaces have been added) */ | ||
847 | int vis_init(struct bat_priv *bat_priv) | ||
848 | { | ||
849 | struct vis_packet *packet; | ||
850 | int hash_added; | ||
851 | |||
852 | if (bat_priv->vis_hash) | ||
853 | return 1; | ||
854 | |||
855 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
856 | |||
857 | bat_priv->vis_hash = hash_new(256); | ||
858 | if (!bat_priv->vis_hash) { | ||
859 | pr_err("Can't initialize vis_hash\n"); | ||
860 | goto err; | ||
861 | } | ||
862 | |||
863 | bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC); | ||
864 | if (!bat_priv->my_vis_info) { | ||
865 | pr_err("Can't initialize vis packet\n"); | ||
866 | goto err; | ||
867 | } | ||
868 | |||
869 | bat_priv->my_vis_info->skb_packet = dev_alloc_skb( | ||
870 | sizeof(struct vis_packet) + | ||
871 | MAX_VIS_PACKET_SIZE + | ||
872 | sizeof(struct ethhdr)); | ||
873 | if (!bat_priv->my_vis_info->skb_packet) | ||
874 | goto free_info; | ||
875 | |||
876 | skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr)); | ||
877 | packet = (struct vis_packet *)skb_put( | ||
878 | bat_priv->my_vis_info->skb_packet, | ||
879 | sizeof(struct vis_packet)); | ||
880 | |||
881 | /* prefill the vis info */ | ||
882 | bat_priv->my_vis_info->first_seen = jiffies - | ||
883 | msecs_to_jiffies(VIS_INTERVAL); | ||
884 | INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list); | ||
885 | INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list); | ||
886 | kref_init(&bat_priv->my_vis_info->refcount); | ||
887 | bat_priv->my_vis_info->bat_priv = bat_priv; | ||
888 | packet->version = COMPAT_VERSION; | ||
889 | packet->packet_type = BAT_VIS; | ||
890 | packet->ttl = TTL; | ||
891 | packet->seqno = 0; | ||
892 | packet->entries = 0; | ||
893 | |||
894 | INIT_LIST_HEAD(&bat_priv->vis_send_list); | ||
895 | |||
896 | hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, | ||
897 | bat_priv->my_vis_info); | ||
898 | if (hash_added < 0) { | ||
899 | pr_err("Can't add own vis packet into hash\n"); | ||
900 | /* not in hash, need to remove it manually. */ | ||
901 | kref_put(&bat_priv->my_vis_info->refcount, free_info); | ||
902 | goto err; | ||
903 | } | ||
904 | |||
905 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
906 | start_vis_timer(bat_priv); | ||
907 | return 1; | ||
908 | |||
909 | free_info: | ||
910 | kfree(bat_priv->my_vis_info); | ||
911 | bat_priv->my_vis_info = NULL; | ||
912 | err: | ||
913 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
914 | vis_quit(bat_priv); | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | /* Decrease the reference count on a hash item info */ | ||
919 | static void free_info_ref(void *data, void *arg) | ||
920 | { | ||
921 | struct vis_info *info = data; | ||
922 | |||
923 | send_list_del(info); | ||
924 | kref_put(&info->refcount, free_info); | ||
925 | } | ||
926 | |||
927 | /* shutdown vis-server */ | ||
928 | void vis_quit(struct bat_priv *bat_priv) | ||
929 | { | ||
930 | if (!bat_priv->vis_hash) | ||
931 | return; | ||
932 | |||
933 | cancel_delayed_work_sync(&bat_priv->vis_work); | ||
934 | |||
935 | spin_lock_bh(&bat_priv->vis_hash_lock); | ||
936 | /* properly remove, kill timers ... */ | ||
937 | hash_delete(bat_priv->vis_hash, free_info_ref, NULL); | ||
938 | bat_priv->vis_hash = NULL; | ||
939 | bat_priv->my_vis_info = NULL; | ||
940 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
941 | } | ||
942 | |||
943 | /* schedule packets for (re)transmission */ | ||
944 | static void start_vis_timer(struct bat_priv *bat_priv) | ||
945 | { | ||
946 | INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets); | ||
947 | queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work, | ||
948 | msecs_to_jiffies(VIS_INTERVAL)); | ||
949 | } | ||
diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h new file mode 100644 index 000000000000..2c3b33089a9b --- /dev/null +++ b/net/batman-adv/vis.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2010 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Simon Wunderlich, Marek Lindner | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public | ||
8 | * License as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | * 02110-1301, USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _NET_BATMAN_ADV_VIS_H_ | ||
23 | #define _NET_BATMAN_ADV_VIS_H_ | ||
24 | |||
25 | #define VIS_TIMEOUT 200 /* timeout of vis packets in seconds */ | ||
26 | |||
27 | int vis_seq_print_text(struct seq_file *seq, void *offset); | ||
28 | void receive_server_sync_packet(struct bat_priv *bat_priv, | ||
29 | struct vis_packet *vis_packet, | ||
30 | int vis_info_len); | ||
31 | void receive_client_update_packet(struct bat_priv *bat_priv, | ||
32 | struct vis_packet *vis_packet, | ||
33 | int vis_info_len); | ||
34 | int vis_init(struct bat_priv *bat_priv); | ||
35 | void vis_quit(struct bat_priv *bat_priv); | ||
36 | |||
37 | #endif /* _NET_BATMAN_ADV_VIS_H_ */ | ||
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index d1e433f7d673..7ca1f46a471a 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile | |||
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP) += bnep/ | |||
10 | obj-$(CONFIG_BT_CMTP) += cmtp/ | 10 | obj-$(CONFIG_BT_CMTP) += cmtp/ |
11 | obj-$(CONFIG_BT_HIDP) += hidp/ | 11 | obj-$(CONFIG_BT_HIDP) += hidp/ |
12 | 12 | ||
13 | bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o | 13 | bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o |
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index f10b41fb05a0..5868597534e5 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c | |||
@@ -648,6 +648,7 @@ int bnep_del_connection(struct bnep_conndel_req *req) | |||
648 | 648 | ||
649 | static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) | 649 | static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) |
650 | { | 650 | { |
651 | memset(ci, 0, sizeof(*ci)); | ||
651 | memcpy(ci->dst, s->eh.h_source, ETH_ALEN); | 652 | memcpy(ci->dst, s->eh.h_source, ETH_ALEN); |
652 | strcpy(ci->device, s->dev->name); | 653 | strcpy(ci->device, s->dev->name); |
653 | ci->flags = s->flags; | 654 | ci->flags = s->flags; |
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index ec0a1347f933..8e5f292529ac 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c | |||
@@ -78,6 +78,7 @@ static void __cmtp_unlink_session(struct cmtp_session *session) | |||
78 | 78 | ||
79 | static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) | 79 | static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) |
80 | { | 80 | { |
81 | memset(ci, 0, sizeof(*ci)); | ||
81 | bacpy(&ci->bdaddr, &session->bdaddr); | 82 | bacpy(&ci->bdaddr, &session->bdaddr); |
82 | 83 | ||
83 | ci->flags = session->flags; | 84 | ci->flags = session->flags; |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0b1e460fe440..6b90a4191734 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <net/sock.h> | 39 | #include <net/sock.h> |
40 | 40 | ||
41 | #include <asm/system.h> | 41 | #include <asm/system.h> |
42 | #include <asm/uaccess.h> | 42 | #include <linux/uaccess.h> |
43 | #include <asm/unaligned.h> | 43 | #include <asm/unaligned.h> |
44 | 44 | ||
45 | #include <net/bluetooth/bluetooth.h> | 45 | #include <net/bluetooth/bluetooth.h> |
@@ -66,7 +66,8 @@ void hci_acl_connect(struct hci_conn *conn) | |||
66 | bacpy(&cp.bdaddr, &conn->dst); | 66 | bacpy(&cp.bdaddr, &conn->dst); |
67 | cp.pscan_rep_mode = 0x02; | 67 | cp.pscan_rep_mode = 0x02; |
68 | 68 | ||
69 | if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { | 69 | ie = hci_inquiry_cache_lookup(hdev, &conn->dst); |
70 | if (ie) { | ||
70 | if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { | 71 | if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { |
71 | cp.pscan_rep_mode = ie->data.pscan_rep_mode; | 72 | cp.pscan_rep_mode = ie->data.pscan_rep_mode; |
72 | cp.pscan_mode = ie->data.pscan_mode; | 73 | cp.pscan_mode = ie->data.pscan_mode; |
@@ -368,8 +369,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 | |||
368 | 369 | ||
369 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 370 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); |
370 | 371 | ||
371 | if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) { | 372 | acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); |
372 | if (!(acl = hci_conn_add(hdev, ACL_LINK, dst))) | 373 | if (!acl) { |
374 | acl = hci_conn_add(hdev, ACL_LINK, dst); | ||
375 | if (!acl) | ||
373 | return NULL; | 376 | return NULL; |
374 | } | 377 | } |
375 | 378 | ||
@@ -389,8 +392,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 | |||
389 | if (type == ACL_LINK) | 392 | if (type == ACL_LINK) |
390 | return acl; | 393 | return acl; |
391 | 394 | ||
392 | if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) { | 395 | sco = hci_conn_hash_lookup_ba(hdev, type, dst); |
393 | if (!(sco = hci_conn_add(hdev, type, dst))) { | 396 | if (!sco) { |
397 | sco = hci_conn_add(hdev, type, dst); | ||
398 | if (!sco) { | ||
394 | hci_conn_put(acl); | 399 | hci_conn_put(acl); |
395 | return NULL; | 400 | return NULL; |
396 | } | 401 | } |
@@ -647,10 +652,12 @@ int hci_get_conn_list(void __user *arg) | |||
647 | 652 | ||
648 | size = sizeof(req) + req.conn_num * sizeof(*ci); | 653 | size = sizeof(req) + req.conn_num * sizeof(*ci); |
649 | 654 | ||
650 | if (!(cl = kmalloc(size, GFP_KERNEL))) | 655 | cl = kmalloc(size, GFP_KERNEL); |
656 | if (!cl) | ||
651 | return -ENOMEM; | 657 | return -ENOMEM; |
652 | 658 | ||
653 | if (!(hdev = hci_dev_get(req.dev_id))) { | 659 | hdev = hci_dev_get(req.dev_id); |
660 | if (!hdev) { | ||
654 | kfree(cl); | 661 | kfree(cl); |
655 | return -ENODEV; | 662 | return -ENODEV; |
656 | } | 663 | } |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bc2a052e518b..51c61f75a797 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <net/sock.h> | 44 | #include <net/sock.h> |
45 | 45 | ||
46 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | #include <asm/uaccess.h> | 47 | #include <linux/uaccess.h> |
48 | #include <asm/unaligned.h> | 48 | #include <asm/unaligned.h> |
49 | 49 | ||
50 | #include <net/bluetooth/bluetooth.h> | 50 | #include <net/bluetooth/bluetooth.h> |
@@ -349,20 +349,23 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b | |||
349 | void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) | 349 | void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) |
350 | { | 350 | { |
351 | struct inquiry_cache *cache = &hdev->inq_cache; | 351 | struct inquiry_cache *cache = &hdev->inq_cache; |
352 | struct inquiry_entry *e; | 352 | struct inquiry_entry *ie; |
353 | 353 | ||
354 | BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); | 354 | BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); |
355 | 355 | ||
356 | if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) { | 356 | ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr); |
357 | if (!ie) { | ||
357 | /* Entry not in the cache. Add new one. */ | 358 | /* Entry not in the cache. Add new one. */ |
358 | if (!(e = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) | 359 | ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); |
360 | if (!ie) | ||
359 | return; | 361 | return; |
360 | e->next = cache->list; | 362 | |
361 | cache->list = e; | 363 | ie->next = cache->list; |
364 | cache->list = ie; | ||
362 | } | 365 | } |
363 | 366 | ||
364 | memcpy(&e->data, data, sizeof(*data)); | 367 | memcpy(&ie->data, data, sizeof(*data)); |
365 | e->timestamp = jiffies; | 368 | ie->timestamp = jiffies; |
366 | cache->timestamp = jiffies; | 369 | cache->timestamp = jiffies; |
367 | } | 370 | } |
368 | 371 | ||
@@ -422,16 +425,20 @@ int hci_inquiry(void __user *arg) | |||
422 | 425 | ||
423 | hci_dev_lock_bh(hdev); | 426 | hci_dev_lock_bh(hdev); |
424 | if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || | 427 | if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || |
425 | inquiry_cache_empty(hdev) || | 428 | inquiry_cache_empty(hdev) || |
426 | ir.flags & IREQ_CACHE_FLUSH) { | 429 | ir.flags & IREQ_CACHE_FLUSH) { |
427 | inquiry_cache_flush(hdev); | 430 | inquiry_cache_flush(hdev); |
428 | do_inquiry = 1; | 431 | do_inquiry = 1; |
429 | } | 432 | } |
430 | hci_dev_unlock_bh(hdev); | 433 | hci_dev_unlock_bh(hdev); |
431 | 434 | ||
432 | timeo = ir.length * msecs_to_jiffies(2000); | 435 | timeo = ir.length * msecs_to_jiffies(2000); |
433 | if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) | 436 | |
434 | goto done; | 437 | if (do_inquiry) { |
438 | err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo); | ||
439 | if (err < 0) | ||
440 | goto done; | ||
441 | } | ||
435 | 442 | ||
436 | /* for unlimited number of responses we will use buffer with 255 entries */ | 443 | /* for unlimited number of responses we will use buffer with 255 entries */ |
437 | max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp; | 444 | max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp; |
@@ -439,7 +446,8 @@ int hci_inquiry(void __user *arg) | |||
439 | /* cache_dump can't sleep. Therefore we allocate temp buffer and then | 446 | /* cache_dump can't sleep. Therefore we allocate temp buffer and then |
440 | * copy it to the user space. | 447 | * copy it to the user space. |
441 | */ | 448 | */ |
442 | if (!(buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL))) { | 449 | buf = kmalloc(sizeof(struct inquiry_info) *max_rsp, GFP_KERNEL); |
450 | if (!buf) { | ||
443 | err = -ENOMEM; | 451 | err = -ENOMEM; |
444 | goto done; | 452 | goto done; |
445 | } | 453 | } |
@@ -611,7 +619,8 @@ int hci_dev_close(__u16 dev) | |||
611 | struct hci_dev *hdev; | 619 | struct hci_dev *hdev; |
612 | int err; | 620 | int err; |
613 | 621 | ||
614 | if (!(hdev = hci_dev_get(dev))) | 622 | hdev = hci_dev_get(dev); |
623 | if (!hdev) | ||
615 | return -ENODEV; | 624 | return -ENODEV; |
616 | err = hci_dev_do_close(hdev); | 625 | err = hci_dev_do_close(hdev); |
617 | hci_dev_put(hdev); | 626 | hci_dev_put(hdev); |
@@ -623,7 +632,8 @@ int hci_dev_reset(__u16 dev) | |||
623 | struct hci_dev *hdev; | 632 | struct hci_dev *hdev; |
624 | int ret = 0; | 633 | int ret = 0; |
625 | 634 | ||
626 | if (!(hdev = hci_dev_get(dev))) | 635 | hdev = hci_dev_get(dev); |
636 | if (!hdev) | ||
627 | return -ENODEV; | 637 | return -ENODEV; |
628 | 638 | ||
629 | hci_req_lock(hdev); | 639 | hci_req_lock(hdev); |
@@ -663,7 +673,8 @@ int hci_dev_reset_stat(__u16 dev) | |||
663 | struct hci_dev *hdev; | 673 | struct hci_dev *hdev; |
664 | int ret = 0; | 674 | int ret = 0; |
665 | 675 | ||
666 | if (!(hdev = hci_dev_get(dev))) | 676 | hdev = hci_dev_get(dev); |
677 | if (!hdev) | ||
667 | return -ENODEV; | 678 | return -ENODEV; |
668 | 679 | ||
669 | memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); | 680 | memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); |
@@ -682,7 +693,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) | |||
682 | if (copy_from_user(&dr, arg, sizeof(dr))) | 693 | if (copy_from_user(&dr, arg, sizeof(dr))) |
683 | return -EFAULT; | 694 | return -EFAULT; |
684 | 695 | ||
685 | if (!(hdev = hci_dev_get(dr.dev_id))) | 696 | hdev = hci_dev_get(dr.dev_id); |
697 | if (!hdev) | ||
686 | return -ENODEV; | 698 | return -ENODEV; |
687 | 699 | ||
688 | switch (cmd) { | 700 | switch (cmd) { |
@@ -763,7 +775,8 @@ int hci_get_dev_list(void __user *arg) | |||
763 | 775 | ||
764 | size = sizeof(*dl) + dev_num * sizeof(*dr); | 776 | size = sizeof(*dl) + dev_num * sizeof(*dr); |
765 | 777 | ||
766 | if (!(dl = kzalloc(size, GFP_KERNEL))) | 778 | dl = kzalloc(size, GFP_KERNEL); |
779 | if (!dl) | ||
767 | return -ENOMEM; | 780 | return -ENOMEM; |
768 | 781 | ||
769 | dr = dl->dev_req; | 782 | dr = dl->dev_req; |
@@ -797,7 +810,8 @@ int hci_get_dev_info(void __user *arg) | |||
797 | if (copy_from_user(&di, arg, sizeof(di))) | 810 | if (copy_from_user(&di, arg, sizeof(di))) |
798 | return -EFAULT; | 811 | return -EFAULT; |
799 | 812 | ||
800 | if (!(hdev = hci_dev_get(di.dev_id))) | 813 | hdev = hci_dev_get(di.dev_id); |
814 | if (!hdev) | ||
801 | return -ENODEV; | 815 | return -ENODEV; |
802 | 816 | ||
803 | strcpy(di.name, hdev->name); | 817 | strcpy(di.name, hdev->name); |
@@ -905,7 +919,7 @@ int hci_register_dev(struct hci_dev *hdev) | |||
905 | hdev->sniff_max_interval = 800; | 919 | hdev->sniff_max_interval = 800; |
906 | hdev->sniff_min_interval = 80; | 920 | hdev->sniff_min_interval = 80; |
907 | 921 | ||
908 | tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); | 922 | tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); |
909 | tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); | 923 | tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); |
910 | tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); | 924 | tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); |
911 | 925 | ||
@@ -1368,7 +1382,8 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) | |||
1368 | bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; | 1382 | bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; |
1369 | hci_add_acl_hdr(skb, conn->handle, flags | ACL_START); | 1383 | hci_add_acl_hdr(skb, conn->handle, flags | ACL_START); |
1370 | 1384 | ||
1371 | if (!(list = skb_shinfo(skb)->frag_list)) { | 1385 | list = skb_shinfo(skb)->frag_list; |
1386 | if (!list) { | ||
1372 | /* Non fragmented */ | 1387 | /* Non fragmented */ |
1373 | BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); | 1388 | BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); |
1374 | 1389 | ||
@@ -1609,7 +1624,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
1609 | hci_conn_enter_active_mode(conn); | 1624 | hci_conn_enter_active_mode(conn); |
1610 | 1625 | ||
1611 | /* Send to upper protocol */ | 1626 | /* Send to upper protocol */ |
1612 | if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { | 1627 | hp = hci_proto[HCI_PROTO_L2CAP]; |
1628 | if (hp && hp->recv_acldata) { | ||
1613 | hp->recv_acldata(conn, skb, flags); | 1629 | hp->recv_acldata(conn, skb, flags); |
1614 | return; | 1630 | return; |
1615 | } | 1631 | } |
@@ -1644,7 +1660,8 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
1644 | register struct hci_proto *hp; | 1660 | register struct hci_proto *hp; |
1645 | 1661 | ||
1646 | /* Send to upper protocol */ | 1662 | /* Send to upper protocol */ |
1647 | if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) { | 1663 | hp = hci_proto[HCI_PROTO_SCO]; |
1664 | if (hp && hp->recv_scodata) { | ||
1648 | hp->recv_scodata(conn, skb); | 1665 | hp->recv_scodata(conn, skb); |
1649 | return; | 1666 | return; |
1650 | } | 1667 | } |
@@ -1727,7 +1744,8 @@ static void hci_cmd_task(unsigned long arg) | |||
1727 | if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) { | 1744 | if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) { |
1728 | kfree_skb(hdev->sent_cmd); | 1745 | kfree_skb(hdev->sent_cmd); |
1729 | 1746 | ||
1730 | if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) { | 1747 | hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC); |
1748 | if (hdev->sent_cmd) { | ||
1731 | atomic_dec(&hdev->cmd_cnt); | 1749 | atomic_dec(&hdev->cmd_cnt); |
1732 | hci_send_frame(skb); | 1750 | hci_send_frame(skb); |
1733 | hdev->cmd_last_tx = jiffies; | 1751 | hdev->cmd_last_tx = jiffies; |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 84093b0000b9..8923b36a67a2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <net/sock.h> | 39 | #include <net/sock.h> |
40 | 40 | ||
41 | #include <asm/system.h> | 41 | #include <asm/system.h> |
42 | #include <asm/uaccess.h> | 42 | #include <linux/uaccess.h> |
43 | #include <asm/unaligned.h> | 43 | #include <asm/unaligned.h> |
44 | 44 | ||
45 | #include <net/bluetooth/bluetooth.h> | 45 | #include <net/bluetooth/bluetooth.h> |
@@ -677,9 +677,50 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) | |||
677 | hci_dev_unlock(hdev); | 677 | hci_dev_unlock(hdev); |
678 | } | 678 | } |
679 | 679 | ||
680 | static int hci_outgoing_auth_needed(struct hci_dev *hdev, | ||
681 | struct hci_conn *conn) | ||
682 | { | ||
683 | if (conn->state != BT_CONFIG || !conn->out) | ||
684 | return 0; | ||
685 | |||
686 | if (conn->sec_level == BT_SECURITY_SDP) | ||
687 | return 0; | ||
688 | |||
689 | /* Only request authentication for SSP connections or non-SSP | ||
690 | * devices with sec_level HIGH */ | ||
691 | if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) && | ||
692 | conn->sec_level != BT_SECURITY_HIGH) | ||
693 | return 0; | ||
694 | |||
695 | return 1; | ||
696 | } | ||
697 | |||
680 | static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) | 698 | static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) |
681 | { | 699 | { |
700 | struct hci_cp_remote_name_req *cp; | ||
701 | struct hci_conn *conn; | ||
702 | |||
682 | BT_DBG("%s status 0x%x", hdev->name, status); | 703 | BT_DBG("%s status 0x%x", hdev->name, status); |
704 | |||
705 | /* If successful wait for the name req complete event before | ||
706 | * checking for the need to do authentication */ | ||
707 | if (!status) | ||
708 | return; | ||
709 | |||
710 | cp = hci_sent_cmd_data(hdev, HCI_OP_REMOTE_NAME_REQ); | ||
711 | if (!cp) | ||
712 | return; | ||
713 | |||
714 | hci_dev_lock(hdev); | ||
715 | |||
716 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); | ||
717 | if (conn && hci_outgoing_auth_needed(hdev, conn)) { | ||
718 | struct hci_cp_auth_requested cp; | ||
719 | cp.handle = __cpu_to_le16(conn->handle); | ||
720 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); | ||
721 | } | ||
722 | |||
723 | hci_dev_unlock(hdev); | ||
683 | } | 724 | } |
684 | 725 | ||
685 | static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status) | 726 | static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status) |
@@ -955,12 +996,14 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
955 | 996 | ||
956 | hci_dev_lock(hdev); | 997 | hci_dev_lock(hdev); |
957 | 998 | ||
958 | if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) | 999 | ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); |
1000 | if (ie) | ||
959 | memcpy(ie->data.dev_class, ev->dev_class, 3); | 1001 | memcpy(ie->data.dev_class, ev->dev_class, 3); |
960 | 1002 | ||
961 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); | 1003 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); |
962 | if (!conn) { | 1004 | if (!conn) { |
963 | if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) { | 1005 | conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); |
1006 | if (!conn) { | ||
964 | BT_ERR("No memory for new connection"); | 1007 | BT_ERR("No memory for new connection"); |
965 | hci_dev_unlock(hdev); | 1008 | hci_dev_unlock(hdev); |
966 | return; | 1009 | return; |
@@ -1090,9 +1133,23 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
1090 | 1133 | ||
1091 | static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1134 | static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb) |
1092 | { | 1135 | { |
1136 | struct hci_ev_remote_name *ev = (void *) skb->data; | ||
1137 | struct hci_conn *conn; | ||
1138 | |||
1093 | BT_DBG("%s", hdev->name); | 1139 | BT_DBG("%s", hdev->name); |
1094 | 1140 | ||
1095 | hci_conn_check_pending(hdev); | 1141 | hci_conn_check_pending(hdev); |
1142 | |||
1143 | hci_dev_lock(hdev); | ||
1144 | |||
1145 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); | ||
1146 | if (conn && hci_outgoing_auth_needed(hdev, conn)) { | ||
1147 | struct hci_cp_auth_requested cp; | ||
1148 | cp.handle = __cpu_to_le16(conn->handle); | ||
1149 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); | ||
1150 | } | ||
1151 | |||
1152 | hci_dev_unlock(hdev); | ||
1096 | } | 1153 | } |
1097 | 1154 | ||
1098 | static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1155 | static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -1162,33 +1219,39 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff | |||
1162 | hci_dev_lock(hdev); | 1219 | hci_dev_lock(hdev); |
1163 | 1220 | ||
1164 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | 1221 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
1165 | if (conn) { | 1222 | if (!conn) |
1166 | if (!ev->status) | 1223 | goto unlock; |
1167 | memcpy(conn->features, ev->features, 8); | ||
1168 | 1224 | ||
1169 | if (conn->state == BT_CONFIG) { | 1225 | if (!ev->status) |
1170 | if (!ev->status && lmp_ssp_capable(hdev) && | 1226 | memcpy(conn->features, ev->features, 8); |
1171 | lmp_ssp_capable(conn)) { | 1227 | |
1172 | struct hci_cp_read_remote_ext_features cp; | 1228 | if (conn->state != BT_CONFIG) |
1173 | cp.handle = ev->handle; | 1229 | goto unlock; |
1174 | cp.page = 0x01; | 1230 | |
1175 | hci_send_cmd(hdev, | 1231 | if (!ev->status && lmp_ssp_capable(hdev) && lmp_ssp_capable(conn)) { |
1176 | HCI_OP_READ_REMOTE_EXT_FEATURES, | 1232 | struct hci_cp_read_remote_ext_features cp; |
1177 | sizeof(cp), &cp); | 1233 | cp.handle = ev->handle; |
1178 | } else if (!ev->status && conn->out && | 1234 | cp.page = 0x01; |
1179 | conn->sec_level == BT_SECURITY_HIGH) { | 1235 | hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES, |
1180 | struct hci_cp_auth_requested cp; | ||
1181 | cp.handle = ev->handle; | ||
1182 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, | ||
1183 | sizeof(cp), &cp); | 1236 | sizeof(cp), &cp); |
1184 | } else { | 1237 | goto unlock; |
1185 | conn->state = BT_CONNECTED; | 1238 | } |
1186 | hci_proto_connect_cfm(conn, ev->status); | 1239 | |
1187 | hci_conn_put(conn); | 1240 | if (!ev->status) { |
1188 | } | 1241 | struct hci_cp_remote_name_req cp; |
1189 | } | 1242 | memset(&cp, 0, sizeof(cp)); |
1243 | bacpy(&cp.bdaddr, &conn->dst); | ||
1244 | cp.pscan_rep_mode = 0x02; | ||
1245 | hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); | ||
1190 | } | 1246 | } |
1191 | 1247 | ||
1248 | if (!hci_outgoing_auth_needed(hdev, conn)) { | ||
1249 | conn->state = BT_CONNECTED; | ||
1250 | hci_proto_connect_cfm(conn, ev->status); | ||
1251 | hci_conn_put(conn); | ||
1252 | } | ||
1253 | |||
1254 | unlock: | ||
1192 | hci_dev_unlock(hdev); | 1255 | hci_dev_unlock(hdev); |
1193 | } | 1256 | } |
1194 | 1257 | ||
@@ -1449,10 +1512,12 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s | |||
1449 | conn->sent -= count; | 1512 | conn->sent -= count; |
1450 | 1513 | ||
1451 | if (conn->type == ACL_LINK) { | 1514 | if (conn->type == ACL_LINK) { |
1452 | if ((hdev->acl_cnt += count) > hdev->acl_pkts) | 1515 | hdev->acl_cnt += count; |
1516 | if (hdev->acl_cnt > hdev->acl_pkts) | ||
1453 | hdev->acl_cnt = hdev->acl_pkts; | 1517 | hdev->acl_cnt = hdev->acl_pkts; |
1454 | } else { | 1518 | } else { |
1455 | if ((hdev->sco_cnt += count) > hdev->sco_pkts) | 1519 | hdev->sco_cnt += count; |
1520 | if (hdev->sco_cnt > hdev->sco_pkts) | ||
1456 | hdev->sco_cnt = hdev->sco_pkts; | 1521 | hdev->sco_cnt = hdev->sco_pkts; |
1457 | } | 1522 | } |
1458 | } | 1523 | } |
@@ -1547,7 +1612,8 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1547 | if (conn && !ev->status) { | 1612 | if (conn && !ev->status) { |
1548 | struct inquiry_entry *ie; | 1613 | struct inquiry_entry *ie; |
1549 | 1614 | ||
1550 | if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { | 1615 | ie = hci_inquiry_cache_lookup(hdev, &conn->dst); |
1616 | if (ie) { | ||
1551 | ie->data.clock_offset = ev->clock_offset; | 1617 | ie->data.clock_offset = ev->clock_offset; |
1552 | ie->timestamp = jiffies; | 1618 | ie->timestamp = jiffies; |
1553 | } | 1619 | } |
@@ -1581,7 +1647,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff * | |||
1581 | 1647 | ||
1582 | hci_dev_lock(hdev); | 1648 | hci_dev_lock(hdev); |
1583 | 1649 | ||
1584 | if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) { | 1650 | ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); |
1651 | if (ie) { | ||
1585 | ie->data.pscan_rep_mode = ev->pscan_rep_mode; | 1652 | ie->data.pscan_rep_mode = ev->pscan_rep_mode; |
1586 | ie->timestamp = jiffies; | 1653 | ie->timestamp = jiffies; |
1587 | } | 1654 | } |
@@ -1646,32 +1713,37 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b | |||
1646 | hci_dev_lock(hdev); | 1713 | hci_dev_lock(hdev); |
1647 | 1714 | ||
1648 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | 1715 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
1649 | if (conn) { | 1716 | if (!conn) |
1650 | if (!ev->status && ev->page == 0x01) { | 1717 | goto unlock; |
1651 | struct inquiry_entry *ie; | ||
1652 | 1718 | ||
1653 | if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) | 1719 | if (!ev->status && ev->page == 0x01) { |
1654 | ie->data.ssp_mode = (ev->features[0] & 0x01); | 1720 | struct inquiry_entry *ie; |
1655 | 1721 | ||
1656 | conn->ssp_mode = (ev->features[0] & 0x01); | 1722 | ie = hci_inquiry_cache_lookup(hdev, &conn->dst); |
1657 | } | 1723 | if (ie) |
1724 | ie->data.ssp_mode = (ev->features[0] & 0x01); | ||
1658 | 1725 | ||
1659 | if (conn->state == BT_CONFIG) { | 1726 | conn->ssp_mode = (ev->features[0] & 0x01); |
1660 | if (!ev->status && hdev->ssp_mode > 0 && | ||
1661 | conn->ssp_mode > 0 && conn->out && | ||
1662 | conn->sec_level != BT_SECURITY_SDP) { | ||
1663 | struct hci_cp_auth_requested cp; | ||
1664 | cp.handle = ev->handle; | ||
1665 | hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, | ||
1666 | sizeof(cp), &cp); | ||
1667 | } else { | ||
1668 | conn->state = BT_CONNECTED; | ||
1669 | hci_proto_connect_cfm(conn, ev->status); | ||
1670 | hci_conn_put(conn); | ||
1671 | } | ||
1672 | } | ||
1673 | } | 1727 | } |
1674 | 1728 | ||
1729 | if (conn->state != BT_CONFIG) | ||
1730 | goto unlock; | ||
1731 | |||
1732 | if (!ev->status) { | ||
1733 | struct hci_cp_remote_name_req cp; | ||
1734 | memset(&cp, 0, sizeof(cp)); | ||
1735 | bacpy(&cp.bdaddr, &conn->dst); | ||
1736 | cp.pscan_rep_mode = 0x02; | ||
1737 | hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); | ||
1738 | } | ||
1739 | |||
1740 | if (!hci_outgoing_auth_needed(hdev, conn)) { | ||
1741 | conn->state = BT_CONNECTED; | ||
1742 | hci_proto_connect_cfm(conn, ev->status); | ||
1743 | hci_conn_put(conn); | ||
1744 | } | ||
1745 | |||
1746 | unlock: | ||
1675 | hci_dev_unlock(hdev); | 1747 | hci_dev_unlock(hdev); |
1676 | } | 1748 | } |
1677 | 1749 | ||
@@ -1821,7 +1893,8 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ | |||
1821 | 1893 | ||
1822 | hci_dev_lock(hdev); | 1894 | hci_dev_lock(hdev); |
1823 | 1895 | ||
1824 | if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) | 1896 | ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr); |
1897 | if (ie) | ||
1825 | ie->data.ssp_mode = (ev->features[0] & 0x01); | 1898 | ie->data.ssp_mode = (ev->features[0] & 0x01); |
1826 | 1899 | ||
1827 | hci_dev_unlock(hdev); | 1900 | hci_dev_unlock(hdev); |
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 83acd164d39e..b3753bad2a55 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #include <net/sock.h> | 43 | #include <net/sock.h> |
44 | 44 | ||
45 | #include <asm/system.h> | 45 | #include <asm/system.h> |
46 | #include <asm/uaccess.h> | 46 | #include <linux/uaccess.h> |
47 | #include <asm/unaligned.h> | 47 | #include <asm/unaligned.h> |
48 | 48 | ||
49 | #include <net/bluetooth/bluetooth.h> | 49 | #include <net/bluetooth/bluetooth.h> |
@@ -125,7 +125,8 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | |||
125 | continue; | 125 | continue; |
126 | } | 126 | } |
127 | 127 | ||
128 | if (!(nskb = skb_clone(skb, GFP_ATOMIC))) | 128 | nskb = skb_clone(skb, GFP_ATOMIC); |
129 | if (!nskb) | ||
129 | continue; | 130 | continue; |
130 | 131 | ||
131 | /* Put type byte before the data */ | 132 | /* Put type byte before the data */ |
@@ -370,7 +371,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le | |||
370 | } | 371 | } |
371 | 372 | ||
372 | if (haddr->hci_dev != HCI_DEV_NONE) { | 373 | if (haddr->hci_dev != HCI_DEV_NONE) { |
373 | if (!(hdev = hci_dev_get(haddr->hci_dev))) { | 374 | hdev = hci_dev_get(haddr->hci_dev); |
375 | if (!hdev) { | ||
374 | err = -ENODEV; | 376 | err = -ENODEV; |
375 | goto done; | 377 | goto done; |
376 | } | 378 | } |
@@ -457,7 +459,8 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
457 | if (sk->sk_state == BT_CLOSED) | 459 | if (sk->sk_state == BT_CLOSED) |
458 | return 0; | 460 | return 0; |
459 | 461 | ||
460 | if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) | 462 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
463 | if (!skb) | ||
461 | return err; | 464 | return err; |
462 | 465 | ||
463 | msg->msg_namelen = 0; | 466 | msg->msg_namelen = 0; |
@@ -499,7 +502,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
499 | 502 | ||
500 | lock_sock(sk); | 503 | lock_sock(sk); |
501 | 504 | ||
502 | if (!(hdev = hci_pi(sk)->hdev)) { | 505 | hdev = hci_pi(sk)->hdev; |
506 | if (!hdev) { | ||
503 | err = -EBADFD; | 507 | err = -EBADFD; |
504 | goto done; | 508 | goto done; |
505 | } | 509 | } |
@@ -509,7 +513,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
509 | goto done; | 513 | goto done; |
510 | } | 514 | } |
511 | 515 | ||
512 | if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) | 516 | skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); |
517 | if (!skb) | ||
513 | goto done; | 518 | goto done; |
514 | 519 | ||
515 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 520 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index c0ee8b3928ed..29544c21f4b5 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -107,6 +107,7 @@ static void __hidp_unlink_session(struct hidp_session *session) | |||
107 | 107 | ||
108 | static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci) | 108 | static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci) |
109 | { | 109 | { |
110 | memset(ci, 0, sizeof(*ci)); | ||
110 | bacpy(&ci->bdaddr, &session->bdaddr); | 111 | bacpy(&ci->bdaddr, &session->bdaddr); |
111 | 112 | ||
112 | ci->flags = session->flags; | 113 | ci->flags = session->flags; |
@@ -115,7 +116,6 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin | |||
115 | ci->vendor = 0x0000; | 116 | ci->vendor = 0x0000; |
116 | ci->product = 0x0000; | 117 | ci->product = 0x0000; |
117 | ci->version = 0x0000; | 118 | ci->version = 0x0000; |
118 | memset(ci->name, 0, 128); | ||
119 | 119 | ||
120 | if (session->input) { | 120 | if (session->input) { |
121 | ci->vendor = session->input->id.vendor; | 121 | ci->vendor = session->input->id.vendor; |
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cd8f6ea03841..c12eccfdfe01 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -57,7 +57,7 @@ | |||
57 | 57 | ||
58 | #define VERSION "2.15" | 58 | #define VERSION "2.15" |
59 | 59 | ||
60 | static int disable_ertm = 0; | 60 | static int disable_ertm; |
61 | 61 | ||
62 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; | 62 | static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; |
63 | static u8 l2cap_fixed_chan[8] = { 0x02, }; | 63 | static u8 l2cap_fixed_chan[8] = { 0x02, }; |
@@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, | |||
83 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); | 83 | static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); |
84 | 84 | ||
85 | /* ---- L2CAP timers ---- */ | 85 | /* ---- L2CAP timers ---- */ |
86 | static void l2cap_sock_set_timer(struct sock *sk, long timeout) | ||
87 | { | ||
88 | BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); | ||
89 | sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); | ||
90 | } | ||
91 | |||
92 | static void l2cap_sock_clear_timer(struct sock *sk) | ||
93 | { | ||
94 | BT_DBG("sock %p state %d", sk, sk->sk_state); | ||
95 | sk_stop_timer(sk, &sk->sk_timer); | ||
96 | } | ||
97 | |||
86 | static void l2cap_sock_timeout(unsigned long arg) | 98 | static void l2cap_sock_timeout(unsigned long arg) |
87 | { | 99 | { |
88 | struct sock *sk = (struct sock *) arg; | 100 | struct sock *sk = (struct sock *) arg; |
@@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg) | |||
92 | 104 | ||
93 | bh_lock_sock(sk); | 105 | bh_lock_sock(sk); |
94 | 106 | ||
107 | if (sock_owned_by_user(sk)) { | ||
108 | /* sk is owned by user. Try again later */ | ||
109 | l2cap_sock_set_timer(sk, HZ / 5); | ||
110 | bh_unlock_sock(sk); | ||
111 | sock_put(sk); | ||
112 | return; | ||
113 | } | ||
114 | |||
95 | if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) | 115 | if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) |
96 | reason = ECONNREFUSED; | 116 | reason = ECONNREFUSED; |
97 | else if (sk->sk_state == BT_CONNECT && | 117 | else if (sk->sk_state == BT_CONNECT && |
@@ -108,18 +128,6 @@ static void l2cap_sock_timeout(unsigned long arg) | |||
108 | sock_put(sk); | 128 | sock_put(sk); |
109 | } | 129 | } |
110 | 130 | ||
111 | static void l2cap_sock_set_timer(struct sock *sk, long timeout) | ||
112 | { | ||
113 | BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); | ||
114 | sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout); | ||
115 | } | ||
116 | |||
117 | static void l2cap_sock_clear_timer(struct sock *sk) | ||
118 | { | ||
119 | BT_DBG("sock %p state %d", sk, sk->sk_state); | ||
120 | sk_stop_timer(sk, &sk->sk_timer); | ||
121 | } | ||
122 | |||
123 | /* ---- L2CAP channels ---- */ | 131 | /* ---- L2CAP channels ---- */ |
124 | static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) | 132 | static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) |
125 | { | 133 | { |
@@ -743,11 +751,13 @@ found: | |||
743 | /* Find socket with psm and source bdaddr. | 751 | /* Find socket with psm and source bdaddr. |
744 | * Returns closest match. | 752 | * Returns closest match. |
745 | */ | 753 | */ |
746 | static struct sock *__l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) | 754 | static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) |
747 | { | 755 | { |
748 | struct sock *sk = NULL, *sk1 = NULL; | 756 | struct sock *sk = NULL, *sk1 = NULL; |
749 | struct hlist_node *node; | 757 | struct hlist_node *node; |
750 | 758 | ||
759 | read_lock(&l2cap_sk_list.lock); | ||
760 | |||
751 | sk_for_each(sk, node, &l2cap_sk_list.head) { | 761 | sk_for_each(sk, node, &l2cap_sk_list.head) { |
752 | if (state && sk->sk_state != state) | 762 | if (state && sk->sk_state != state) |
753 | continue; | 763 | continue; |
@@ -762,20 +772,10 @@ static struct sock *__l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src | |||
762 | sk1 = sk; | 772 | sk1 = sk; |
763 | } | 773 | } |
764 | } | 774 | } |
765 | return node ? sk : sk1; | ||
766 | } | ||
767 | 775 | ||
768 | /* Find socket with given address (psm, src). | ||
769 | * Returns locked socket */ | ||
770 | static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) | ||
771 | { | ||
772 | struct sock *s; | ||
773 | read_lock(&l2cap_sk_list.lock); | ||
774 | s = __l2cap_get_sock_by_psm(state, psm, src); | ||
775 | if (s) | ||
776 | bh_lock_sock(s); | ||
777 | read_unlock(&l2cap_sk_list.lock); | 776 | read_unlock(&l2cap_sk_list.lock); |
778 | return s; | 777 | |
778 | return node ? sk : sk1; | ||
779 | } | 779 | } |
780 | 780 | ||
781 | static void l2cap_sock_destruct(struct sock *sk) | 781 | static void l2cap_sock_destruct(struct sock *sk) |
@@ -2926,6 +2926,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
2926 | goto sendresp; | 2926 | goto sendresp; |
2927 | } | 2927 | } |
2928 | 2928 | ||
2929 | bh_lock_sock(parent); | ||
2930 | |||
2929 | /* Check if the ACL is secure enough (if not SDP) */ | 2931 | /* Check if the ACL is secure enough (if not SDP) */ |
2930 | if (psm != cpu_to_le16(0x0001) && | 2932 | if (psm != cpu_to_le16(0x0001) && |
2931 | !hci_conn_check_link_mode(conn->hcon)) { | 2933 | !hci_conn_check_link_mode(conn->hcon)) { |
@@ -3078,6 +3080,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
3078 | break; | 3080 | break; |
3079 | 3081 | ||
3080 | default: | 3082 | default: |
3083 | /* don't delete l2cap channel if sk is owned by user */ | ||
3084 | if (sock_owned_by_user(sk)) { | ||
3085 | sk->sk_state = BT_DISCONN; | ||
3086 | l2cap_sock_clear_timer(sk); | ||
3087 | l2cap_sock_set_timer(sk, HZ / 5); | ||
3088 | break; | ||
3089 | } | ||
3090 | |||
3081 | l2cap_chan_del(sk, ECONNREFUSED); | 3091 | l2cap_chan_del(sk, ECONNREFUSED); |
3082 | break; | 3092 | break; |
3083 | } | 3093 | } |
@@ -3283,6 +3293,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd | |||
3283 | 3293 | ||
3284 | sk->sk_shutdown = SHUTDOWN_MASK; | 3294 | sk->sk_shutdown = SHUTDOWN_MASK; |
3285 | 3295 | ||
3296 | /* don't delete l2cap channel if sk is owned by user */ | ||
3297 | if (sock_owned_by_user(sk)) { | ||
3298 | sk->sk_state = BT_DISCONN; | ||
3299 | l2cap_sock_clear_timer(sk); | ||
3300 | l2cap_sock_set_timer(sk, HZ / 5); | ||
3301 | bh_unlock_sock(sk); | ||
3302 | return 0; | ||
3303 | } | ||
3304 | |||
3286 | l2cap_chan_del(sk, ECONNRESET); | 3305 | l2cap_chan_del(sk, ECONNRESET); |
3287 | bh_unlock_sock(sk); | 3306 | bh_unlock_sock(sk); |
3288 | 3307 | ||
@@ -3305,6 +3324,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd | |||
3305 | if (!sk) | 3324 | if (!sk) |
3306 | return 0; | 3325 | return 0; |
3307 | 3326 | ||
3327 | /* don't delete l2cap channel if sk is owned by user */ | ||
3328 | if (sock_owned_by_user(sk)) { | ||
3329 | sk->sk_state = BT_DISCONN; | ||
3330 | l2cap_sock_clear_timer(sk); | ||
3331 | l2cap_sock_set_timer(sk, HZ / 5); | ||
3332 | bh_unlock_sock(sk); | ||
3333 | return 0; | ||
3334 | } | ||
3335 | |||
3308 | l2cap_chan_del(sk, 0); | 3336 | l2cap_chan_del(sk, 0); |
3309 | bh_unlock_sock(sk); | 3337 | bh_unlock_sock(sk); |
3310 | 3338 | ||
@@ -4134,11 +4162,10 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) | |||
4134 | __mod_retrans_timer(); | 4162 | __mod_retrans_timer(); |
4135 | 4163 | ||
4136 | pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; | 4164 | pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; |
4137 | if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { | 4165 | if (pi->conn_state & L2CAP_CONN_SREJ_SENT) |
4138 | l2cap_send_ack(pi); | 4166 | l2cap_send_ack(pi); |
4139 | } else { | 4167 | else |
4140 | l2cap_ertm_send(sk); | 4168 | l2cap_ertm_send(sk); |
4141 | } | ||
4142 | } | 4169 | } |
4143 | } | 4170 | } |
4144 | 4171 | ||
@@ -4430,6 +4457,8 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str | |||
4430 | if (!sk) | 4457 | if (!sk) |
4431 | goto drop; | 4458 | goto drop; |
4432 | 4459 | ||
4460 | bh_lock_sock(sk); | ||
4461 | |||
4433 | BT_DBG("sk %p, len %d", sk, skb->len); | 4462 | BT_DBG("sk %p, len %d", sk, skb->len); |
4434 | 4463 | ||
4435 | if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) | 4464 | if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) |
@@ -4841,8 +4870,10 @@ static int __init l2cap_init(void) | |||
4841 | return err; | 4870 | return err; |
4842 | 4871 | ||
4843 | _busy_wq = create_singlethread_workqueue("l2cap"); | 4872 | _busy_wq = create_singlethread_workqueue("l2cap"); |
4844 | if (!_busy_wq) | 4873 | if (!_busy_wq) { |
4845 | goto error; | 4874 | proto_unregister(&l2cap_proto); |
4875 | return -ENOMEM; | ||
4876 | } | ||
4846 | 4877 | ||
4847 | err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); | 4878 | err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); |
4848 | if (err < 0) { | 4879 | if (err < 0) { |
@@ -4870,6 +4901,7 @@ static int __init l2cap_init(void) | |||
4870 | return 0; | 4901 | return 0; |
4871 | 4902 | ||
4872 | error: | 4903 | error: |
4904 | destroy_workqueue(_busy_wq); | ||
4873 | proto_unregister(&l2cap_proto); | 4905 | proto_unregister(&l2cap_proto); |
4874 | return err; | 4906 | return err; |
4875 | } | 4907 | } |
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 432a9a633e8d..ff8aaa736650 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | 42 | ||
43 | #include <net/sock.h> | 43 | #include <net/sock.h> |
44 | #include <asm/uaccess.h> | 44 | #include <linux/uaccess.h> |
45 | #include <asm/unaligned.h> | 45 | #include <asm/unaligned.h> |
46 | 46 | ||
47 | #include <net/bluetooth/bluetooth.h> | 47 | #include <net/bluetooth/bluetooth.h> |
@@ -51,10 +51,10 @@ | |||
51 | 51 | ||
52 | #define VERSION "1.11" | 52 | #define VERSION "1.11" |
53 | 53 | ||
54 | static int disable_cfc = 0; | 54 | static int disable_cfc; |
55 | static int l2cap_ertm; | ||
55 | static int channel_mtu = -1; | 56 | static int channel_mtu = -1; |
56 | static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; | 57 | static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; |
57 | static int l2cap_ertm = 0; | ||
58 | 58 | ||
59 | static struct task_struct *rfcomm_thread; | 59 | static struct task_struct *rfcomm_thread; |
60 | 60 | ||
@@ -1902,7 +1902,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s) | |||
1902 | 1902 | ||
1903 | BT_DBG("%p state %ld", s, s->state); | 1903 | BT_DBG("%p state %ld", s, s->state); |
1904 | 1904 | ||
1905 | switch(sk->sk_state) { | 1905 | switch (sk->sk_state) { |
1906 | case BT_CONNECTED: | 1906 | case BT_CONNECTED: |
1907 | s->state = BT_CONNECT; | 1907 | s->state = BT_CONNECT; |
1908 | 1908 | ||
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index aec505f934df..66cc1f0c3df8 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c | |||
@@ -45,7 +45,7 @@ | |||
45 | #include <net/sock.h> | 45 | #include <net/sock.h> |
46 | 46 | ||
47 | #include <asm/system.h> | 47 | #include <asm/system.h> |
48 | #include <asm/uaccess.h> | 48 | #include <linux/uaccess.h> |
49 | 49 | ||
50 | #include <net/bluetooth/bluetooth.h> | 50 | #include <net/bluetooth/bluetooth.h> |
51 | #include <net/bluetooth/hci_core.h> | 51 | #include <net/bluetooth/hci_core.h> |
@@ -140,11 +140,13 @@ static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src) | |||
140 | /* Find socket with channel and source bdaddr. | 140 | /* Find socket with channel and source bdaddr. |
141 | * Returns closest match. | 141 | * Returns closest match. |
142 | */ | 142 | */ |
143 | static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) | 143 | static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) |
144 | { | 144 | { |
145 | struct sock *sk = NULL, *sk1 = NULL; | 145 | struct sock *sk = NULL, *sk1 = NULL; |
146 | struct hlist_node *node; | 146 | struct hlist_node *node; |
147 | 147 | ||
148 | read_lock(&rfcomm_sk_list.lock); | ||
149 | |||
148 | sk_for_each(sk, node, &rfcomm_sk_list.head) { | 150 | sk_for_each(sk, node, &rfcomm_sk_list.head) { |
149 | if (state && sk->sk_state != state) | 151 | if (state && sk->sk_state != state) |
150 | continue; | 152 | continue; |
@@ -159,19 +161,10 @@ static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t | |||
159 | sk1 = sk; | 161 | sk1 = sk; |
160 | } | 162 | } |
161 | } | 163 | } |
162 | return node ? sk : sk1; | ||
163 | } | ||
164 | 164 | ||
165 | /* Find socket with given address (channel, src). | ||
166 | * Returns locked socket */ | ||
167 | static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) | ||
168 | { | ||
169 | struct sock *s; | ||
170 | read_lock(&rfcomm_sk_list.lock); | ||
171 | s = __rfcomm_get_sock_by_channel(state, channel, src); | ||
172 | if (s) bh_lock_sock(s); | ||
173 | read_unlock(&rfcomm_sk_list.lock); | 165 | read_unlock(&rfcomm_sk_list.lock); |
174 | return s; | 166 | |
167 | return node ? sk : sk1; | ||
175 | } | 168 | } |
176 | 169 | ||
177 | static void rfcomm_sock_destruct(struct sock *sk) | 170 | static void rfcomm_sock_destruct(struct sock *sk) |
@@ -895,7 +888,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) | |||
895 | 888 | ||
896 | BT_DBG("sock %p, sk %p", sock, sk); | 889 | BT_DBG("sock %p, sk %p", sock, sk); |
897 | 890 | ||
898 | if (!sk) return 0; | 891 | if (!sk) |
892 | return 0; | ||
899 | 893 | ||
900 | lock_sock(sk); | 894 | lock_sock(sk); |
901 | if (!sk->sk_shutdown) { | 895 | if (!sk->sk_shutdown) { |
@@ -945,6 +939,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * | |||
945 | if (!parent) | 939 | if (!parent) |
946 | return 0; | 940 | return 0; |
947 | 941 | ||
942 | bh_lock_sock(parent); | ||
943 | |||
948 | /* Check for backlog size */ | 944 | /* Check for backlog size */ |
949 | if (sk_acceptq_is_full(parent)) { | 945 | if (sk_acceptq_is_full(parent)) { |
950 | BT_DBG("backlog full %d", parent->sk_ack_backlog); | 946 | BT_DBG("backlog full %d", parent->sk_ack_backlog); |
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a9b81f5dacd1..2575c2db6404 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
@@ -58,9 +58,9 @@ struct rfcomm_dev { | |||
58 | 58 | ||
59 | bdaddr_t src; | 59 | bdaddr_t src; |
60 | bdaddr_t dst; | 60 | bdaddr_t dst; |
61 | u8 channel; | 61 | u8 channel; |
62 | 62 | ||
63 | uint modem_status; | 63 | uint modem_status; |
64 | 64 | ||
65 | struct rfcomm_dlc *dlc; | 65 | struct rfcomm_dlc *dlc; |
66 | struct tty_struct *tty; | 66 | struct tty_struct *tty; |
@@ -69,7 +69,7 @@ struct rfcomm_dev { | |||
69 | 69 | ||
70 | struct device *tty_dev; | 70 | struct device *tty_dev; |
71 | 71 | ||
72 | atomic_t wmem_alloc; | 72 | atomic_t wmem_alloc; |
73 | 73 | ||
74 | struct sk_buff_head pending; | 74 | struct sk_buff_head pending; |
75 | }; | 75 | }; |
@@ -431,7 +431,8 @@ static int rfcomm_release_dev(void __user *arg) | |||
431 | 431 | ||
432 | BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags); | 432 | BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags); |
433 | 433 | ||
434 | if (!(dev = rfcomm_dev_get(req.dev_id))) | 434 | dev = rfcomm_dev_get(req.dev_id); |
435 | if (!dev) | ||
435 | return -ENODEV; | 436 | return -ENODEV; |
436 | 437 | ||
437 | if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) { | 438 | if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) { |
@@ -470,7 +471,8 @@ static int rfcomm_get_dev_list(void __user *arg) | |||
470 | 471 | ||
471 | size = sizeof(*dl) + dev_num * sizeof(*di); | 472 | size = sizeof(*dl) + dev_num * sizeof(*di); |
472 | 473 | ||
473 | if (!(dl = kmalloc(size, GFP_KERNEL))) | 474 | dl = kmalloc(size, GFP_KERNEL); |
475 | if (!dl) | ||
474 | return -ENOMEM; | 476 | return -ENOMEM; |
475 | 477 | ||
476 | di = dl->dev_info; | 478 | di = dl->dev_info; |
@@ -513,7 +515,8 @@ static int rfcomm_get_dev_info(void __user *arg) | |||
513 | if (copy_from_user(&di, arg, sizeof(di))) | 515 | if (copy_from_user(&di, arg, sizeof(di))) |
514 | return -EFAULT; | 516 | return -EFAULT; |
515 | 517 | ||
516 | if (!(dev = rfcomm_dev_get(di.id))) | 518 | dev = rfcomm_dev_get(di.id); |
519 | if (!dev) | ||
517 | return -ENODEV; | 520 | return -ENODEV; |
518 | 521 | ||
519 | di.flags = dev->flags; | 522 | di.flags = dev->flags; |
@@ -561,7 +564,8 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) | |||
561 | return; | 564 | return; |
562 | } | 565 | } |
563 | 566 | ||
564 | if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) { | 567 | tty = dev->tty; |
568 | if (!tty || !skb_queue_empty(&dev->pending)) { | ||
565 | skb_queue_tail(&dev->pending, skb); | 569 | skb_queue_tail(&dev->pending, skb); |
566 | return; | 570 | return; |
567 | } | 571 | } |
@@ -796,7 +800,8 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in | |||
796 | 800 | ||
797 | memcpy(skb_put(skb, size), buf + sent, size); | 801 | memcpy(skb_put(skb, size), buf + sent, size); |
798 | 802 | ||
799 | if ((err = rfcomm_dlc_send(dlc, skb)) < 0) { | 803 | err = rfcomm_dlc_send(dlc, skb); |
804 | if (err < 0) { | ||
800 | kfree_skb(skb); | 805 | kfree_skb(skb); |
801 | break; | 806 | break; |
802 | } | 807 | } |
@@ -892,7 +897,7 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | |||
892 | 897 | ||
893 | /* Parity on/off and when on, odd/even */ | 898 | /* Parity on/off and when on, odd/even */ |
894 | if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) || | 899 | if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) || |
895 | ((old->c_cflag & PARODD) != (new->c_cflag & PARODD)) ) { | 900 | ((old->c_cflag & PARODD) != (new->c_cflag & PARODD))) { |
896 | changes |= RFCOMM_RPN_PM_PARITY; | 901 | changes |= RFCOMM_RPN_PM_PARITY; |
897 | BT_DBG("Parity change detected."); | 902 | BT_DBG("Parity change detected."); |
898 | } | 903 | } |
@@ -937,11 +942,10 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | |||
937 | /* POSIX does not support 1.5 stop bits and RFCOMM does not | 942 | /* POSIX does not support 1.5 stop bits and RFCOMM does not |
938 | * support 2 stop bits. So a request for 2 stop bits gets | 943 | * support 2 stop bits. So a request for 2 stop bits gets |
939 | * translated to 1.5 stop bits */ | 944 | * translated to 1.5 stop bits */ |
940 | if (new->c_cflag & CSTOPB) { | 945 | if (new->c_cflag & CSTOPB) |
941 | stop_bits = RFCOMM_RPN_STOP_15; | 946 | stop_bits = RFCOMM_RPN_STOP_15; |
942 | } else { | 947 | else |
943 | stop_bits = RFCOMM_RPN_STOP_1; | 948 | stop_bits = RFCOMM_RPN_STOP_1; |
944 | } | ||
945 | 949 | ||
946 | /* Handle number of data bits [5-8] */ | 950 | /* Handle number of data bits [5-8] */ |
947 | if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE)) | 951 | if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE)) |
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 66b9e5c0523a..960c6d1637da 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <net/sock.h> | 44 | #include <net/sock.h> |
45 | 45 | ||
46 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | #include <asm/uaccess.h> | 47 | #include <linux/uaccess.h> |
48 | 48 | ||
49 | #include <net/bluetooth/bluetooth.h> | 49 | #include <net/bluetooth/bluetooth.h> |
50 | #include <net/bluetooth/hci_core.h> | 50 | #include <net/bluetooth/hci_core.h> |
@@ -52,7 +52,7 @@ | |||
52 | 52 | ||
53 | #define VERSION "0.6" | 53 | #define VERSION "0.6" |
54 | 54 | ||
55 | static int disable_esco = 0; | 55 | static int disable_esco; |
56 | 56 | ||
57 | static const struct proto_ops sco_sock_ops; | 57 | static const struct proto_ops sco_sock_ops; |
58 | 58 | ||
@@ -138,16 +138,17 @@ static inline struct sock *sco_chan_get(struct sco_conn *conn) | |||
138 | 138 | ||
139 | static int sco_conn_del(struct hci_conn *hcon, int err) | 139 | static int sco_conn_del(struct hci_conn *hcon, int err) |
140 | { | 140 | { |
141 | struct sco_conn *conn; | 141 | struct sco_conn *conn = hcon->sco_data; |
142 | struct sock *sk; | 142 | struct sock *sk; |
143 | 143 | ||
144 | if (!(conn = hcon->sco_data)) | 144 | if (!conn) |
145 | return 0; | 145 | return 0; |
146 | 146 | ||
147 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); | 147 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); |
148 | 148 | ||
149 | /* Kill socket */ | 149 | /* Kill socket */ |
150 | if ((sk = sco_chan_get(conn))) { | 150 | sk = sco_chan_get(conn); |
151 | if (sk) { | ||
151 | bh_lock_sock(sk); | 152 | bh_lock_sock(sk); |
152 | sco_sock_clear_timer(sk); | 153 | sco_sock_clear_timer(sk); |
153 | sco_chan_del(sk, err); | 154 | sco_chan_del(sk, err); |
@@ -185,7 +186,8 @@ static int sco_connect(struct sock *sk) | |||
185 | 186 | ||
186 | BT_DBG("%s -> %s", batostr(src), batostr(dst)); | 187 | BT_DBG("%s -> %s", batostr(src), batostr(dst)); |
187 | 188 | ||
188 | if (!(hdev = hci_get_route(dst, src))) | 189 | hdev = hci_get_route(dst, src); |
190 | if (!hdev) | ||
189 | return -EHOSTUNREACH; | 191 | return -EHOSTUNREACH; |
190 | 192 | ||
191 | hci_dev_lock_bh(hdev); | 193 | hci_dev_lock_bh(hdev); |
@@ -510,7 +512,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen | |||
510 | /* Set destination address and psm */ | 512 | /* Set destination address and psm */ |
511 | bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); | 513 | bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); |
512 | 514 | ||
513 | if ((err = sco_connect(sk))) | 515 | err = sco_connect(sk); |
516 | if (err) | ||
514 | goto done; | 517 | goto done; |
515 | 518 | ||
516 | err = bt_sock_wait_state(sk, BT_CONNECTED, | 519 | err = bt_sock_wait_state(sk, BT_CONNECTED, |
@@ -828,13 +831,14 @@ static void sco_chan_del(struct sock *sk, int err) | |||
828 | 831 | ||
829 | static void sco_conn_ready(struct sco_conn *conn) | 832 | static void sco_conn_ready(struct sco_conn *conn) |
830 | { | 833 | { |
831 | struct sock *parent, *sk; | 834 | struct sock *parent; |
835 | struct sock *sk = conn->sk; | ||
832 | 836 | ||
833 | BT_DBG("conn %p", conn); | 837 | BT_DBG("conn %p", conn); |
834 | 838 | ||
835 | sco_conn_lock(conn); | 839 | sco_conn_lock(conn); |
836 | 840 | ||
837 | if ((sk = conn->sk)) { | 841 | if (sk) { |
838 | sco_sock_clear_timer(sk); | 842 | sco_sock_clear_timer(sk); |
839 | bh_lock_sock(sk); | 843 | bh_lock_sock(sk); |
840 | sk->sk_state = BT_CONNECTED; | 844 | sk->sk_state = BT_CONNECTED; |
diff --git a/net/bridge/br.c b/net/bridge/br.c index c8436fa31344..84bbb82599b2 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -22,8 +22,6 @@ | |||
22 | 22 | ||
23 | #include "br_private.h" | 23 | #include "br_private.h" |
24 | 24 | ||
25 | int (*br_should_route_hook)(struct sk_buff *skb); | ||
26 | |||
27 | static const struct stp_proto br_stp_proto = { | 25 | static const struct stp_proto br_stp_proto = { |
28 | .rcv = br_stp_rcv, | 26 | .rcv = br_stp_rcv, |
29 | }; | 27 | }; |
@@ -102,8 +100,6 @@ static void __exit br_deinit(void) | |||
102 | br_fdb_fini(); | 100 | br_fdb_fini(); |
103 | } | 101 | } |
104 | 102 | ||
105 | EXPORT_SYMBOL(br_should_route_hook); | ||
106 | |||
107 | module_init(br_init) | 103 | module_init(br_init) |
108 | module_exit(br_deinit) | 104 | module_exit(br_deinit) |
109 | MODULE_LICENSE("GPL"); | 105 | MODULE_LICENSE("GPL"); |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 17cb0b633576..556443566e9c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -141,7 +141,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) | |||
141 | 141 | ||
142 | #ifdef CONFIG_BRIDGE_NETFILTER | 142 | #ifdef CONFIG_BRIDGE_NETFILTER |
143 | /* remember the MTU in the rtable for PMTU */ | 143 | /* remember the MTU in the rtable for PMTU */ |
144 | br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu; | 144 | dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | return 0; | 147 | return 0; |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 90512ccfd3e9..2872393b2939 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -238,15 +238,18 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | |||
238 | int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) | 238 | int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) |
239 | { | 239 | { |
240 | struct net_bridge_fdb_entry *fdb; | 240 | struct net_bridge_fdb_entry *fdb; |
241 | struct net_bridge_port *port; | ||
241 | int ret; | 242 | int ret; |
242 | 243 | ||
243 | if (!br_port_exists(dev)) | ||
244 | return 0; | ||
245 | |||
246 | rcu_read_lock(); | 244 | rcu_read_lock(); |
247 | fdb = __br_fdb_get(br_port_get_rcu(dev)->br, addr); | 245 | port = br_port_get_rcu(dev); |
248 | ret = fdb && fdb->dst->dev != dev && | 246 | if (!port) |
249 | fdb->dst->state == BR_STATE_FORWARDING; | 247 | ret = 0; |
248 | else { | ||
249 | fdb = __br_fdb_get(port->br, addr); | ||
250 | ret = fdb && fdb->dst->dev != dev && | ||
251 | fdb->dst->state == BR_STATE_FORWARDING; | ||
252 | } | ||
250 | rcu_read_unlock(); | 253 | rcu_read_unlock(); |
251 | 254 | ||
252 | return ret; | 255 | return ret; |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index cbfe87f0f34a..2bd11ec6d166 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -223,7 +223,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | |||
223 | struct net_bridge_port_group *p; | 223 | struct net_bridge_port_group *p; |
224 | struct hlist_node *rp; | 224 | struct hlist_node *rp; |
225 | 225 | ||
226 | rp = rcu_dereference(br->router_list.first); | 226 | rp = rcu_dereference(hlist_first_rcu(&br->router_list)); |
227 | p = mdst ? rcu_dereference(mdst->ports) : NULL; | 227 | p = mdst ? rcu_dereference(mdst->ports) : NULL; |
228 | while (p || rp) { | 228 | while (p || rp) { |
229 | struct net_bridge_port *port, *lport, *rport; | 229 | struct net_bridge_port *port, *lport, *rport; |
@@ -242,7 +242,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | |||
242 | if ((unsigned long)lport >= (unsigned long)port) | 242 | if ((unsigned long)lport >= (unsigned long)port) |
243 | p = rcu_dereference(p->next); | 243 | p = rcu_dereference(p->next); |
244 | if ((unsigned long)rport >= (unsigned long)port) | 244 | if ((unsigned long)rport >= (unsigned long)port) |
245 | rp = rcu_dereference(rp->next); | 245 | rp = rcu_dereference(hlist_next_rcu(rp)); |
246 | } | 246 | } |
247 | 247 | ||
248 | if (!prev) | 248 | if (!prev) |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 89ad25a76202..d9d1e2bac1d6 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -475,11 +475,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) | |||
475 | { | 475 | { |
476 | struct net_bridge_port *p; | 476 | struct net_bridge_port *p; |
477 | 477 | ||
478 | if (!br_port_exists(dev)) | 478 | p = br_port_get_rtnl(dev); |
479 | return -EINVAL; | 479 | if (!p || p->br != br) |
480 | |||
481 | p = br_port_get(dev); | ||
482 | if (p->br != br) | ||
483 | return -EINVAL; | 480 | return -EINVAL; |
484 | 481 | ||
485 | del_nbp(p); | 482 | del_nbp(p); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 25207a1f182b..6f6d8e1b776f 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -21,6 +21,10 @@ | |||
21 | /* Bridge group multicast address 802.1d (pg 51). */ | 21 | /* Bridge group multicast address 802.1d (pg 51). */ |
22 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | 22 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; |
23 | 23 | ||
24 | /* Hook for brouter */ | ||
25 | br_should_route_hook_t __rcu *br_should_route_hook __read_mostly; | ||
26 | EXPORT_SYMBOL(br_should_route_hook); | ||
27 | |||
24 | static int br_pass_frame_up(struct sk_buff *skb) | 28 | static int br_pass_frame_up(struct sk_buff *skb) |
25 | { | 29 | { |
26 | struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; | 30 | struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev; |
@@ -139,7 +143,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb) | |||
139 | { | 143 | { |
140 | struct net_bridge_port *p; | 144 | struct net_bridge_port *p; |
141 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 145 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
142 | int (*rhook)(struct sk_buff *skb); | 146 | br_should_route_hook_t *rhook; |
143 | 147 | ||
144 | if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) | 148 | if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) |
145 | return skb; | 149 | return skb; |
@@ -173,8 +177,8 @@ forward: | |||
173 | switch (p->state) { | 177 | switch (p->state) { |
174 | case BR_STATE_FORWARDING: | 178 | case BR_STATE_FORWARDING: |
175 | rhook = rcu_dereference(br_should_route_hook); | 179 | rhook = rcu_dereference(br_should_route_hook); |
176 | if (rhook != NULL) { | 180 | if (rhook) { |
177 | if (rhook(skb)) | 181 | if ((*rhook)(skb)) |
178 | return skb; | 182 | return skb; |
179 | dest = eth_hdr(skb)->h_dest; | 183 | dest = eth_hdr(skb)->h_dest; |
180 | } | 184 | } |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 543b3262d002..f701a21acb34 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -33,6 +33,9 @@ | |||
33 | 33 | ||
34 | #include "br_private.h" | 34 | #include "br_private.h" |
35 | 35 | ||
36 | #define mlock_dereference(X, br) \ | ||
37 | rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) | ||
38 | |||
36 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 39 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
37 | static inline int ipv6_is_local_multicast(const struct in6_addr *addr) | 40 | static inline int ipv6_is_local_multicast(const struct in6_addr *addr) |
38 | { | 41 | { |
@@ -135,7 +138,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get( | |||
135 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, | 138 | struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br, |
136 | struct sk_buff *skb) | 139 | struct sk_buff *skb) |
137 | { | 140 | { |
138 | struct net_bridge_mdb_htable *mdb = br->mdb; | 141 | struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb); |
139 | struct br_ip ip; | 142 | struct br_ip ip; |
140 | 143 | ||
141 | if (br->multicast_disabled) | 144 | if (br->multicast_disabled) |
@@ -235,7 +238,8 @@ static void br_multicast_group_expired(unsigned long data) | |||
235 | if (mp->ports) | 238 | if (mp->ports) |
236 | goto out; | 239 | goto out; |
237 | 240 | ||
238 | mdb = br->mdb; | 241 | mdb = mlock_dereference(br->mdb, br); |
242 | |||
239 | hlist_del_rcu(&mp->hlist[mdb->ver]); | 243 | hlist_del_rcu(&mp->hlist[mdb->ver]); |
240 | mdb->size--; | 244 | mdb->size--; |
241 | 245 | ||
@@ -249,16 +253,20 @@ out: | |||
249 | static void br_multicast_del_pg(struct net_bridge *br, | 253 | static void br_multicast_del_pg(struct net_bridge *br, |
250 | struct net_bridge_port_group *pg) | 254 | struct net_bridge_port_group *pg) |
251 | { | 255 | { |
252 | struct net_bridge_mdb_htable *mdb = br->mdb; | 256 | struct net_bridge_mdb_htable *mdb; |
253 | struct net_bridge_mdb_entry *mp; | 257 | struct net_bridge_mdb_entry *mp; |
254 | struct net_bridge_port_group *p; | 258 | struct net_bridge_port_group *p; |
255 | struct net_bridge_port_group **pp; | 259 | struct net_bridge_port_group __rcu **pp; |
260 | |||
261 | mdb = mlock_dereference(br->mdb, br); | ||
256 | 262 | ||
257 | mp = br_mdb_ip_get(mdb, &pg->addr); | 263 | mp = br_mdb_ip_get(mdb, &pg->addr); |
258 | if (WARN_ON(!mp)) | 264 | if (WARN_ON(!mp)) |
259 | return; | 265 | return; |
260 | 266 | ||
261 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 267 | for (pp = &mp->ports; |
268 | (p = mlock_dereference(*pp, br)) != NULL; | ||
269 | pp = &p->next) { | ||
262 | if (p != pg) | 270 | if (p != pg) |
263 | continue; | 271 | continue; |
264 | 272 | ||
@@ -294,10 +302,10 @@ out: | |||
294 | spin_unlock(&br->multicast_lock); | 302 | spin_unlock(&br->multicast_lock); |
295 | } | 303 | } |
296 | 304 | ||
297 | static int br_mdb_rehash(struct net_bridge_mdb_htable **mdbp, int max, | 305 | static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max, |
298 | int elasticity) | 306 | int elasticity) |
299 | { | 307 | { |
300 | struct net_bridge_mdb_htable *old = *mdbp; | 308 | struct net_bridge_mdb_htable *old = rcu_dereference_protected(*mdbp, 1); |
301 | struct net_bridge_mdb_htable *mdb; | 309 | struct net_bridge_mdb_htable *mdb; |
302 | int err; | 310 | int err; |
303 | 311 | ||
@@ -569,7 +577,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( | |||
569 | struct net_bridge *br, struct net_bridge_port *port, | 577 | struct net_bridge *br, struct net_bridge_port *port, |
570 | struct br_ip *group, int hash) | 578 | struct br_ip *group, int hash) |
571 | { | 579 | { |
572 | struct net_bridge_mdb_htable *mdb = br->mdb; | 580 | struct net_bridge_mdb_htable *mdb; |
573 | struct net_bridge_mdb_entry *mp; | 581 | struct net_bridge_mdb_entry *mp; |
574 | struct hlist_node *p; | 582 | struct hlist_node *p; |
575 | unsigned count = 0; | 583 | unsigned count = 0; |
@@ -577,6 +585,7 @@ static struct net_bridge_mdb_entry *br_multicast_get_group( | |||
577 | int elasticity; | 585 | int elasticity; |
578 | int err; | 586 | int err; |
579 | 587 | ||
588 | mdb = rcu_dereference_protected(br->mdb, 1); | ||
580 | hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { | 589 | hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) { |
581 | count++; | 590 | count++; |
582 | if (unlikely(br_ip_equal(group, &mp->addr))) | 591 | if (unlikely(br_ip_equal(group, &mp->addr))) |
@@ -642,13 +651,16 @@ static struct net_bridge_mdb_entry *br_multicast_new_group( | |||
642 | struct net_bridge *br, struct net_bridge_port *port, | 651 | struct net_bridge *br, struct net_bridge_port *port, |
643 | struct br_ip *group) | 652 | struct br_ip *group) |
644 | { | 653 | { |
645 | struct net_bridge_mdb_htable *mdb = br->mdb; | 654 | struct net_bridge_mdb_htable *mdb; |
646 | struct net_bridge_mdb_entry *mp; | 655 | struct net_bridge_mdb_entry *mp; |
647 | int hash; | 656 | int hash; |
657 | int err; | ||
648 | 658 | ||
659 | mdb = rcu_dereference_protected(br->mdb, 1); | ||
649 | if (!mdb) { | 660 | if (!mdb) { |
650 | if (br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0)) | 661 | err = br_mdb_rehash(&br->mdb, BR_HASH_SIZE, 0); |
651 | return NULL; | 662 | if (err) |
663 | return ERR_PTR(err); | ||
652 | goto rehash; | 664 | goto rehash; |
653 | } | 665 | } |
654 | 666 | ||
@@ -660,7 +672,7 @@ static struct net_bridge_mdb_entry *br_multicast_new_group( | |||
660 | 672 | ||
661 | case -EAGAIN: | 673 | case -EAGAIN: |
662 | rehash: | 674 | rehash: |
663 | mdb = br->mdb; | 675 | mdb = rcu_dereference_protected(br->mdb, 1); |
664 | hash = br_ip_hash(mdb, group); | 676 | hash = br_ip_hash(mdb, group); |
665 | break; | 677 | break; |
666 | 678 | ||
@@ -670,7 +682,7 @@ rehash: | |||
670 | 682 | ||
671 | mp = kzalloc(sizeof(*mp), GFP_ATOMIC); | 683 | mp = kzalloc(sizeof(*mp), GFP_ATOMIC); |
672 | if (unlikely(!mp)) | 684 | if (unlikely(!mp)) |
673 | goto out; | 685 | return ERR_PTR(-ENOMEM); |
674 | 686 | ||
675 | mp->br = br; | 687 | mp->br = br; |
676 | mp->addr = *group; | 688 | mp->addr = *group; |
@@ -692,7 +704,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
692 | { | 704 | { |
693 | struct net_bridge_mdb_entry *mp; | 705 | struct net_bridge_mdb_entry *mp; |
694 | struct net_bridge_port_group *p; | 706 | struct net_bridge_port_group *p; |
695 | struct net_bridge_port_group **pp; | 707 | struct net_bridge_port_group __rcu **pp; |
696 | unsigned long now = jiffies; | 708 | unsigned long now = jiffies; |
697 | int err; | 709 | int err; |
698 | 710 | ||
@@ -703,7 +715,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
703 | 715 | ||
704 | mp = br_multicast_new_group(br, port, group); | 716 | mp = br_multicast_new_group(br, port, group); |
705 | err = PTR_ERR(mp); | 717 | err = PTR_ERR(mp); |
706 | if (unlikely(IS_ERR(mp) || !mp)) | 718 | if (IS_ERR(mp)) |
707 | goto err; | 719 | goto err; |
708 | 720 | ||
709 | if (!port) { | 721 | if (!port) { |
@@ -712,7 +724,9 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
712 | goto out; | 724 | goto out; |
713 | } | 725 | } |
714 | 726 | ||
715 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 727 | for (pp = &mp->ports; |
728 | (p = mlock_dereference(*pp, br)) != NULL; | ||
729 | pp = &p->next) { | ||
716 | if (p->port == port) | 730 | if (p->port == port) |
717 | goto found; | 731 | goto found; |
718 | if ((unsigned long)p->port < (unsigned long)port) | 732 | if ((unsigned long)p->port < (unsigned long)port) |
@@ -1106,7 +1120,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1106 | struct net_bridge_mdb_entry *mp; | 1120 | struct net_bridge_mdb_entry *mp; |
1107 | struct igmpv3_query *ih3; | 1121 | struct igmpv3_query *ih3; |
1108 | struct net_bridge_port_group *p; | 1122 | struct net_bridge_port_group *p; |
1109 | struct net_bridge_port_group **pp; | 1123 | struct net_bridge_port_group __rcu **pp; |
1110 | unsigned long max_delay; | 1124 | unsigned long max_delay; |
1111 | unsigned long now = jiffies; | 1125 | unsigned long now = jiffies; |
1112 | __be32 group; | 1126 | __be32 group; |
@@ -1145,7 +1159,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1145 | if (!group) | 1159 | if (!group) |
1146 | goto out; | 1160 | goto out; |
1147 | 1161 | ||
1148 | mp = br_mdb_ip4_get(br->mdb, group); | 1162 | mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group); |
1149 | if (!mp) | 1163 | if (!mp) |
1150 | goto out; | 1164 | goto out; |
1151 | 1165 | ||
@@ -1157,7 +1171,9 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1157 | try_to_del_timer_sync(&mp->timer) >= 0)) | 1171 | try_to_del_timer_sync(&mp->timer) >= 0)) |
1158 | mod_timer(&mp->timer, now + max_delay); | 1172 | mod_timer(&mp->timer, now + max_delay); |
1159 | 1173 | ||
1160 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 1174 | for (pp = &mp->ports; |
1175 | (p = mlock_dereference(*pp, br)) != NULL; | ||
1176 | pp = &p->next) { | ||
1161 | if (timer_pending(&p->timer) ? | 1177 | if (timer_pending(&p->timer) ? |
1162 | time_after(p->timer.expires, now + max_delay) : | 1178 | time_after(p->timer.expires, now + max_delay) : |
1163 | try_to_del_timer_sync(&p->timer) >= 0) | 1179 | try_to_del_timer_sync(&p->timer) >= 0) |
@@ -1178,7 +1194,8 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1178 | struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); | 1194 | struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb); |
1179 | struct net_bridge_mdb_entry *mp; | 1195 | struct net_bridge_mdb_entry *mp; |
1180 | struct mld2_query *mld2q; | 1196 | struct mld2_query *mld2q; |
1181 | struct net_bridge_port_group *p, **pp; | 1197 | struct net_bridge_port_group *p; |
1198 | struct net_bridge_port_group __rcu **pp; | ||
1182 | unsigned long max_delay; | 1199 | unsigned long max_delay; |
1183 | unsigned long now = jiffies; | 1200 | unsigned long now = jiffies; |
1184 | struct in6_addr *group = NULL; | 1201 | struct in6_addr *group = NULL; |
@@ -1214,7 +1231,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1214 | if (!group) | 1231 | if (!group) |
1215 | goto out; | 1232 | goto out; |
1216 | 1233 | ||
1217 | mp = br_mdb_ip6_get(br->mdb, group); | 1234 | mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group); |
1218 | if (!mp) | 1235 | if (!mp) |
1219 | goto out; | 1236 | goto out; |
1220 | 1237 | ||
@@ -1225,7 +1242,9 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1225 | try_to_del_timer_sync(&mp->timer) >= 0)) | 1242 | try_to_del_timer_sync(&mp->timer) >= 0)) |
1226 | mod_timer(&mp->timer, now + max_delay); | 1243 | mod_timer(&mp->timer, now + max_delay); |
1227 | 1244 | ||
1228 | for (pp = &mp->ports; (p = *pp); pp = &p->next) { | 1245 | for (pp = &mp->ports; |
1246 | (p = mlock_dereference(*pp, br)) != NULL; | ||
1247 | pp = &p->next) { | ||
1229 | if (timer_pending(&p->timer) ? | 1248 | if (timer_pending(&p->timer) ? |
1230 | time_after(p->timer.expires, now + max_delay) : | 1249 | time_after(p->timer.expires, now + max_delay) : |
1231 | try_to_del_timer_sync(&p->timer) >= 0) | 1250 | try_to_del_timer_sync(&p->timer) >= 0) |
@@ -1254,7 +1273,7 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1254 | timer_pending(&br->multicast_querier_timer)) | 1273 | timer_pending(&br->multicast_querier_timer)) |
1255 | goto out; | 1274 | goto out; |
1256 | 1275 | ||
1257 | mdb = br->mdb; | 1276 | mdb = mlock_dereference(br->mdb, br); |
1258 | mp = br_mdb_ip_get(mdb, group); | 1277 | mp = br_mdb_ip_get(mdb, group); |
1259 | if (!mp) | 1278 | if (!mp) |
1260 | goto out; | 1279 | goto out; |
@@ -1277,7 +1296,9 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1277 | goto out; | 1296 | goto out; |
1278 | } | 1297 | } |
1279 | 1298 | ||
1280 | for (p = mp->ports; p; p = p->next) { | 1299 | for (p = mlock_dereference(mp->ports, br); |
1300 | p != NULL; | ||
1301 | p = mlock_dereference(p->next, br)) { | ||
1281 | if (p->port != port) | 1302 | if (p->port != port) |
1282 | continue; | 1303 | continue; |
1283 | 1304 | ||
@@ -1633,7 +1654,7 @@ void br_multicast_stop(struct net_bridge *br) | |||
1633 | del_timer_sync(&br->multicast_query_timer); | 1654 | del_timer_sync(&br->multicast_query_timer); |
1634 | 1655 | ||
1635 | spin_lock_bh(&br->multicast_lock); | 1656 | spin_lock_bh(&br->multicast_lock); |
1636 | mdb = br->mdb; | 1657 | mdb = mlock_dereference(br->mdb, br); |
1637 | if (!mdb) | 1658 | if (!mdb) |
1638 | goto out; | 1659 | goto out; |
1639 | 1660 | ||
@@ -1737,6 +1758,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1737 | { | 1758 | { |
1738 | struct net_bridge_port *port; | 1759 | struct net_bridge_port *port; |
1739 | int err = 0; | 1760 | int err = 0; |
1761 | struct net_bridge_mdb_htable *mdb; | ||
1740 | 1762 | ||
1741 | spin_lock(&br->multicast_lock); | 1763 | spin_lock(&br->multicast_lock); |
1742 | if (br->multicast_disabled == !val) | 1764 | if (br->multicast_disabled == !val) |
@@ -1749,15 +1771,16 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1749 | if (!netif_running(br->dev)) | 1771 | if (!netif_running(br->dev)) |
1750 | goto unlock; | 1772 | goto unlock; |
1751 | 1773 | ||
1752 | if (br->mdb) { | 1774 | mdb = mlock_dereference(br->mdb, br); |
1753 | if (br->mdb->old) { | 1775 | if (mdb) { |
1776 | if (mdb->old) { | ||
1754 | err = -EEXIST; | 1777 | err = -EEXIST; |
1755 | rollback: | 1778 | rollback: |
1756 | br->multicast_disabled = !!val; | 1779 | br->multicast_disabled = !!val; |
1757 | goto unlock; | 1780 | goto unlock; |
1758 | } | 1781 | } |
1759 | 1782 | ||
1760 | err = br_mdb_rehash(&br->mdb, br->mdb->max, | 1783 | err = br_mdb_rehash(&br->mdb, mdb->max, |
1761 | br->hash_elasticity); | 1784 | br->hash_elasticity); |
1762 | if (err) | 1785 | if (err) |
1763 | goto rollback; | 1786 | goto rollback; |
@@ -1782,6 +1805,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1782 | { | 1805 | { |
1783 | int err = -ENOENT; | 1806 | int err = -ENOENT; |
1784 | u32 old; | 1807 | u32 old; |
1808 | struct net_bridge_mdb_htable *mdb; | ||
1785 | 1809 | ||
1786 | spin_lock(&br->multicast_lock); | 1810 | spin_lock(&br->multicast_lock); |
1787 | if (!netif_running(br->dev)) | 1811 | if (!netif_running(br->dev)) |
@@ -1790,7 +1814,9 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1790 | err = -EINVAL; | 1814 | err = -EINVAL; |
1791 | if (!is_power_of_2(val)) | 1815 | if (!is_power_of_2(val)) |
1792 | goto unlock; | 1816 | goto unlock; |
1793 | if (br->mdb && val < br->mdb->size) | 1817 | |
1818 | mdb = mlock_dereference(br->mdb, br); | ||
1819 | if (mdb && val < mdb->size) | ||
1794 | goto unlock; | 1820 | goto unlock; |
1795 | 1821 | ||
1796 | err = 0; | 1822 | err = 0; |
@@ -1798,8 +1824,8 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val) | |||
1798 | old = br->hash_max; | 1824 | old = br->hash_max; |
1799 | br->hash_max = val; | 1825 | br->hash_max = val; |
1800 | 1826 | ||
1801 | if (br->mdb) { | 1827 | if (mdb) { |
1802 | if (br->mdb->old) { | 1828 | if (mdb->old) { |
1803 | err = -EEXIST; | 1829 | err = -EEXIST; |
1804 | rollback: | 1830 | rollback: |
1805 | br->hash_max = old; | 1831 | br->hash_max = old; |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 865fd7634b67..4b5b66d07bba 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -124,24 +124,25 @@ void br_netfilter_rtable_init(struct net_bridge *br) | |||
124 | atomic_set(&rt->dst.__refcnt, 1); | 124 | atomic_set(&rt->dst.__refcnt, 1); |
125 | rt->dst.dev = br->dev; | 125 | rt->dst.dev = br->dev; |
126 | rt->dst.path = &rt->dst; | 126 | rt->dst.path = &rt->dst; |
127 | rt->dst.metrics[RTAX_MTU - 1] = 1500; | 127 | dst_metric_set(&rt->dst, RTAX_MTU, 1500); |
128 | rt->dst.flags = DST_NOXFRM; | 128 | rt->dst.flags = DST_NOXFRM; |
129 | rt->dst.ops = &fake_dst_ops; | 129 | rt->dst.ops = &fake_dst_ops; |
130 | } | 130 | } |
131 | 131 | ||
132 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) | 132 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) |
133 | { | 133 | { |
134 | if (!br_port_exists(dev)) | 134 | struct net_bridge_port *port; |
135 | return NULL; | 135 | |
136 | return &br_port_get_rcu(dev)->br->fake_rtable; | 136 | port = br_port_get_rcu(dev); |
137 | return port ? &port->br->fake_rtable : NULL; | ||
137 | } | 138 | } |
138 | 139 | ||
139 | static inline struct net_device *bridge_parent(const struct net_device *dev) | 140 | static inline struct net_device *bridge_parent(const struct net_device *dev) |
140 | { | 141 | { |
141 | if (!br_port_exists(dev)) | 142 | struct net_bridge_port *port; |
142 | return NULL; | ||
143 | 143 | ||
144 | return br_port_get_rcu(dev)->br->dev; | 144 | port = br_port_get_rcu(dev); |
145 | return port ? port->br->dev : NULL; | ||
145 | } | 146 | } |
146 | 147 | ||
147 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | 148 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) |
@@ -412,13 +413,8 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) | |||
412 | if (dnat_took_place(skb)) { | 413 | if (dnat_took_place(skb)) { |
413 | if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { | 414 | if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { |
414 | struct flowi fl = { | 415 | struct flowi fl = { |
415 | .nl_u = { | 416 | .fl4_dst = iph->daddr, |
416 | .ip4_u = { | 417 | .fl4_tos = RT_TOS(iph->tos), |
417 | .daddr = iph->daddr, | ||
418 | .saddr = 0, | ||
419 | .tos = RT_TOS(iph->tos) }, | ||
420 | }, | ||
421 | .proto = 0, | ||
422 | }; | 418 | }; |
423 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 419 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
424 | 420 | ||
@@ -566,26 +562,26 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
566 | u32 pkt_len; | 562 | u32 pkt_len; |
567 | 563 | ||
568 | if (skb->len < sizeof(struct ipv6hdr)) | 564 | if (skb->len < sizeof(struct ipv6hdr)) |
569 | goto inhdr_error; | 565 | return NF_DROP; |
570 | 566 | ||
571 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 567 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
572 | goto inhdr_error; | 568 | return NF_DROP; |
573 | 569 | ||
574 | hdr = ipv6_hdr(skb); | 570 | hdr = ipv6_hdr(skb); |
575 | 571 | ||
576 | if (hdr->version != 6) | 572 | if (hdr->version != 6) |
577 | goto inhdr_error; | 573 | return NF_DROP; |
578 | 574 | ||
579 | pkt_len = ntohs(hdr->payload_len); | 575 | pkt_len = ntohs(hdr->payload_len); |
580 | 576 | ||
581 | if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { | 577 | if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { |
582 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) | 578 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) |
583 | goto inhdr_error; | 579 | return NF_DROP; |
584 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) | 580 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) |
585 | goto inhdr_error; | 581 | return NF_DROP; |
586 | } | 582 | } |
587 | if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) | 583 | if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) |
588 | goto inhdr_error; | 584 | return NF_DROP; |
589 | 585 | ||
590 | nf_bridge_put(skb->nf_bridge); | 586 | nf_bridge_put(skb->nf_bridge); |
591 | if (!nf_bridge_alloc(skb)) | 587 | if (!nf_bridge_alloc(skb)) |
@@ -598,9 +594,6 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
598 | br_nf_pre_routing_finish_ipv6); | 594 | br_nf_pre_routing_finish_ipv6); |
599 | 595 | ||
600 | return NF_STOLEN; | 596 | return NF_STOLEN; |
601 | |||
602 | inhdr_error: | ||
603 | return NF_DROP; | ||
604 | } | 597 | } |
605 | 598 | ||
606 | /* Direct IPv6 traffic to br_nf_pre_routing_ipv6. | 599 | /* Direct IPv6 traffic to br_nf_pre_routing_ipv6. |
@@ -619,11 +612,11 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
619 | __u32 len = nf_bridge_encap_header_len(skb); | 612 | __u32 len = nf_bridge_encap_header_len(skb); |
620 | 613 | ||
621 | if (unlikely(!pskb_may_pull(skb, len))) | 614 | if (unlikely(!pskb_may_pull(skb, len))) |
622 | goto out; | 615 | return NF_DROP; |
623 | 616 | ||
624 | p = br_port_get_rcu(in); | 617 | p = br_port_get_rcu(in); |
625 | if (p == NULL) | 618 | if (p == NULL) |
626 | goto out; | 619 | return NF_DROP; |
627 | br = p->br; | 620 | br = p->br; |
628 | 621 | ||
629 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || | 622 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || |
@@ -645,8 +638,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
645 | nf_bridge_pull_encap_header_rcsum(skb); | 638 | nf_bridge_pull_encap_header_rcsum(skb); |
646 | 639 | ||
647 | if (br_parse_ip_options(skb)) | 640 | if (br_parse_ip_options(skb)) |
648 | /* Drop invalid packet */ | 641 | return NF_DROP; |
649 | goto out; | ||
650 | 642 | ||
651 | nf_bridge_put(skb->nf_bridge); | 643 | nf_bridge_put(skb->nf_bridge); |
652 | if (!nf_bridge_alloc(skb)) | 644 | if (!nf_bridge_alloc(skb)) |
@@ -660,9 +652,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
660 | br_nf_pre_routing_finish); | 652 | br_nf_pre_routing_finish); |
661 | 653 | ||
662 | return NF_STOLEN; | 654 | return NF_STOLEN; |
663 | |||
664 | out: | ||
665 | return NF_DROP; | ||
666 | } | 655 | } |
667 | 656 | ||
668 | 657 | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 4a6a378c84e3..f8bf4c7f842c 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -119,11 +119,13 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
119 | 119 | ||
120 | idx = 0; | 120 | idx = 0; |
121 | for_each_netdev(net, dev) { | 121 | for_each_netdev(net, dev) { |
122 | struct net_bridge_port *port = br_port_get_rtnl(dev); | ||
123 | |||
122 | /* not a bridge port */ | 124 | /* not a bridge port */ |
123 | if (!br_port_exists(dev) || idx < cb->args[0]) | 125 | if (!port || idx < cb->args[0]) |
124 | goto skip; | 126 | goto skip; |
125 | 127 | ||
126 | if (br_fill_ifinfo(skb, br_port_get(dev), | 128 | if (br_fill_ifinfo(skb, port, |
127 | NETLINK_CB(cb->skb).pid, | 129 | NETLINK_CB(cb->skb).pid, |
128 | cb->nlh->nlmsg_seq, RTM_NEWLINK, | 130 | cb->nlh->nlmsg_seq, RTM_NEWLINK, |
129 | NLM_F_MULTI) < 0) | 131 | NLM_F_MULTI) < 0) |
@@ -169,9 +171,9 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
169 | if (!dev) | 171 | if (!dev) |
170 | return -ENODEV; | 172 | return -ENODEV; |
171 | 173 | ||
172 | if (!br_port_exists(dev)) | 174 | p = br_port_get_rtnl(dev); |
175 | if (!p) | ||
173 | return -EINVAL; | 176 | return -EINVAL; |
174 | p = br_port_get(dev); | ||
175 | 177 | ||
176 | /* if kernel STP is running, don't allow changes */ | 178 | /* if kernel STP is running, don't allow changes */ |
177 | if (p->br->stp_enabled == BR_KERNEL_STP) | 179 | if (p->br->stp_enabled == BR_KERNEL_STP) |
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 404d4e14c6a7..7d337c9b6082 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -32,15 +32,15 @@ struct notifier_block br_device_notifier = { | |||
32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | 32 | static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
33 | { | 33 | { |
34 | struct net_device *dev = ptr; | 34 | struct net_device *dev = ptr; |
35 | struct net_bridge_port *p = br_port_get(dev); | 35 | struct net_bridge_port *p; |
36 | struct net_bridge *br; | 36 | struct net_bridge *br; |
37 | int err; | 37 | int err; |
38 | 38 | ||
39 | /* not a port of a bridge */ | 39 | /* not a port of a bridge */ |
40 | if (!br_port_exists(dev)) | 40 | p = br_port_get_rtnl(dev); |
41 | if (!p) | ||
41 | return NOTIFY_DONE; | 42 | return NOTIFY_DONE; |
42 | 43 | ||
43 | p = br_port_get(dev); | ||
44 | br = p->br; | 44 | br = p->br; |
45 | 45 | ||
46 | switch (event) { | 46 | switch (event) { |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 75c90edaf7db..84aac7734bfc 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -72,7 +72,7 @@ struct net_bridge_fdb_entry | |||
72 | 72 | ||
73 | struct net_bridge_port_group { | 73 | struct net_bridge_port_group { |
74 | struct net_bridge_port *port; | 74 | struct net_bridge_port *port; |
75 | struct net_bridge_port_group *next; | 75 | struct net_bridge_port_group __rcu *next; |
76 | struct hlist_node mglist; | 76 | struct hlist_node mglist; |
77 | struct rcu_head rcu; | 77 | struct rcu_head rcu; |
78 | struct timer_list timer; | 78 | struct timer_list timer; |
@@ -86,7 +86,7 @@ struct net_bridge_mdb_entry | |||
86 | struct hlist_node hlist[2]; | 86 | struct hlist_node hlist[2]; |
87 | struct hlist_node mglist; | 87 | struct hlist_node mglist; |
88 | struct net_bridge *br; | 88 | struct net_bridge *br; |
89 | struct net_bridge_port_group *ports; | 89 | struct net_bridge_port_group __rcu *ports; |
90 | struct rcu_head rcu; | 90 | struct rcu_head rcu; |
91 | struct timer_list timer; | 91 | struct timer_list timer; |
92 | struct timer_list query_timer; | 92 | struct timer_list query_timer; |
@@ -151,11 +151,20 @@ struct net_bridge_port | |||
151 | #endif | 151 | #endif |
152 | }; | 152 | }; |
153 | 153 | ||
154 | #define br_port_get_rcu(dev) \ | ||
155 | ((struct net_bridge_port *) rcu_dereference(dev->rx_handler_data)) | ||
156 | #define br_port_get(dev) ((struct net_bridge_port *) dev->rx_handler_data) | ||
157 | #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) | 154 | #define br_port_exists(dev) (dev->priv_flags & IFF_BRIDGE_PORT) |
158 | 155 | ||
156 | static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev) | ||
157 | { | ||
158 | struct net_bridge_port *port = rcu_dereference(dev->rx_handler_data); | ||
159 | return br_port_exists(dev) ? port : NULL; | ||
160 | } | ||
161 | |||
162 | static inline struct net_bridge_port *br_port_get_rtnl(struct net_device *dev) | ||
163 | { | ||
164 | return br_port_exists(dev) ? | ||
165 | rtnl_dereference(dev->rx_handler_data) : NULL; | ||
166 | } | ||
167 | |||
159 | struct br_cpu_netstats { | 168 | struct br_cpu_netstats { |
160 | u64 rx_packets; | 169 | u64 rx_packets; |
161 | u64 rx_bytes; | 170 | u64 rx_bytes; |
@@ -227,7 +236,7 @@ struct net_bridge | |||
227 | unsigned long multicast_startup_query_interval; | 236 | unsigned long multicast_startup_query_interval; |
228 | 237 | ||
229 | spinlock_t multicast_lock; | 238 | spinlock_t multicast_lock; |
230 | struct net_bridge_mdb_htable *mdb; | 239 | struct net_bridge_mdb_htable __rcu *mdb; |
231 | struct hlist_head router_list; | 240 | struct hlist_head router_list; |
232 | struct hlist_head mglist; | 241 | struct hlist_head mglist; |
233 | 242 | ||
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index e3d7aefa9181..289646ec9b7b 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -143,10 +143,6 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | |||
143 | struct net_bridge *br; | 143 | struct net_bridge *br; |
144 | const unsigned char *buf; | 144 | const unsigned char *buf; |
145 | 145 | ||
146 | if (!br_port_exists(dev)) | ||
147 | goto err; | ||
148 | p = br_port_get_rcu(dev); | ||
149 | |||
150 | if (!pskb_may_pull(skb, 4)) | 146 | if (!pskb_may_pull(skb, 4)) |
151 | goto err; | 147 | goto err; |
152 | 148 | ||
@@ -155,6 +151,10 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | |||
155 | if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) | 151 | if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) |
156 | goto err; | 152 | goto err; |
157 | 153 | ||
154 | p = br_port_get_rcu(dev); | ||
155 | if (!p) | ||
156 | goto err; | ||
157 | |||
158 | br = p->br; | 158 | br = p->br; |
159 | spin_lock(&br->lock); | 159 | spin_lock(&br->lock); |
160 | 160 | ||
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 1d8826914cbf..79372d4a4055 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
@@ -145,7 +145,7 @@ static void br_stp_stop(struct net_bridge *br) | |||
145 | char *envp[] = { NULL }; | 145 | char *envp[] = { NULL }; |
146 | 146 | ||
147 | if (br->stp_enabled == BR_USER_STP) { | 147 | if (br->stp_enabled == BR_USER_STP) { |
148 | r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); | 148 | r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC); |
149 | br_info(br, "userspace STP stopped, return code %d\n", r); | 149 | br_info(br, "userspace STP stopped, return code %d\n", r); |
150 | 150 | ||
151 | /* To start timers on any ports left in blocking */ | 151 | /* To start timers on any ports left in blocking */ |
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index ae3f106c3908..1bcaf36ad612 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c | |||
@@ -87,7 +87,8 @@ static int __init ebtable_broute_init(void) | |||
87 | if (ret < 0) | 87 | if (ret < 0) |
88 | return ret; | 88 | return ret; |
89 | /* see br_input.c */ | 89 | /* see br_input.c */ |
90 | rcu_assign_pointer(br_should_route_hook, ebt_broute); | 90 | rcu_assign_pointer(br_should_route_hook, |
91 | (br_should_route_hook_t *)ebt_broute); | ||
91 | return 0; | 92 | return 0; |
92 | } | 93 | } |
93 | 94 | ||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index a1dcf83f0d58..16df0532d4b9 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -128,6 +128,7 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, | |||
128 | const struct net_device *in, const struct net_device *out) | 128 | const struct net_device *in, const struct net_device *out) |
129 | { | 129 | { |
130 | const struct ethhdr *h = eth_hdr(skb); | 130 | const struct ethhdr *h = eth_hdr(skb); |
131 | const struct net_bridge_port *p; | ||
131 | __be16 ethproto; | 132 | __be16 ethproto; |
132 | int verdict, i; | 133 | int verdict, i; |
133 | 134 | ||
@@ -148,13 +149,11 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, | |||
148 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) | 149 | if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) |
149 | return 1; | 150 | return 1; |
150 | /* rcu_read_lock()ed by nf_hook_slow */ | 151 | /* rcu_read_lock()ed by nf_hook_slow */ |
151 | if (in && br_port_exists(in) && | 152 | if (in && (p = br_port_get_rcu(in)) != NULL && |
152 | FWINV2(ebt_dev_check(e->logical_in, br_port_get_rcu(in)->br->dev), | 153 | FWINV2(ebt_dev_check(e->logical_in, p->br->dev), EBT_ILOGICALIN)) |
153 | EBT_ILOGICALIN)) | ||
154 | return 1; | 154 | return 1; |
155 | if (out && br_port_exists(out) && | 155 | if (out && (p = br_port_get_rcu(out)) != NULL && |
156 | FWINV2(ebt_dev_check(e->logical_out, br_port_get_rcu(out)->br->dev), | 156 | FWINV2(ebt_dev_check(e->logical_out, p->br->dev), EBT_ILOGICALOUT)) |
157 | EBT_ILOGICALOUT)) | ||
158 | return 1; | 157 | return 1; |
159 | 158 | ||
160 | if (e->bitmask & EBT_SOURCEMAC) { | 159 | if (e->bitmask & EBT_SOURCEMAC) { |
@@ -1148,7 +1147,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table) | |||
1148 | void *p; | 1147 | void *p; |
1149 | 1148 | ||
1150 | if (input_table == NULL || (repl = input_table->table) == NULL || | 1149 | if (input_table == NULL || (repl = input_table->table) == NULL || |
1151 | repl->entries == 0 || repl->entries_size == 0 || | 1150 | repl->entries == NULL || repl->entries_size == 0 || |
1152 | repl->counters != NULL || input_table->private != NULL) { | 1151 | repl->counters != NULL || input_table->private != NULL) { |
1153 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); | 1152 | BUGPRINT("Bad table data for ebt_register_table!!!\n"); |
1154 | return ERR_PTR(-EINVAL); | 1153 | return ERR_PTR(-EINVAL); |
diff --git a/net/caif/Makefile b/net/caif/Makefile index f87481fb0e65..9d38e406e4a4 100644 --- a/net/caif/Makefile +++ b/net/caif/Makefile | |||
@@ -1,8 +1,6 @@ | |||
1 | ifeq ($(CONFIG_CAIF_DEBUG),y) | 1 | ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG |
2 | EXTRA_CFLAGS += -DDEBUG | ||
3 | endif | ||
4 | 2 | ||
5 | caif-objs := caif_dev.o \ | 3 | caif-y := caif_dev.o \ |
6 | cfcnfg.o cfmuxl.o cfctrl.o \ | 4 | cfcnfg.o cfmuxl.o cfctrl.o \ |
7 | cffrml.o cfveil.o cfdbgl.o\ | 5 | cffrml.o cfveil.o cfdbgl.o\ |
8 | cfserl.o cfdgml.o \ | 6 | cfserl.o cfdgml.o \ |
@@ -13,4 +11,4 @@ obj-$(CONFIG_CAIF) += caif.o | |||
13 | obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o | 11 | obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o |
14 | obj-$(CONFIG_CAIF) += caif_socket.o | 12 | obj-$(CONFIG_CAIF) += caif_socket.o |
15 | 13 | ||
16 | export-objs := caif.o | 14 | export-y := caif.o |
diff --git a/net/can/Makefile b/net/can/Makefile index 9cd3c4b3abda..2d3894b32742 100644 --- a/net/can/Makefile +++ b/net/can/Makefile | |||
@@ -3,10 +3,10 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_CAN) += can.o | 5 | obj-$(CONFIG_CAN) += can.o |
6 | can-objs := af_can.o proc.o | 6 | can-y := af_can.o proc.o |
7 | 7 | ||
8 | obj-$(CONFIG_CAN_RAW) += can-raw.o | 8 | obj-$(CONFIG_CAN_RAW) += can-raw.o |
9 | can-raw-objs := raw.o | 9 | can-raw-y := raw.o |
10 | 10 | ||
11 | obj-$(CONFIG_CAN_BCM) += can-bcm.o | 11 | obj-$(CONFIG_CAN_BCM) += can-bcm.o |
12 | can-bcm-objs := bcm.o | 12 | can-bcm-y := bcm.o |
diff --git a/net/ceph/Makefile b/net/ceph/Makefile index 5f19415ec9c0..e87ef435e11b 100644 --- a/net/ceph/Makefile +++ b/net/ceph/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | obj-$(CONFIG_CEPH_LIB) += libceph.o | 4 | obj-$(CONFIG_CEPH_LIB) += libceph.o |
5 | 5 | ||
6 | libceph-objs := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ | 6 | libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ |
7 | mon_client.o \ | 7 | mon_client.o \ |
8 | osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ | 8 | osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ |
9 | debugfs.o \ | 9 | debugfs.o \ |
diff --git a/net/core/datagram.c b/net/core/datagram.c index cd1e039c8755..18ac112ea7ae 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -177,7 +177,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, | |||
177 | * interrupt level will suddenly eat the receive_queue. | 177 | * interrupt level will suddenly eat the receive_queue. |
178 | * | 178 | * |
179 | * Look at current nfs client by the way... | 179 | * Look at current nfs client by the way... |
180 | * However, this function was corrent in any case. 8) | 180 | * However, this function was correct in any case. 8) |
181 | */ | 181 | */ |
182 | unsigned long cpu_flags; | 182 | unsigned long cpu_flags; |
183 | 183 | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 0dd54a69dace..a215269d2e35 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -743,34 +743,31 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex) | |||
743 | EXPORT_SYMBOL(dev_get_by_index); | 743 | EXPORT_SYMBOL(dev_get_by_index); |
744 | 744 | ||
745 | /** | 745 | /** |
746 | * dev_getbyhwaddr - find a device by its hardware address | 746 | * dev_getbyhwaddr_rcu - find a device by its hardware address |
747 | * @net: the applicable net namespace | 747 | * @net: the applicable net namespace |
748 | * @type: media type of device | 748 | * @type: media type of device |
749 | * @ha: hardware address | 749 | * @ha: hardware address |
750 | * | 750 | * |
751 | * Search for an interface by MAC address. Returns NULL if the device | 751 | * Search for an interface by MAC address. Returns NULL if the device |
752 | * is not found or a pointer to the device. The caller must hold the | 752 | * is not found or a pointer to the device. The caller must hold RCU |
753 | * rtnl semaphore. The returned device has not had its ref count increased | 753 | * The returned device has not had its ref count increased |
754 | * and the caller must therefore be careful about locking | 754 | * and the caller must therefore be careful about locking |
755 | * | 755 | * |
756 | * BUGS: | ||
757 | * If the API was consistent this would be __dev_get_by_hwaddr | ||
758 | */ | 756 | */ |
759 | 757 | ||
760 | struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha) | 758 | struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type, |
759 | const char *ha) | ||
761 | { | 760 | { |
762 | struct net_device *dev; | 761 | struct net_device *dev; |
763 | 762 | ||
764 | ASSERT_RTNL(); | 763 | for_each_netdev_rcu(net, dev) |
765 | |||
766 | for_each_netdev(net, dev) | ||
767 | if (dev->type == type && | 764 | if (dev->type == type && |
768 | !memcmp(dev->dev_addr, ha, dev->addr_len)) | 765 | !memcmp(dev->dev_addr, ha, dev->addr_len)) |
769 | return dev; | 766 | return dev; |
770 | 767 | ||
771 | return NULL; | 768 | return NULL; |
772 | } | 769 | } |
773 | EXPORT_SYMBOL(dev_getbyhwaddr); | 770 | EXPORT_SYMBOL(dev_getbyhwaddr_rcu); |
774 | 771 | ||
775 | struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) | 772 | struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) |
776 | { | 773 | { |
@@ -1225,52 +1222,90 @@ int dev_open(struct net_device *dev) | |||
1225 | } | 1222 | } |
1226 | EXPORT_SYMBOL(dev_open); | 1223 | EXPORT_SYMBOL(dev_open); |
1227 | 1224 | ||
1228 | static int __dev_close(struct net_device *dev) | 1225 | static int __dev_close_many(struct list_head *head) |
1229 | { | 1226 | { |
1230 | const struct net_device_ops *ops = dev->netdev_ops; | 1227 | struct net_device *dev; |
1231 | 1228 | ||
1232 | ASSERT_RTNL(); | 1229 | ASSERT_RTNL(); |
1233 | might_sleep(); | 1230 | might_sleep(); |
1234 | 1231 | ||
1235 | /* | 1232 | list_for_each_entry(dev, head, unreg_list) { |
1236 | * Tell people we are going down, so that they can | 1233 | /* |
1237 | * prepare to death, when device is still operating. | 1234 | * Tell people we are going down, so that they can |
1238 | */ | 1235 | * prepare to death, when device is still operating. |
1239 | call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); | 1236 | */ |
1237 | call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); | ||
1240 | 1238 | ||
1241 | clear_bit(__LINK_STATE_START, &dev->state); | 1239 | clear_bit(__LINK_STATE_START, &dev->state); |
1242 | 1240 | ||
1243 | /* Synchronize to scheduled poll. We cannot touch poll list, | 1241 | /* Synchronize to scheduled poll. We cannot touch poll list, it |
1244 | * it can be even on different cpu. So just clear netif_running(). | 1242 | * can be even on different cpu. So just clear netif_running(). |
1245 | * | 1243 | * |
1246 | * dev->stop() will invoke napi_disable() on all of it's | 1244 | * dev->stop() will invoke napi_disable() on all of it's |
1247 | * napi_struct instances on this device. | 1245 | * napi_struct instances on this device. |
1248 | */ | 1246 | */ |
1249 | smp_mb__after_clear_bit(); /* Commit netif_running(). */ | 1247 | smp_mb__after_clear_bit(); /* Commit netif_running(). */ |
1248 | } | ||
1250 | 1249 | ||
1251 | dev_deactivate(dev); | 1250 | dev_deactivate_many(head); |
1252 | 1251 | ||
1253 | /* | 1252 | list_for_each_entry(dev, head, unreg_list) { |
1254 | * Call the device specific close. This cannot fail. | 1253 | const struct net_device_ops *ops = dev->netdev_ops; |
1255 | * Only if device is UP | ||
1256 | * | ||
1257 | * We allow it to be called even after a DETACH hot-plug | ||
1258 | * event. | ||
1259 | */ | ||
1260 | if (ops->ndo_stop) | ||
1261 | ops->ndo_stop(dev); | ||
1262 | 1254 | ||
1263 | /* | 1255 | /* |
1264 | * Device is now down. | 1256 | * Call the device specific close. This cannot fail. |
1265 | */ | 1257 | * Only if device is UP |
1258 | * | ||
1259 | * We allow it to be called even after a DETACH hot-plug | ||
1260 | * event. | ||
1261 | */ | ||
1262 | if (ops->ndo_stop) | ||
1263 | ops->ndo_stop(dev); | ||
1264 | |||
1265 | /* | ||
1266 | * Device is now down. | ||
1267 | */ | ||
1268 | |||
1269 | dev->flags &= ~IFF_UP; | ||
1270 | |||
1271 | /* | ||
1272 | * Shutdown NET_DMA | ||
1273 | */ | ||
1274 | net_dmaengine_put(); | ||
1275 | } | ||
1276 | |||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | static int __dev_close(struct net_device *dev) | ||
1281 | { | ||
1282 | LIST_HEAD(single); | ||
1283 | |||
1284 | list_add(&dev->unreg_list, &single); | ||
1285 | return __dev_close_many(&single); | ||
1286 | } | ||
1287 | |||
1288 | int dev_close_many(struct list_head *head) | ||
1289 | { | ||
1290 | struct net_device *dev, *tmp; | ||
1291 | LIST_HEAD(tmp_list); | ||
1292 | |||
1293 | list_for_each_entry_safe(dev, tmp, head, unreg_list) | ||
1294 | if (!(dev->flags & IFF_UP)) | ||
1295 | list_move(&dev->unreg_list, &tmp_list); | ||
1266 | 1296 | ||
1267 | dev->flags &= ~IFF_UP; | 1297 | __dev_close_many(head); |
1268 | 1298 | ||
1269 | /* | 1299 | /* |
1270 | * Shutdown NET_DMA | 1300 | * Tell people we are down |
1271 | */ | 1301 | */ |
1272 | net_dmaengine_put(); | 1302 | list_for_each_entry(dev, head, unreg_list) { |
1303 | rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); | ||
1304 | call_netdevice_notifiers(NETDEV_DOWN, dev); | ||
1305 | } | ||
1273 | 1306 | ||
1307 | /* rollback_registered_many needs the complete original list */ | ||
1308 | list_splice(&tmp_list, head); | ||
1274 | return 0; | 1309 | return 0; |
1275 | } | 1310 | } |
1276 | 1311 | ||
@@ -1285,16 +1320,10 @@ static int __dev_close(struct net_device *dev) | |||
1285 | */ | 1320 | */ |
1286 | int dev_close(struct net_device *dev) | 1321 | int dev_close(struct net_device *dev) |
1287 | { | 1322 | { |
1288 | if (!(dev->flags & IFF_UP)) | 1323 | LIST_HEAD(single); |
1289 | return 0; | ||
1290 | |||
1291 | __dev_close(dev); | ||
1292 | 1324 | ||
1293 | /* | 1325 | list_add(&dev->unreg_list, &single); |
1294 | * Tell people we are down | 1326 | dev_close_many(&single); |
1295 | */ | ||
1296 | rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); | ||
1297 | call_netdevice_notifiers(NETDEV_DOWN, dev); | ||
1298 | 1327 | ||
1299 | return 0; | 1328 | return 0; |
1300 | } | 1329 | } |
@@ -1499,6 +1528,14 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) | |||
1499 | } | 1528 | } |
1500 | EXPORT_SYMBOL_GPL(dev_forward_skb); | 1529 | EXPORT_SYMBOL_GPL(dev_forward_skb); |
1501 | 1530 | ||
1531 | static inline int deliver_skb(struct sk_buff *skb, | ||
1532 | struct packet_type *pt_prev, | ||
1533 | struct net_device *orig_dev) | ||
1534 | { | ||
1535 | atomic_inc(&skb->users); | ||
1536 | return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); | ||
1537 | } | ||
1538 | |||
1502 | /* | 1539 | /* |
1503 | * Support routine. Sends outgoing frames to any network | 1540 | * Support routine. Sends outgoing frames to any network |
1504 | * taps currently in use. | 1541 | * taps currently in use. |
@@ -1507,13 +1544,8 @@ EXPORT_SYMBOL_GPL(dev_forward_skb); | |||
1507 | static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) | 1544 | static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) |
1508 | { | 1545 | { |
1509 | struct packet_type *ptype; | 1546 | struct packet_type *ptype; |
1510 | 1547 | struct sk_buff *skb2 = NULL; | |
1511 | #ifdef CONFIG_NET_CLS_ACT | 1548 | struct packet_type *pt_prev = NULL; |
1512 | if (!(skb->tstamp.tv64 && (G_TC_FROM(skb->tc_verd) & AT_INGRESS))) | ||
1513 | net_timestamp_set(skb); | ||
1514 | #else | ||
1515 | net_timestamp_set(skb); | ||
1516 | #endif | ||
1517 | 1549 | ||
1518 | rcu_read_lock(); | 1550 | rcu_read_lock(); |
1519 | list_for_each_entry_rcu(ptype, &ptype_all, list) { | 1551 | list_for_each_entry_rcu(ptype, &ptype_all, list) { |
@@ -1523,10 +1555,18 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) | |||
1523 | if ((ptype->dev == dev || !ptype->dev) && | 1555 | if ((ptype->dev == dev || !ptype->dev) && |
1524 | (ptype->af_packet_priv == NULL || | 1556 | (ptype->af_packet_priv == NULL || |
1525 | (struct sock *)ptype->af_packet_priv != skb->sk)) { | 1557 | (struct sock *)ptype->af_packet_priv != skb->sk)) { |
1526 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); | 1558 | if (pt_prev) { |
1559 | deliver_skb(skb2, pt_prev, skb->dev); | ||
1560 | pt_prev = ptype; | ||
1561 | continue; | ||
1562 | } | ||
1563 | |||
1564 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
1527 | if (!skb2) | 1565 | if (!skb2) |
1528 | break; | 1566 | break; |
1529 | 1567 | ||
1568 | net_timestamp_set(skb2); | ||
1569 | |||
1530 | /* skb->nh should be correctly | 1570 | /* skb->nh should be correctly |
1531 | set by sender, so that the second statement is | 1571 | set by sender, so that the second statement is |
1532 | just protection against buggy protocols. | 1572 | just protection against buggy protocols. |
@@ -1545,9 +1585,11 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) | |||
1545 | 1585 | ||
1546 | skb2->transport_header = skb2->network_header; | 1586 | skb2->transport_header = skb2->network_header; |
1547 | skb2->pkt_type = PACKET_OUTGOING; | 1587 | skb2->pkt_type = PACKET_OUTGOING; |
1548 | ptype->func(skb2, skb->dev, ptype, skb->dev); | 1588 | pt_prev = ptype; |
1549 | } | 1589 | } |
1550 | } | 1590 | } |
1591 | if (pt_prev) | ||
1592 | pt_prev->func(skb2, skb->dev, pt_prev, skb->dev); | ||
1551 | rcu_read_unlock(); | 1593 | rcu_read_unlock(); |
1552 | } | 1594 | } |
1553 | 1595 | ||
@@ -1557,12 +1599,19 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) | |||
1557 | */ | 1599 | */ |
1558 | int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) | 1600 | int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) |
1559 | { | 1601 | { |
1602 | int rc; | ||
1603 | |||
1560 | if (txq < 1 || txq > dev->num_tx_queues) | 1604 | if (txq < 1 || txq > dev->num_tx_queues) |
1561 | return -EINVAL; | 1605 | return -EINVAL; |
1562 | 1606 | ||
1563 | if (dev->reg_state == NETREG_REGISTERED) { | 1607 | if (dev->reg_state == NETREG_REGISTERED) { |
1564 | ASSERT_RTNL(); | 1608 | ASSERT_RTNL(); |
1565 | 1609 | ||
1610 | rc = netdev_queue_update_kobjects(dev, dev->real_num_tx_queues, | ||
1611 | txq); | ||
1612 | if (rc) | ||
1613 | return rc; | ||
1614 | |||
1566 | if (txq < dev->real_num_tx_queues) | 1615 | if (txq < dev->real_num_tx_queues) |
1567 | qdisc_reset_all_tx_gt(dev, txq); | 1616 | qdisc_reset_all_tx_gt(dev, txq); |
1568 | } | 1617 | } |
@@ -1757,7 +1806,7 @@ int skb_checksum_help(struct sk_buff *skb) | |||
1757 | goto out_set_summed; | 1806 | goto out_set_summed; |
1758 | } | 1807 | } |
1759 | 1808 | ||
1760 | offset = skb->csum_start - skb_headroom(skb); | 1809 | offset = skb_checksum_start_offset(skb); |
1761 | BUG_ON(offset >= skb_headlen(skb)); | 1810 | BUG_ON(offset >= skb_headlen(skb)); |
1762 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | 1811 | csum = skb_checksum(skb, offset, skb->len - offset, 0); |
1763 | 1812 | ||
@@ -1794,16 +1843,18 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) | |||
1794 | struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); | 1843 | struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); |
1795 | struct packet_type *ptype; | 1844 | struct packet_type *ptype; |
1796 | __be16 type = skb->protocol; | 1845 | __be16 type = skb->protocol; |
1846 | int vlan_depth = ETH_HLEN; | ||
1797 | int err; | 1847 | int err; |
1798 | 1848 | ||
1799 | if (type == htons(ETH_P_8021Q)) { | 1849 | while (type == htons(ETH_P_8021Q)) { |
1800 | struct vlan_ethhdr *veh; | 1850 | struct vlan_hdr *vh; |
1801 | 1851 | ||
1802 | if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) | 1852 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) |
1803 | return ERR_PTR(-EINVAL); | 1853 | return ERR_PTR(-EINVAL); |
1804 | 1854 | ||
1805 | veh = (struct vlan_ethhdr *)skb->data; | 1855 | vh = (struct vlan_hdr *)(skb->data + vlan_depth); |
1806 | type = veh->h_vlan_encapsulated_proto; | 1856 | type = vh->h_vlan_encapsulated_proto; |
1857 | vlan_depth += VLAN_HLEN; | ||
1807 | } | 1858 | } |
1808 | 1859 | ||
1809 | skb_reset_mac_header(skb); | 1860 | skb_reset_mac_header(skb); |
@@ -1817,8 +1868,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) | |||
1817 | if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) | 1868 | if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) |
1818 | dev->ethtool_ops->get_drvinfo(dev, &info); | 1869 | dev->ethtool_ops->get_drvinfo(dev, &info); |
1819 | 1870 | ||
1820 | WARN(1, "%s: caps=(0x%lx, 0x%lx) len=%d data_len=%d " | 1871 | WARN(1, "%s: caps=(0x%lx, 0x%lx) len=%d data_len=%d ip_summed=%d\n", |
1821 | "ip_summed=%d", | ||
1822 | info.driver, dev ? dev->features : 0L, | 1872 | info.driver, dev ? dev->features : 0L, |
1823 | skb->sk ? skb->sk->sk_route_caps : 0L, | 1873 | skb->sk ? skb->sk->sk_route_caps : 0L, |
1824 | skb->len, skb->data_len, skb->ip_summed); | 1874 | skb->len, skb->data_len, skb->ip_summed); |
@@ -1967,6 +2017,23 @@ static inline void skb_orphan_try(struct sk_buff *skb) | |||
1967 | } | 2017 | } |
1968 | } | 2018 | } |
1969 | 2019 | ||
2020 | int netif_get_vlan_features(struct sk_buff *skb, struct net_device *dev) | ||
2021 | { | ||
2022 | __be16 protocol = skb->protocol; | ||
2023 | |||
2024 | if (protocol == htons(ETH_P_8021Q)) { | ||
2025 | struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; | ||
2026 | protocol = veh->h_vlan_encapsulated_proto; | ||
2027 | } else if (!skb->vlan_tci) | ||
2028 | return dev->features; | ||
2029 | |||
2030 | if (protocol != htons(ETH_P_8021Q)) | ||
2031 | return dev->features & dev->vlan_features; | ||
2032 | else | ||
2033 | return 0; | ||
2034 | } | ||
2035 | EXPORT_SYMBOL(netif_get_vlan_features); | ||
2036 | |||
1970 | /* | 2037 | /* |
1971 | * Returns true if either: | 2038 | * Returns true if either: |
1972 | * 1. skb has frag_list and the device doesn't support FRAGLIST, or | 2039 | * 1. skb has frag_list and the device doesn't support FRAGLIST, or |
@@ -1977,15 +2044,20 @@ static inline void skb_orphan_try(struct sk_buff *skb) | |||
1977 | static inline int skb_needs_linearize(struct sk_buff *skb, | 2044 | static inline int skb_needs_linearize(struct sk_buff *skb, |
1978 | struct net_device *dev) | 2045 | struct net_device *dev) |
1979 | { | 2046 | { |
1980 | int features = dev->features; | 2047 | if (skb_is_nonlinear(skb)) { |
2048 | int features = dev->features; | ||
1981 | 2049 | ||
1982 | if (skb->protocol == htons(ETH_P_8021Q) || vlan_tx_tag_present(skb)) | 2050 | if (vlan_tx_tag_present(skb)) |
1983 | features &= dev->vlan_features; | 2051 | features &= dev->vlan_features; |
1984 | 2052 | ||
1985 | return skb_is_nonlinear(skb) && | 2053 | return (skb_has_frag_list(skb) && |
1986 | ((skb_has_frag_list(skb) && !(features & NETIF_F_FRAGLIST)) || | 2054 | !(features & NETIF_F_FRAGLIST)) || |
1987 | (skb_shinfo(skb)->nr_frags && (!(features & NETIF_F_SG) || | 2055 | (skb_shinfo(skb)->nr_frags && |
1988 | illegal_highdma(dev, skb)))); | 2056 | (!(features & NETIF_F_SG) || |
2057 | illegal_highdma(dev, skb))); | ||
2058 | } | ||
2059 | |||
2060 | return 0; | ||
1989 | } | 2061 | } |
1990 | 2062 | ||
1991 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | 2063 | int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, |
@@ -1995,9 +2067,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
1995 | int rc = NETDEV_TX_OK; | 2067 | int rc = NETDEV_TX_OK; |
1996 | 2068 | ||
1997 | if (likely(!skb->next)) { | 2069 | if (likely(!skb->next)) { |
1998 | if (!list_empty(&ptype_all)) | ||
1999 | dev_queue_xmit_nit(skb, dev); | ||
2000 | |||
2001 | /* | 2070 | /* |
2002 | * If device doesnt need skb->dst, release it right now while | 2071 | * If device doesnt need skb->dst, release it right now while |
2003 | * its hot in this cpu cache | 2072 | * its hot in this cpu cache |
@@ -2005,6 +2074,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
2005 | if (dev->priv_flags & IFF_XMIT_DST_RELEASE) | 2074 | if (dev->priv_flags & IFF_XMIT_DST_RELEASE) |
2006 | skb_dst_drop(skb); | 2075 | skb_dst_drop(skb); |
2007 | 2076 | ||
2077 | if (!list_empty(&ptype_all)) | ||
2078 | dev_queue_xmit_nit(skb, dev); | ||
2079 | |||
2008 | skb_orphan_try(skb); | 2080 | skb_orphan_try(skb); |
2009 | 2081 | ||
2010 | if (vlan_tx_tag_present(skb) && | 2082 | if (vlan_tx_tag_present(skb) && |
@@ -2031,8 +2103,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, | |||
2031 | * checksumming here. | 2103 | * checksumming here. |
2032 | */ | 2104 | */ |
2033 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 2105 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
2034 | skb_set_transport_header(skb, skb->csum_start - | 2106 | skb_set_transport_header(skb, |
2035 | skb_headroom(skb)); | 2107 | skb_checksum_start_offset(skb)); |
2036 | if (!dev_can_checksum(dev, skb) && | 2108 | if (!dev_can_checksum(dev, skb) && |
2037 | skb_checksum_help(skb)) | 2109 | skb_checksum_help(skb)) |
2038 | goto out_kfree_skb; | 2110 | goto out_kfree_skb; |
@@ -2085,14 +2157,19 @@ out: | |||
2085 | 2157 | ||
2086 | static u32 hashrnd __read_mostly; | 2158 | static u32 hashrnd __read_mostly; |
2087 | 2159 | ||
2088 | u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) | 2160 | /* |
2161 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number | ||
2162 | * to be used as a distribution range. | ||
2163 | */ | ||
2164 | u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | ||
2165 | unsigned int num_tx_queues) | ||
2089 | { | 2166 | { |
2090 | u32 hash; | 2167 | u32 hash; |
2091 | 2168 | ||
2092 | if (skb_rx_queue_recorded(skb)) { | 2169 | if (skb_rx_queue_recorded(skb)) { |
2093 | hash = skb_get_rx_queue(skb); | 2170 | hash = skb_get_rx_queue(skb); |
2094 | while (unlikely(hash >= dev->real_num_tx_queues)) | 2171 | while (unlikely(hash >= num_tx_queues)) |
2095 | hash -= dev->real_num_tx_queues; | 2172 | hash -= num_tx_queues; |
2096 | return hash; | 2173 | return hash; |
2097 | } | 2174 | } |
2098 | 2175 | ||
@@ -2102,9 +2179,9 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb) | |||
2102 | hash = (__force u16) skb->protocol ^ skb->rxhash; | 2179 | hash = (__force u16) skb->protocol ^ skb->rxhash; |
2103 | hash = jhash_1word(hash, hashrnd); | 2180 | hash = jhash_1word(hash, hashrnd); |
2104 | 2181 | ||
2105 | return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32); | 2182 | return (u16) (((u64) hash * num_tx_queues) >> 32); |
2106 | } | 2183 | } |
2107 | EXPORT_SYMBOL(skb_tx_hash); | 2184 | EXPORT_SYMBOL(__skb_tx_hash); |
2108 | 2185 | ||
2109 | static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index) | 2186 | static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index) |
2110 | { | 2187 | { |
@@ -2119,26 +2196,70 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index) | |||
2119 | return queue_index; | 2196 | return queue_index; |
2120 | } | 2197 | } |
2121 | 2198 | ||
2199 | static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) | ||
2200 | { | ||
2201 | #ifdef CONFIG_XPS | ||
2202 | struct xps_dev_maps *dev_maps; | ||
2203 | struct xps_map *map; | ||
2204 | int queue_index = -1; | ||
2205 | |||
2206 | rcu_read_lock(); | ||
2207 | dev_maps = rcu_dereference(dev->xps_maps); | ||
2208 | if (dev_maps) { | ||
2209 | map = rcu_dereference( | ||
2210 | dev_maps->cpu_map[raw_smp_processor_id()]); | ||
2211 | if (map) { | ||
2212 | if (map->len == 1) | ||
2213 | queue_index = map->queues[0]; | ||
2214 | else { | ||
2215 | u32 hash; | ||
2216 | if (skb->sk && skb->sk->sk_hash) | ||
2217 | hash = skb->sk->sk_hash; | ||
2218 | else | ||
2219 | hash = (__force u16) skb->protocol ^ | ||
2220 | skb->rxhash; | ||
2221 | hash = jhash_1word(hash, hashrnd); | ||
2222 | queue_index = map->queues[ | ||
2223 | ((u64)hash * map->len) >> 32]; | ||
2224 | } | ||
2225 | if (unlikely(queue_index >= dev->real_num_tx_queues)) | ||
2226 | queue_index = -1; | ||
2227 | } | ||
2228 | } | ||
2229 | rcu_read_unlock(); | ||
2230 | |||
2231 | return queue_index; | ||
2232 | #else | ||
2233 | return -1; | ||
2234 | #endif | ||
2235 | } | ||
2236 | |||
2122 | static struct netdev_queue *dev_pick_tx(struct net_device *dev, | 2237 | static struct netdev_queue *dev_pick_tx(struct net_device *dev, |
2123 | struct sk_buff *skb) | 2238 | struct sk_buff *skb) |
2124 | { | 2239 | { |
2125 | int queue_index; | 2240 | int queue_index; |
2126 | const struct net_device_ops *ops = dev->netdev_ops; | 2241 | const struct net_device_ops *ops = dev->netdev_ops; |
2127 | 2242 | ||
2128 | if (ops->ndo_select_queue) { | 2243 | if (dev->real_num_tx_queues == 1) |
2244 | queue_index = 0; | ||
2245 | else if (ops->ndo_select_queue) { | ||
2129 | queue_index = ops->ndo_select_queue(dev, skb); | 2246 | queue_index = ops->ndo_select_queue(dev, skb); |
2130 | queue_index = dev_cap_txqueue(dev, queue_index); | 2247 | queue_index = dev_cap_txqueue(dev, queue_index); |
2131 | } else { | 2248 | } else { |
2132 | struct sock *sk = skb->sk; | 2249 | struct sock *sk = skb->sk; |
2133 | queue_index = sk_tx_queue_get(sk); | 2250 | queue_index = sk_tx_queue_get(sk); |
2134 | if (queue_index < 0 || queue_index >= dev->real_num_tx_queues) { | ||
2135 | 2251 | ||
2136 | queue_index = 0; | 2252 | if (queue_index < 0 || skb->ooo_okay || |
2137 | if (dev->real_num_tx_queues > 1) | 2253 | queue_index >= dev->real_num_tx_queues) { |
2254 | int old_index = queue_index; | ||
2255 | |||
2256 | queue_index = get_xps_queue(dev, skb); | ||
2257 | if (queue_index < 0) | ||
2138 | queue_index = skb_tx_hash(dev, skb); | 2258 | queue_index = skb_tx_hash(dev, skb); |
2139 | 2259 | ||
2140 | if (sk) { | 2260 | if (queue_index != old_index && sk) { |
2141 | struct dst_entry *dst = rcu_dereference_check(sk->sk_dst_cache, 1); | 2261 | struct dst_entry *dst = |
2262 | rcu_dereference_check(sk->sk_dst_cache, 1); | ||
2142 | 2263 | ||
2143 | if (dst && skb_dst(skb) == dst) | 2264 | if (dst && skb_dst(skb) == dst) |
2144 | sk_tx_queue_set(sk, queue_index); | 2265 | sk_tx_queue_set(sk, queue_index); |
@@ -2712,14 +2833,6 @@ static void net_tx_action(struct softirq_action *h) | |||
2712 | } | 2833 | } |
2713 | } | 2834 | } |
2714 | 2835 | ||
2715 | static inline int deliver_skb(struct sk_buff *skb, | ||
2716 | struct packet_type *pt_prev, | ||
2717 | struct net_device *orig_dev) | ||
2718 | { | ||
2719 | atomic_inc(&skb->users); | ||
2720 | return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); | ||
2721 | } | ||
2722 | |||
2723 | #if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \ | 2836 | #if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \ |
2724 | (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)) | 2837 | (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)) |
2725 | /* This hook is defined here for ATM LANE */ | 2838 | /* This hook is defined here for ATM LANE */ |
@@ -4887,10 +5000,12 @@ static void rollback_registered_many(struct list_head *head) | |||
4887 | } | 5000 | } |
4888 | 5001 | ||
4889 | BUG_ON(dev->reg_state != NETREG_REGISTERED); | 5002 | BUG_ON(dev->reg_state != NETREG_REGISTERED); |
5003 | } | ||
4890 | 5004 | ||
4891 | /* If device is running, close it first. */ | 5005 | /* If device is running, close it first. */ |
4892 | dev_close(dev); | 5006 | dev_close_many(head); |
4893 | 5007 | ||
5008 | list_for_each_entry(dev, head, unreg_list) { | ||
4894 | /* And unlink it from device chain. */ | 5009 | /* And unlink it from device chain. */ |
4895 | unlist_netdevice(dev); | 5010 | unlist_netdevice(dev); |
4896 | 5011 | ||
@@ -4967,10 +5082,13 @@ unsigned long netdev_fix_features(unsigned long features, const char *name) | |||
4967 | } | 5082 | } |
4968 | 5083 | ||
4969 | if (features & NETIF_F_UFO) { | 5084 | if (features & NETIF_F_UFO) { |
4970 | if (!(features & NETIF_F_GEN_CSUM)) { | 5085 | /* maybe split UFO into V4 and V6? */ |
5086 | if (!((features & NETIF_F_GEN_CSUM) || | ||
5087 | (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) | ||
5088 | == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { | ||
4971 | if (name) | 5089 | if (name) |
4972 | printk(KERN_ERR "%s: Dropping NETIF_F_UFO " | 5090 | printk(KERN_ERR "%s: Dropping NETIF_F_UFO " |
4973 | "since no NETIF_F_HW_CSUM feature.\n", | 5091 | "since no checksum offload features.\n", |
4974 | name); | 5092 | name); |
4975 | features &= ~NETIF_F_UFO; | 5093 | features &= ~NETIF_F_UFO; |
4976 | } | 5094 | } |
@@ -5014,9 +5132,9 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev, | |||
5014 | } | 5132 | } |
5015 | EXPORT_SYMBOL(netif_stacked_transfer_operstate); | 5133 | EXPORT_SYMBOL(netif_stacked_transfer_operstate); |
5016 | 5134 | ||
5135 | #ifdef CONFIG_RPS | ||
5017 | static int netif_alloc_rx_queues(struct net_device *dev) | 5136 | static int netif_alloc_rx_queues(struct net_device *dev) |
5018 | { | 5137 | { |
5019 | #ifdef CONFIG_RPS | ||
5020 | unsigned int i, count = dev->num_rx_queues; | 5138 | unsigned int i, count = dev->num_rx_queues; |
5021 | struct netdev_rx_queue *rx; | 5139 | struct netdev_rx_queue *rx; |
5022 | 5140 | ||
@@ -5029,15 +5147,22 @@ static int netif_alloc_rx_queues(struct net_device *dev) | |||
5029 | } | 5147 | } |
5030 | dev->_rx = rx; | 5148 | dev->_rx = rx; |
5031 | 5149 | ||
5032 | /* | ||
5033 | * Set a pointer to first element in the array which holds the | ||
5034 | * reference count. | ||
5035 | */ | ||
5036 | for (i = 0; i < count; i++) | 5150 | for (i = 0; i < count; i++) |
5037 | rx[i].first = rx; | 5151 | rx[i].dev = dev; |
5038 | #endif | ||
5039 | return 0; | 5152 | return 0; |
5040 | } | 5153 | } |
5154 | #endif | ||
5155 | |||
5156 | static void netdev_init_one_queue(struct net_device *dev, | ||
5157 | struct netdev_queue *queue, void *_unused) | ||
5158 | { | ||
5159 | /* Initialize queue lock */ | ||
5160 | spin_lock_init(&queue->_xmit_lock); | ||
5161 | netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type); | ||
5162 | queue->xmit_lock_owner = -1; | ||
5163 | netdev_queue_numa_node_write(queue, NUMA_NO_NODE); | ||
5164 | queue->dev = dev; | ||
5165 | } | ||
5041 | 5166 | ||
5042 | static int netif_alloc_netdev_queues(struct net_device *dev) | 5167 | static int netif_alloc_netdev_queues(struct net_device *dev) |
5043 | { | 5168 | { |
@@ -5053,25 +5178,11 @@ static int netif_alloc_netdev_queues(struct net_device *dev) | |||
5053 | return -ENOMEM; | 5178 | return -ENOMEM; |
5054 | } | 5179 | } |
5055 | dev->_tx = tx; | 5180 | dev->_tx = tx; |
5056 | return 0; | ||
5057 | } | ||
5058 | 5181 | ||
5059 | static void netdev_init_one_queue(struct net_device *dev, | ||
5060 | struct netdev_queue *queue, | ||
5061 | void *_unused) | ||
5062 | { | ||
5063 | queue->dev = dev; | ||
5064 | |||
5065 | /* Initialize queue lock */ | ||
5066 | spin_lock_init(&queue->_xmit_lock); | ||
5067 | netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type); | ||
5068 | queue->xmit_lock_owner = -1; | ||
5069 | } | ||
5070 | |||
5071 | static void netdev_init_queues(struct net_device *dev) | ||
5072 | { | ||
5073 | netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); | 5182 | netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); |
5074 | spin_lock_init(&dev->tx_global_lock); | 5183 | spin_lock_init(&dev->tx_global_lock); |
5184 | |||
5185 | return 0; | ||
5075 | } | 5186 | } |
5076 | 5187 | ||
5077 | /** | 5188 | /** |
@@ -5110,16 +5221,6 @@ int register_netdevice(struct net_device *dev) | |||
5110 | 5221 | ||
5111 | dev->iflink = -1; | 5222 | dev->iflink = -1; |
5112 | 5223 | ||
5113 | ret = netif_alloc_rx_queues(dev); | ||
5114 | if (ret) | ||
5115 | goto out; | ||
5116 | |||
5117 | ret = netif_alloc_netdev_queues(dev); | ||
5118 | if (ret) | ||
5119 | goto out; | ||
5120 | |||
5121 | netdev_init_queues(dev); | ||
5122 | |||
5123 | /* Init, if this function is available */ | 5224 | /* Init, if this function is available */ |
5124 | if (dev->netdev_ops->ndo_init) { | 5225 | if (dev->netdev_ops->ndo_init) { |
5125 | ret = dev->netdev_ops->ndo_init(dev); | 5226 | ret = dev->netdev_ops->ndo_init(dev); |
@@ -5577,10 +5678,14 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, | |||
5577 | 5678 | ||
5578 | dev->num_tx_queues = queue_count; | 5679 | dev->num_tx_queues = queue_count; |
5579 | dev->real_num_tx_queues = queue_count; | 5680 | dev->real_num_tx_queues = queue_count; |
5681 | if (netif_alloc_netdev_queues(dev)) | ||
5682 | goto free_pcpu; | ||
5580 | 5683 | ||
5581 | #ifdef CONFIG_RPS | 5684 | #ifdef CONFIG_RPS |
5582 | dev->num_rx_queues = queue_count; | 5685 | dev->num_rx_queues = queue_count; |
5583 | dev->real_num_rx_queues = queue_count; | 5686 | dev->real_num_rx_queues = queue_count; |
5687 | if (netif_alloc_rx_queues(dev)) | ||
5688 | goto free_pcpu; | ||
5584 | #endif | 5689 | #endif |
5585 | 5690 | ||
5586 | dev->gso_max_size = GSO_MAX_SIZE; | 5691 | dev->gso_max_size = GSO_MAX_SIZE; |
@@ -5597,6 +5702,11 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, | |||
5597 | 5702 | ||
5598 | free_pcpu: | 5703 | free_pcpu: |
5599 | free_percpu(dev->pcpu_refcnt); | 5704 | free_percpu(dev->pcpu_refcnt); |
5705 | kfree(dev->_tx); | ||
5706 | #ifdef CONFIG_RPS | ||
5707 | kfree(dev->_rx); | ||
5708 | #endif | ||
5709 | |||
5600 | free_p: | 5710 | free_p: |
5601 | kfree(p); | 5711 | kfree(p); |
5602 | return NULL; | 5712 | return NULL; |
@@ -5618,6 +5728,9 @@ void free_netdev(struct net_device *dev) | |||
5618 | release_net(dev_net(dev)); | 5728 | release_net(dev_net(dev)); |
5619 | 5729 | ||
5620 | kfree(dev->_tx); | 5730 | kfree(dev->_tx); |
5731 | #ifdef CONFIG_RPS | ||
5732 | kfree(dev->_rx); | ||
5733 | #endif | ||
5621 | 5734 | ||
5622 | kfree(rcu_dereference_raw(dev->ingress_queue)); | 5735 | kfree(rcu_dereference_raw(dev->ingress_queue)); |
5623 | 5736 | ||
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 956a9f4971cb..17741782a345 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -891,6 +891,20 @@ static int ethtool_nway_reset(struct net_device *dev) | |||
891 | return dev->ethtool_ops->nway_reset(dev); | 891 | return dev->ethtool_ops->nway_reset(dev); |
892 | } | 892 | } |
893 | 893 | ||
894 | static int ethtool_get_link(struct net_device *dev, char __user *useraddr) | ||
895 | { | ||
896 | struct ethtool_value edata = { .cmd = ETHTOOL_GLINK }; | ||
897 | |||
898 | if (!dev->ethtool_ops->get_link) | ||
899 | return -EOPNOTSUPP; | ||
900 | |||
901 | edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev); | ||
902 | |||
903 | if (copy_to_user(useraddr, &edata, sizeof(edata))) | ||
904 | return -EFAULT; | ||
905 | return 0; | ||
906 | } | ||
907 | |||
894 | static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) | 908 | static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) |
895 | { | 909 | { |
896 | struct ethtool_eeprom eeprom; | 910 | struct ethtool_eeprom eeprom; |
@@ -1171,7 +1185,9 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr) | |||
1171 | return -EFAULT; | 1185 | return -EFAULT; |
1172 | if (edata.data && !(dev->features & NETIF_F_SG)) | 1186 | if (edata.data && !(dev->features & NETIF_F_SG)) |
1173 | return -EINVAL; | 1187 | return -EINVAL; |
1174 | if (edata.data && !(dev->features & NETIF_F_HW_CSUM)) | 1188 | if (edata.data && !((dev->features & NETIF_F_GEN_CSUM) || |
1189 | (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) | ||
1190 | == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) | ||
1175 | return -EINVAL; | 1191 | return -EINVAL; |
1176 | return dev->ethtool_ops->set_ufo(dev, edata.data); | 1192 | return dev->ethtool_ops->set_ufo(dev, edata.data); |
1177 | } | 1193 | } |
@@ -1528,8 +1544,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1528 | rc = ethtool_nway_reset(dev); | 1544 | rc = ethtool_nway_reset(dev); |
1529 | break; | 1545 | break; |
1530 | case ETHTOOL_GLINK: | 1546 | case ETHTOOL_GLINK: |
1531 | rc = ethtool_get_value(dev, useraddr, ethcmd, | 1547 | rc = ethtool_get_link(dev, useraddr); |
1532 | dev->ethtool_ops->get_link); | ||
1533 | break; | 1548 | break; |
1534 | case ETHTOOL_GEEPROM: | 1549 | case ETHTOOL_GEEPROM: |
1535 | rc = ethtool_get_eeprom(dev, useraddr); | 1550 | rc = ethtool_get_eeprom(dev, useraddr); |
diff --git a/net/core/filter.c b/net/core/filter.c index ae21a0d3c4a2..2b27d4efdd48 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -37,9 +37,69 @@ | |||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/unaligned.h> | 38 | #include <asm/unaligned.h> |
39 | #include <linux/filter.h> | 39 | #include <linux/filter.h> |
40 | #include <linux/reciprocal_div.h> | ||
41 | |||
42 | enum { | ||
43 | BPF_S_RET_K = 1, | ||
44 | BPF_S_RET_A, | ||
45 | BPF_S_ALU_ADD_K, | ||
46 | BPF_S_ALU_ADD_X, | ||
47 | BPF_S_ALU_SUB_K, | ||
48 | BPF_S_ALU_SUB_X, | ||
49 | BPF_S_ALU_MUL_K, | ||
50 | BPF_S_ALU_MUL_X, | ||
51 | BPF_S_ALU_DIV_X, | ||
52 | BPF_S_ALU_AND_K, | ||
53 | BPF_S_ALU_AND_X, | ||
54 | BPF_S_ALU_OR_K, | ||
55 | BPF_S_ALU_OR_X, | ||
56 | BPF_S_ALU_LSH_K, | ||
57 | BPF_S_ALU_LSH_X, | ||
58 | BPF_S_ALU_RSH_K, | ||
59 | BPF_S_ALU_RSH_X, | ||
60 | BPF_S_ALU_NEG, | ||
61 | BPF_S_LD_W_ABS, | ||
62 | BPF_S_LD_H_ABS, | ||
63 | BPF_S_LD_B_ABS, | ||
64 | BPF_S_LD_W_LEN, | ||
65 | BPF_S_LD_W_IND, | ||
66 | BPF_S_LD_H_IND, | ||
67 | BPF_S_LD_B_IND, | ||
68 | BPF_S_LD_IMM, | ||
69 | BPF_S_LDX_W_LEN, | ||
70 | BPF_S_LDX_B_MSH, | ||
71 | BPF_S_LDX_IMM, | ||
72 | BPF_S_MISC_TAX, | ||
73 | BPF_S_MISC_TXA, | ||
74 | BPF_S_ALU_DIV_K, | ||
75 | BPF_S_LD_MEM, | ||
76 | BPF_S_LDX_MEM, | ||
77 | BPF_S_ST, | ||
78 | BPF_S_STX, | ||
79 | BPF_S_JMP_JA, | ||
80 | BPF_S_JMP_JEQ_K, | ||
81 | BPF_S_JMP_JEQ_X, | ||
82 | BPF_S_JMP_JGE_K, | ||
83 | BPF_S_JMP_JGE_X, | ||
84 | BPF_S_JMP_JGT_K, | ||
85 | BPF_S_JMP_JGT_X, | ||
86 | BPF_S_JMP_JSET_K, | ||
87 | BPF_S_JMP_JSET_X, | ||
88 | /* Ancillary data */ | ||
89 | BPF_S_ANC_PROTOCOL, | ||
90 | BPF_S_ANC_PKTTYPE, | ||
91 | BPF_S_ANC_IFINDEX, | ||
92 | BPF_S_ANC_NLATTR, | ||
93 | BPF_S_ANC_NLATTR_NEST, | ||
94 | BPF_S_ANC_MARK, | ||
95 | BPF_S_ANC_QUEUE, | ||
96 | BPF_S_ANC_HATYPE, | ||
97 | BPF_S_ANC_RXHASH, | ||
98 | BPF_S_ANC_CPU, | ||
99 | }; | ||
40 | 100 | ||
41 | /* No hurry in this branch */ | 101 | /* No hurry in this branch */ |
42 | static void *__load_pointer(struct sk_buff *skb, int k) | 102 | static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size) |
43 | { | 103 | { |
44 | u8 *ptr = NULL; | 104 | u8 *ptr = NULL; |
45 | 105 | ||
@@ -48,21 +108,17 @@ static void *__load_pointer(struct sk_buff *skb, int k) | |||
48 | else if (k >= SKF_LL_OFF) | 108 | else if (k >= SKF_LL_OFF) |
49 | ptr = skb_mac_header(skb) + k - SKF_LL_OFF; | 109 | ptr = skb_mac_header(skb) + k - SKF_LL_OFF; |
50 | 110 | ||
51 | if (ptr >= skb->head && ptr < skb_tail_pointer(skb)) | 111 | if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) |
52 | return ptr; | 112 | return ptr; |
53 | return NULL; | 113 | return NULL; |
54 | } | 114 | } |
55 | 115 | ||
56 | static inline void *load_pointer(struct sk_buff *skb, int k, | 116 | static inline void *load_pointer(const struct sk_buff *skb, int k, |
57 | unsigned int size, void *buffer) | 117 | unsigned int size, void *buffer) |
58 | { | 118 | { |
59 | if (k >= 0) | 119 | if (k >= 0) |
60 | return skb_header_pointer(skb, k, size, buffer); | 120 | return skb_header_pointer(skb, k, size, buffer); |
61 | else { | 121 | return __load_pointer(skb, k, size); |
62 | if (k >= SKF_AD_OFF) | ||
63 | return NULL; | ||
64 | return __load_pointer(skb, k); | ||
65 | } | ||
66 | } | 122 | } |
67 | 123 | ||
68 | /** | 124 | /** |
@@ -89,7 +145,7 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) | |||
89 | rcu_read_lock_bh(); | 145 | rcu_read_lock_bh(); |
90 | filter = rcu_dereference_bh(sk->sk_filter); | 146 | filter = rcu_dereference_bh(sk->sk_filter); |
91 | if (filter) { | 147 | if (filter) { |
92 | unsigned int pkt_len = sk_run_filter(skb, filter->insns, filter->len); | 148 | unsigned int pkt_len = sk_run_filter(skb, filter->insns); |
93 | 149 | ||
94 | err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; | 150 | err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; |
95 | } | 151 | } |
@@ -103,50 +159,52 @@ EXPORT_SYMBOL(sk_filter); | |||
103 | * sk_run_filter - run a filter on a socket | 159 | * sk_run_filter - run a filter on a socket |
104 | * @skb: buffer to run the filter on | 160 | * @skb: buffer to run the filter on |
105 | * @filter: filter to apply | 161 | * @filter: filter to apply |
106 | * @flen: length of filter | ||
107 | * | 162 | * |
108 | * Decode and apply filter instructions to the skb->data. | 163 | * Decode and apply filter instructions to the skb->data. |
109 | * Return length to keep, 0 for none. skb is the data we are | 164 | * Return length to keep, 0 for none. @skb is the data we are |
110 | * filtering, filter is the array of filter instructions, and | 165 | * filtering, @filter is the array of filter instructions. |
111 | * len is the number of filter blocks in the array. | 166 | * Because all jumps are guaranteed to be before last instruction, |
167 | * and last instruction guaranteed to be a RET, we dont need to check | ||
168 | * flen. (We used to pass to this function the length of filter) | ||
112 | */ | 169 | */ |
113 | unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) | 170 | unsigned int sk_run_filter(const struct sk_buff *skb, |
171 | const struct sock_filter *fentry) | ||
114 | { | 172 | { |
115 | void *ptr; | 173 | void *ptr; |
116 | u32 A = 0; /* Accumulator */ | 174 | u32 A = 0; /* Accumulator */ |
117 | u32 X = 0; /* Index Register */ | 175 | u32 X = 0; /* Index Register */ |
118 | u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */ | 176 | u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */ |
119 | unsigned long memvalid = 0; | ||
120 | u32 tmp; | 177 | u32 tmp; |
121 | int k; | 178 | int k; |
122 | int pc; | ||
123 | 179 | ||
124 | BUILD_BUG_ON(BPF_MEMWORDS > BITS_PER_LONG); | ||
125 | /* | 180 | /* |
126 | * Process array of filter instructions. | 181 | * Process array of filter instructions. |
127 | */ | 182 | */ |
128 | for (pc = 0; pc < flen; pc++) { | 183 | for (;; fentry++) { |
129 | const struct sock_filter *fentry = &filter[pc]; | 184 | #if defined(CONFIG_X86_32) |
130 | u32 f_k = fentry->k; | 185 | #define K (fentry->k) |
186 | #else | ||
187 | const u32 K = fentry->k; | ||
188 | #endif | ||
131 | 189 | ||
132 | switch (fentry->code) { | 190 | switch (fentry->code) { |
133 | case BPF_S_ALU_ADD_X: | 191 | case BPF_S_ALU_ADD_X: |
134 | A += X; | 192 | A += X; |
135 | continue; | 193 | continue; |
136 | case BPF_S_ALU_ADD_K: | 194 | case BPF_S_ALU_ADD_K: |
137 | A += f_k; | 195 | A += K; |
138 | continue; | 196 | continue; |
139 | case BPF_S_ALU_SUB_X: | 197 | case BPF_S_ALU_SUB_X: |
140 | A -= X; | 198 | A -= X; |
141 | continue; | 199 | continue; |
142 | case BPF_S_ALU_SUB_K: | 200 | case BPF_S_ALU_SUB_K: |
143 | A -= f_k; | 201 | A -= K; |
144 | continue; | 202 | continue; |
145 | case BPF_S_ALU_MUL_X: | 203 | case BPF_S_ALU_MUL_X: |
146 | A *= X; | 204 | A *= X; |
147 | continue; | 205 | continue; |
148 | case BPF_S_ALU_MUL_K: | 206 | case BPF_S_ALU_MUL_K: |
149 | A *= f_k; | 207 | A *= K; |
150 | continue; | 208 | continue; |
151 | case BPF_S_ALU_DIV_X: | 209 | case BPF_S_ALU_DIV_X: |
152 | if (X == 0) | 210 | if (X == 0) |
@@ -154,89 +212,89 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int | |||
154 | A /= X; | 212 | A /= X; |
155 | continue; | 213 | continue; |
156 | case BPF_S_ALU_DIV_K: | 214 | case BPF_S_ALU_DIV_K: |
157 | A /= f_k; | 215 | A = reciprocal_divide(A, K); |
158 | continue; | 216 | continue; |
159 | case BPF_S_ALU_AND_X: | 217 | case BPF_S_ALU_AND_X: |
160 | A &= X; | 218 | A &= X; |
161 | continue; | 219 | continue; |
162 | case BPF_S_ALU_AND_K: | 220 | case BPF_S_ALU_AND_K: |
163 | A &= f_k; | 221 | A &= K; |
164 | continue; | 222 | continue; |
165 | case BPF_S_ALU_OR_X: | 223 | case BPF_S_ALU_OR_X: |
166 | A |= X; | 224 | A |= X; |
167 | continue; | 225 | continue; |
168 | case BPF_S_ALU_OR_K: | 226 | case BPF_S_ALU_OR_K: |
169 | A |= f_k; | 227 | A |= K; |
170 | continue; | 228 | continue; |
171 | case BPF_S_ALU_LSH_X: | 229 | case BPF_S_ALU_LSH_X: |
172 | A <<= X; | 230 | A <<= X; |
173 | continue; | 231 | continue; |
174 | case BPF_S_ALU_LSH_K: | 232 | case BPF_S_ALU_LSH_K: |
175 | A <<= f_k; | 233 | A <<= K; |
176 | continue; | 234 | continue; |
177 | case BPF_S_ALU_RSH_X: | 235 | case BPF_S_ALU_RSH_X: |
178 | A >>= X; | 236 | A >>= X; |
179 | continue; | 237 | continue; |
180 | case BPF_S_ALU_RSH_K: | 238 | case BPF_S_ALU_RSH_K: |
181 | A >>= f_k; | 239 | A >>= K; |
182 | continue; | 240 | continue; |
183 | case BPF_S_ALU_NEG: | 241 | case BPF_S_ALU_NEG: |
184 | A = -A; | 242 | A = -A; |
185 | continue; | 243 | continue; |
186 | case BPF_S_JMP_JA: | 244 | case BPF_S_JMP_JA: |
187 | pc += f_k; | 245 | fentry += K; |
188 | continue; | 246 | continue; |
189 | case BPF_S_JMP_JGT_K: | 247 | case BPF_S_JMP_JGT_K: |
190 | pc += (A > f_k) ? fentry->jt : fentry->jf; | 248 | fentry += (A > K) ? fentry->jt : fentry->jf; |
191 | continue; | 249 | continue; |
192 | case BPF_S_JMP_JGE_K: | 250 | case BPF_S_JMP_JGE_K: |
193 | pc += (A >= f_k) ? fentry->jt : fentry->jf; | 251 | fentry += (A >= K) ? fentry->jt : fentry->jf; |
194 | continue; | 252 | continue; |
195 | case BPF_S_JMP_JEQ_K: | 253 | case BPF_S_JMP_JEQ_K: |
196 | pc += (A == f_k) ? fentry->jt : fentry->jf; | 254 | fentry += (A == K) ? fentry->jt : fentry->jf; |
197 | continue; | 255 | continue; |
198 | case BPF_S_JMP_JSET_K: | 256 | case BPF_S_JMP_JSET_K: |
199 | pc += (A & f_k) ? fentry->jt : fentry->jf; | 257 | fentry += (A & K) ? fentry->jt : fentry->jf; |
200 | continue; | 258 | continue; |
201 | case BPF_S_JMP_JGT_X: | 259 | case BPF_S_JMP_JGT_X: |
202 | pc += (A > X) ? fentry->jt : fentry->jf; | 260 | fentry += (A > X) ? fentry->jt : fentry->jf; |
203 | continue; | 261 | continue; |
204 | case BPF_S_JMP_JGE_X: | 262 | case BPF_S_JMP_JGE_X: |
205 | pc += (A >= X) ? fentry->jt : fentry->jf; | 263 | fentry += (A >= X) ? fentry->jt : fentry->jf; |
206 | continue; | 264 | continue; |
207 | case BPF_S_JMP_JEQ_X: | 265 | case BPF_S_JMP_JEQ_X: |
208 | pc += (A == X) ? fentry->jt : fentry->jf; | 266 | fentry += (A == X) ? fentry->jt : fentry->jf; |
209 | continue; | 267 | continue; |
210 | case BPF_S_JMP_JSET_X: | 268 | case BPF_S_JMP_JSET_X: |
211 | pc += (A & X) ? fentry->jt : fentry->jf; | 269 | fentry += (A & X) ? fentry->jt : fentry->jf; |
212 | continue; | 270 | continue; |
213 | case BPF_S_LD_W_ABS: | 271 | case BPF_S_LD_W_ABS: |
214 | k = f_k; | 272 | k = K; |
215 | load_w: | 273 | load_w: |
216 | ptr = load_pointer(skb, k, 4, &tmp); | 274 | ptr = load_pointer(skb, k, 4, &tmp); |
217 | if (ptr != NULL) { | 275 | if (ptr != NULL) { |
218 | A = get_unaligned_be32(ptr); | 276 | A = get_unaligned_be32(ptr); |
219 | continue; | 277 | continue; |
220 | } | 278 | } |
221 | break; | 279 | return 0; |
222 | case BPF_S_LD_H_ABS: | 280 | case BPF_S_LD_H_ABS: |
223 | k = f_k; | 281 | k = K; |
224 | load_h: | 282 | load_h: |
225 | ptr = load_pointer(skb, k, 2, &tmp); | 283 | ptr = load_pointer(skb, k, 2, &tmp); |
226 | if (ptr != NULL) { | 284 | if (ptr != NULL) { |
227 | A = get_unaligned_be16(ptr); | 285 | A = get_unaligned_be16(ptr); |
228 | continue; | 286 | continue; |
229 | } | 287 | } |
230 | break; | 288 | return 0; |
231 | case BPF_S_LD_B_ABS: | 289 | case BPF_S_LD_B_ABS: |
232 | k = f_k; | 290 | k = K; |
233 | load_b: | 291 | load_b: |
234 | ptr = load_pointer(skb, k, 1, &tmp); | 292 | ptr = load_pointer(skb, k, 1, &tmp); |
235 | if (ptr != NULL) { | 293 | if (ptr != NULL) { |
236 | A = *(u8 *)ptr; | 294 | A = *(u8 *)ptr; |
237 | continue; | 295 | continue; |
238 | } | 296 | } |
239 | break; | 297 | return 0; |
240 | case BPF_S_LD_W_LEN: | 298 | case BPF_S_LD_W_LEN: |
241 | A = skb->len; | 299 | A = skb->len; |
242 | continue; | 300 | continue; |
@@ -244,34 +302,32 @@ load_b: | |||
244 | X = skb->len; | 302 | X = skb->len; |
245 | continue; | 303 | continue; |
246 | case BPF_S_LD_W_IND: | 304 | case BPF_S_LD_W_IND: |
247 | k = X + f_k; | 305 | k = X + K; |
248 | goto load_w; | 306 | goto load_w; |
249 | case BPF_S_LD_H_IND: | 307 | case BPF_S_LD_H_IND: |
250 | k = X + f_k; | 308 | k = X + K; |
251 | goto load_h; | 309 | goto load_h; |
252 | case BPF_S_LD_B_IND: | 310 | case BPF_S_LD_B_IND: |
253 | k = X + f_k; | 311 | k = X + K; |
254 | goto load_b; | 312 | goto load_b; |
255 | case BPF_S_LDX_B_MSH: | 313 | case BPF_S_LDX_B_MSH: |
256 | ptr = load_pointer(skb, f_k, 1, &tmp); | 314 | ptr = load_pointer(skb, K, 1, &tmp); |
257 | if (ptr != NULL) { | 315 | if (ptr != NULL) { |
258 | X = (*(u8 *)ptr & 0xf) << 2; | 316 | X = (*(u8 *)ptr & 0xf) << 2; |
259 | continue; | 317 | continue; |
260 | } | 318 | } |
261 | return 0; | 319 | return 0; |
262 | case BPF_S_LD_IMM: | 320 | case BPF_S_LD_IMM: |
263 | A = f_k; | 321 | A = K; |
264 | continue; | 322 | continue; |
265 | case BPF_S_LDX_IMM: | 323 | case BPF_S_LDX_IMM: |
266 | X = f_k; | 324 | X = K; |
267 | continue; | 325 | continue; |
268 | case BPF_S_LD_MEM: | 326 | case BPF_S_LD_MEM: |
269 | A = (memvalid & (1UL << f_k)) ? | 327 | A = mem[K]; |
270 | mem[f_k] : 0; | ||
271 | continue; | 328 | continue; |
272 | case BPF_S_LDX_MEM: | 329 | case BPF_S_LDX_MEM: |
273 | X = (memvalid & (1UL << f_k)) ? | 330 | X = mem[K]; |
274 | mem[f_k] : 0; | ||
275 | continue; | 331 | continue; |
276 | case BPF_S_MISC_TAX: | 332 | case BPF_S_MISC_TAX: |
277 | X = A; | 333 | X = A; |
@@ -280,50 +336,44 @@ load_b: | |||
280 | A = X; | 336 | A = X; |
281 | continue; | 337 | continue; |
282 | case BPF_S_RET_K: | 338 | case BPF_S_RET_K: |
283 | return f_k; | 339 | return K; |
284 | case BPF_S_RET_A: | 340 | case BPF_S_RET_A: |
285 | return A; | 341 | return A; |
286 | case BPF_S_ST: | 342 | case BPF_S_ST: |
287 | memvalid |= 1UL << f_k; | 343 | mem[K] = A; |
288 | mem[f_k] = A; | ||
289 | continue; | 344 | continue; |
290 | case BPF_S_STX: | 345 | case BPF_S_STX: |
291 | memvalid |= 1UL << f_k; | 346 | mem[K] = X; |
292 | mem[f_k] = X; | ||
293 | continue; | 347 | continue; |
294 | default: | 348 | case BPF_S_ANC_PROTOCOL: |
295 | WARN_ON(1); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Handle ancillary data, which are impossible | ||
301 | * (or very difficult) to get parsing packet contents. | ||
302 | */ | ||
303 | switch (k-SKF_AD_OFF) { | ||
304 | case SKF_AD_PROTOCOL: | ||
305 | A = ntohs(skb->protocol); | 349 | A = ntohs(skb->protocol); |
306 | continue; | 350 | continue; |
307 | case SKF_AD_PKTTYPE: | 351 | case BPF_S_ANC_PKTTYPE: |
308 | A = skb->pkt_type; | 352 | A = skb->pkt_type; |
309 | continue; | 353 | continue; |
310 | case SKF_AD_IFINDEX: | 354 | case BPF_S_ANC_IFINDEX: |
311 | if (!skb->dev) | 355 | if (!skb->dev) |
312 | return 0; | 356 | return 0; |
313 | A = skb->dev->ifindex; | 357 | A = skb->dev->ifindex; |
314 | continue; | 358 | continue; |
315 | case SKF_AD_MARK: | 359 | case BPF_S_ANC_MARK: |
316 | A = skb->mark; | 360 | A = skb->mark; |
317 | continue; | 361 | continue; |
318 | case SKF_AD_QUEUE: | 362 | case BPF_S_ANC_QUEUE: |
319 | A = skb->queue_mapping; | 363 | A = skb->queue_mapping; |
320 | continue; | 364 | continue; |
321 | case SKF_AD_HATYPE: | 365 | case BPF_S_ANC_HATYPE: |
322 | if (!skb->dev) | 366 | if (!skb->dev) |
323 | return 0; | 367 | return 0; |
324 | A = skb->dev->type; | 368 | A = skb->dev->type; |
325 | continue; | 369 | continue; |
326 | case SKF_AD_NLATTR: { | 370 | case BPF_S_ANC_RXHASH: |
371 | A = skb->rxhash; | ||
372 | continue; | ||
373 | case BPF_S_ANC_CPU: | ||
374 | A = raw_smp_processor_id(); | ||
375 | continue; | ||
376 | case BPF_S_ANC_NLATTR: { | ||
327 | struct nlattr *nla; | 377 | struct nlattr *nla; |
328 | 378 | ||
329 | if (skb_is_nonlinear(skb)) | 379 | if (skb_is_nonlinear(skb)) |
@@ -339,7 +389,7 @@ load_b: | |||
339 | A = 0; | 389 | A = 0; |
340 | continue; | 390 | continue; |
341 | } | 391 | } |
342 | case SKF_AD_NLATTR_NEST: { | 392 | case BPF_S_ANC_NLATTR_NEST: { |
343 | struct nlattr *nla; | 393 | struct nlattr *nla; |
344 | 394 | ||
345 | if (skb_is_nonlinear(skb)) | 395 | if (skb_is_nonlinear(skb)) |
@@ -359,6 +409,7 @@ load_b: | |||
359 | continue; | 409 | continue; |
360 | } | 410 | } |
361 | default: | 411 | default: |
412 | WARN_ON(1); | ||
362 | return 0; | 413 | return 0; |
363 | } | 414 | } |
364 | } | 415 | } |
@@ -367,6 +418,66 @@ load_b: | |||
367 | } | 418 | } |
368 | EXPORT_SYMBOL(sk_run_filter); | 419 | EXPORT_SYMBOL(sk_run_filter); |
369 | 420 | ||
421 | /* | ||
422 | * Security : | ||
423 | * A BPF program is able to use 16 cells of memory to store intermediate | ||
424 | * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter()) | ||
425 | * As we dont want to clear mem[] array for each packet going through | ||
426 | * sk_run_filter(), we check that filter loaded by user never try to read | ||
427 | * a cell if not previously written, and we check all branches to be sure | ||
428 | * a malicious user doesnt try to abuse us. | ||
429 | */ | ||
430 | static int check_load_and_stores(struct sock_filter *filter, int flen) | ||
431 | { | ||
432 | u16 *masks, memvalid = 0; /* one bit per cell, 16 cells */ | ||
433 | int pc, ret = 0; | ||
434 | |||
435 | BUILD_BUG_ON(BPF_MEMWORDS > 16); | ||
436 | masks = kmalloc(flen * sizeof(*masks), GFP_KERNEL); | ||
437 | if (!masks) | ||
438 | return -ENOMEM; | ||
439 | memset(masks, 0xff, flen * sizeof(*masks)); | ||
440 | |||
441 | for (pc = 0; pc < flen; pc++) { | ||
442 | memvalid &= masks[pc]; | ||
443 | |||
444 | switch (filter[pc].code) { | ||
445 | case BPF_S_ST: | ||
446 | case BPF_S_STX: | ||
447 | memvalid |= (1 << filter[pc].k); | ||
448 | break; | ||
449 | case BPF_S_LD_MEM: | ||
450 | case BPF_S_LDX_MEM: | ||
451 | if (!(memvalid & (1 << filter[pc].k))) { | ||
452 | ret = -EINVAL; | ||
453 | goto error; | ||
454 | } | ||
455 | break; | ||
456 | case BPF_S_JMP_JA: | ||
457 | /* a jump must set masks on target */ | ||
458 | masks[pc + 1 + filter[pc].k] &= memvalid; | ||
459 | memvalid = ~0; | ||
460 | break; | ||
461 | case BPF_S_JMP_JEQ_K: | ||
462 | case BPF_S_JMP_JEQ_X: | ||
463 | case BPF_S_JMP_JGE_K: | ||
464 | case BPF_S_JMP_JGE_X: | ||
465 | case BPF_S_JMP_JGT_K: | ||
466 | case BPF_S_JMP_JGT_X: | ||
467 | case BPF_S_JMP_JSET_X: | ||
468 | case BPF_S_JMP_JSET_K: | ||
469 | /* a jump must set masks on targets */ | ||
470 | masks[pc + 1 + filter[pc].jt] &= memvalid; | ||
471 | masks[pc + 1 + filter[pc].jf] &= memvalid; | ||
472 | memvalid = ~0; | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | error: | ||
477 | kfree(masks); | ||
478 | return ret; | ||
479 | } | ||
480 | |||
370 | /** | 481 | /** |
371 | * sk_chk_filter - verify socket filter code | 482 | * sk_chk_filter - verify socket filter code |
372 | * @filter: filter to verify | 483 | * @filter: filter to verify |
@@ -383,7 +494,57 @@ EXPORT_SYMBOL(sk_run_filter); | |||
383 | */ | 494 | */ |
384 | int sk_chk_filter(struct sock_filter *filter, int flen) | 495 | int sk_chk_filter(struct sock_filter *filter, int flen) |
385 | { | 496 | { |
386 | struct sock_filter *ftest; | 497 | /* |
498 | * Valid instructions are initialized to non-0. | ||
499 | * Invalid instructions are initialized to 0. | ||
500 | */ | ||
501 | static const u8 codes[] = { | ||
502 | [BPF_ALU|BPF_ADD|BPF_K] = BPF_S_ALU_ADD_K, | ||
503 | [BPF_ALU|BPF_ADD|BPF_X] = BPF_S_ALU_ADD_X, | ||
504 | [BPF_ALU|BPF_SUB|BPF_K] = BPF_S_ALU_SUB_K, | ||
505 | [BPF_ALU|BPF_SUB|BPF_X] = BPF_S_ALU_SUB_X, | ||
506 | [BPF_ALU|BPF_MUL|BPF_K] = BPF_S_ALU_MUL_K, | ||
507 | [BPF_ALU|BPF_MUL|BPF_X] = BPF_S_ALU_MUL_X, | ||
508 | [BPF_ALU|BPF_DIV|BPF_X] = BPF_S_ALU_DIV_X, | ||
509 | [BPF_ALU|BPF_AND|BPF_K] = BPF_S_ALU_AND_K, | ||
510 | [BPF_ALU|BPF_AND|BPF_X] = BPF_S_ALU_AND_X, | ||
511 | [BPF_ALU|BPF_OR|BPF_K] = BPF_S_ALU_OR_K, | ||
512 | [BPF_ALU|BPF_OR|BPF_X] = BPF_S_ALU_OR_X, | ||
513 | [BPF_ALU|BPF_LSH|BPF_K] = BPF_S_ALU_LSH_K, | ||
514 | [BPF_ALU|BPF_LSH|BPF_X] = BPF_S_ALU_LSH_X, | ||
515 | [BPF_ALU|BPF_RSH|BPF_K] = BPF_S_ALU_RSH_K, | ||
516 | [BPF_ALU|BPF_RSH|BPF_X] = BPF_S_ALU_RSH_X, | ||
517 | [BPF_ALU|BPF_NEG] = BPF_S_ALU_NEG, | ||
518 | [BPF_LD|BPF_W|BPF_ABS] = BPF_S_LD_W_ABS, | ||
519 | [BPF_LD|BPF_H|BPF_ABS] = BPF_S_LD_H_ABS, | ||
520 | [BPF_LD|BPF_B|BPF_ABS] = BPF_S_LD_B_ABS, | ||
521 | [BPF_LD|BPF_W|BPF_LEN] = BPF_S_LD_W_LEN, | ||
522 | [BPF_LD|BPF_W|BPF_IND] = BPF_S_LD_W_IND, | ||
523 | [BPF_LD|BPF_H|BPF_IND] = BPF_S_LD_H_IND, | ||
524 | [BPF_LD|BPF_B|BPF_IND] = BPF_S_LD_B_IND, | ||
525 | [BPF_LD|BPF_IMM] = BPF_S_LD_IMM, | ||
526 | [BPF_LDX|BPF_W|BPF_LEN] = BPF_S_LDX_W_LEN, | ||
527 | [BPF_LDX|BPF_B|BPF_MSH] = BPF_S_LDX_B_MSH, | ||
528 | [BPF_LDX|BPF_IMM] = BPF_S_LDX_IMM, | ||
529 | [BPF_MISC|BPF_TAX] = BPF_S_MISC_TAX, | ||
530 | [BPF_MISC|BPF_TXA] = BPF_S_MISC_TXA, | ||
531 | [BPF_RET|BPF_K] = BPF_S_RET_K, | ||
532 | [BPF_RET|BPF_A] = BPF_S_RET_A, | ||
533 | [BPF_ALU|BPF_DIV|BPF_K] = BPF_S_ALU_DIV_K, | ||
534 | [BPF_LD|BPF_MEM] = BPF_S_LD_MEM, | ||
535 | [BPF_LDX|BPF_MEM] = BPF_S_LDX_MEM, | ||
536 | [BPF_ST] = BPF_S_ST, | ||
537 | [BPF_STX] = BPF_S_STX, | ||
538 | [BPF_JMP|BPF_JA] = BPF_S_JMP_JA, | ||
539 | [BPF_JMP|BPF_JEQ|BPF_K] = BPF_S_JMP_JEQ_K, | ||
540 | [BPF_JMP|BPF_JEQ|BPF_X] = BPF_S_JMP_JEQ_X, | ||
541 | [BPF_JMP|BPF_JGE|BPF_K] = BPF_S_JMP_JGE_K, | ||
542 | [BPF_JMP|BPF_JGE|BPF_X] = BPF_S_JMP_JGE_X, | ||
543 | [BPF_JMP|BPF_JGT|BPF_K] = BPF_S_JMP_JGT_K, | ||
544 | [BPF_JMP|BPF_JGT|BPF_X] = BPF_S_JMP_JGT_X, | ||
545 | [BPF_JMP|BPF_JSET|BPF_K] = BPF_S_JMP_JSET_K, | ||
546 | [BPF_JMP|BPF_JSET|BPF_X] = BPF_S_JMP_JSET_X, | ||
547 | }; | ||
387 | int pc; | 548 | int pc; |
388 | 549 | ||
389 | if (flen == 0 || flen > BPF_MAXINSNS) | 550 | if (flen == 0 || flen > BPF_MAXINSNS) |
@@ -391,136 +552,31 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
391 | 552 | ||
392 | /* check the filter code now */ | 553 | /* check the filter code now */ |
393 | for (pc = 0; pc < flen; pc++) { | 554 | for (pc = 0; pc < flen; pc++) { |
394 | ftest = &filter[pc]; | 555 | struct sock_filter *ftest = &filter[pc]; |
395 | 556 | u16 code = ftest->code; | |
396 | /* Only allow valid instructions */ | ||
397 | switch (ftest->code) { | ||
398 | case BPF_ALU|BPF_ADD|BPF_K: | ||
399 | ftest->code = BPF_S_ALU_ADD_K; | ||
400 | break; | ||
401 | case BPF_ALU|BPF_ADD|BPF_X: | ||
402 | ftest->code = BPF_S_ALU_ADD_X; | ||
403 | break; | ||
404 | case BPF_ALU|BPF_SUB|BPF_K: | ||
405 | ftest->code = BPF_S_ALU_SUB_K; | ||
406 | break; | ||
407 | case BPF_ALU|BPF_SUB|BPF_X: | ||
408 | ftest->code = BPF_S_ALU_SUB_X; | ||
409 | break; | ||
410 | case BPF_ALU|BPF_MUL|BPF_K: | ||
411 | ftest->code = BPF_S_ALU_MUL_K; | ||
412 | break; | ||
413 | case BPF_ALU|BPF_MUL|BPF_X: | ||
414 | ftest->code = BPF_S_ALU_MUL_X; | ||
415 | break; | ||
416 | case BPF_ALU|BPF_DIV|BPF_X: | ||
417 | ftest->code = BPF_S_ALU_DIV_X; | ||
418 | break; | ||
419 | case BPF_ALU|BPF_AND|BPF_K: | ||
420 | ftest->code = BPF_S_ALU_AND_K; | ||
421 | break; | ||
422 | case BPF_ALU|BPF_AND|BPF_X: | ||
423 | ftest->code = BPF_S_ALU_AND_X; | ||
424 | break; | ||
425 | case BPF_ALU|BPF_OR|BPF_K: | ||
426 | ftest->code = BPF_S_ALU_OR_K; | ||
427 | break; | ||
428 | case BPF_ALU|BPF_OR|BPF_X: | ||
429 | ftest->code = BPF_S_ALU_OR_X; | ||
430 | break; | ||
431 | case BPF_ALU|BPF_LSH|BPF_K: | ||
432 | ftest->code = BPF_S_ALU_LSH_K; | ||
433 | break; | ||
434 | case BPF_ALU|BPF_LSH|BPF_X: | ||
435 | ftest->code = BPF_S_ALU_LSH_X; | ||
436 | break; | ||
437 | case BPF_ALU|BPF_RSH|BPF_K: | ||
438 | ftest->code = BPF_S_ALU_RSH_K; | ||
439 | break; | ||
440 | case BPF_ALU|BPF_RSH|BPF_X: | ||
441 | ftest->code = BPF_S_ALU_RSH_X; | ||
442 | break; | ||
443 | case BPF_ALU|BPF_NEG: | ||
444 | ftest->code = BPF_S_ALU_NEG; | ||
445 | break; | ||
446 | case BPF_LD|BPF_W|BPF_ABS: | ||
447 | ftest->code = BPF_S_LD_W_ABS; | ||
448 | break; | ||
449 | case BPF_LD|BPF_H|BPF_ABS: | ||
450 | ftest->code = BPF_S_LD_H_ABS; | ||
451 | break; | ||
452 | case BPF_LD|BPF_B|BPF_ABS: | ||
453 | ftest->code = BPF_S_LD_B_ABS; | ||
454 | break; | ||
455 | case BPF_LD|BPF_W|BPF_LEN: | ||
456 | ftest->code = BPF_S_LD_W_LEN; | ||
457 | break; | ||
458 | case BPF_LD|BPF_W|BPF_IND: | ||
459 | ftest->code = BPF_S_LD_W_IND; | ||
460 | break; | ||
461 | case BPF_LD|BPF_H|BPF_IND: | ||
462 | ftest->code = BPF_S_LD_H_IND; | ||
463 | break; | ||
464 | case BPF_LD|BPF_B|BPF_IND: | ||
465 | ftest->code = BPF_S_LD_B_IND; | ||
466 | break; | ||
467 | case BPF_LD|BPF_IMM: | ||
468 | ftest->code = BPF_S_LD_IMM; | ||
469 | break; | ||
470 | case BPF_LDX|BPF_W|BPF_LEN: | ||
471 | ftest->code = BPF_S_LDX_W_LEN; | ||
472 | break; | ||
473 | case BPF_LDX|BPF_B|BPF_MSH: | ||
474 | ftest->code = BPF_S_LDX_B_MSH; | ||
475 | break; | ||
476 | case BPF_LDX|BPF_IMM: | ||
477 | ftest->code = BPF_S_LDX_IMM; | ||
478 | break; | ||
479 | case BPF_MISC|BPF_TAX: | ||
480 | ftest->code = BPF_S_MISC_TAX; | ||
481 | break; | ||
482 | case BPF_MISC|BPF_TXA: | ||
483 | ftest->code = BPF_S_MISC_TXA; | ||
484 | break; | ||
485 | case BPF_RET|BPF_K: | ||
486 | ftest->code = BPF_S_RET_K; | ||
487 | break; | ||
488 | case BPF_RET|BPF_A: | ||
489 | ftest->code = BPF_S_RET_A; | ||
490 | break; | ||
491 | 557 | ||
558 | if (code >= ARRAY_SIZE(codes)) | ||
559 | return -EINVAL; | ||
560 | code = codes[code]; | ||
561 | if (!code) | ||
562 | return -EINVAL; | ||
492 | /* Some instructions need special checks */ | 563 | /* Some instructions need special checks */ |
493 | 564 | switch (code) { | |
565 | case BPF_S_ALU_DIV_K: | ||
494 | /* check for division by zero */ | 566 | /* check for division by zero */ |
495 | case BPF_ALU|BPF_DIV|BPF_K: | ||
496 | if (ftest->k == 0) | 567 | if (ftest->k == 0) |
497 | return -EINVAL; | 568 | return -EINVAL; |
498 | ftest->code = BPF_S_ALU_DIV_K; | 569 | ftest->k = reciprocal_value(ftest->k); |
499 | break; | ||
500 | |||
501 | /* check for invalid memory addresses */ | ||
502 | case BPF_LD|BPF_MEM: | ||
503 | if (ftest->k >= BPF_MEMWORDS) | ||
504 | return -EINVAL; | ||
505 | ftest->code = BPF_S_LD_MEM; | ||
506 | break; | ||
507 | case BPF_LDX|BPF_MEM: | ||
508 | if (ftest->k >= BPF_MEMWORDS) | ||
509 | return -EINVAL; | ||
510 | ftest->code = BPF_S_LDX_MEM; | ||
511 | break; | ||
512 | case BPF_ST: | ||
513 | if (ftest->k >= BPF_MEMWORDS) | ||
514 | return -EINVAL; | ||
515 | ftest->code = BPF_S_ST; | ||
516 | break; | 570 | break; |
517 | case BPF_STX: | 571 | case BPF_S_LD_MEM: |
572 | case BPF_S_LDX_MEM: | ||
573 | case BPF_S_ST: | ||
574 | case BPF_S_STX: | ||
575 | /* check for invalid memory addresses */ | ||
518 | if (ftest->k >= BPF_MEMWORDS) | 576 | if (ftest->k >= BPF_MEMWORDS) |
519 | return -EINVAL; | 577 | return -EINVAL; |
520 | ftest->code = BPF_S_STX; | ||
521 | break; | 578 | break; |
522 | 579 | case BPF_S_JMP_JA: | |
523 | case BPF_JMP|BPF_JA: | ||
524 | /* | 580 | /* |
525 | * Note, the large ftest->k might cause loops. | 581 | * Note, the large ftest->k might cause loops. |
526 | * Compare this with conditional jumps below, | 582 | * Compare this with conditional jumps below, |
@@ -528,40 +584,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
528 | */ | 584 | */ |
529 | if (ftest->k >= (unsigned)(flen-pc-1)) | 585 | if (ftest->k >= (unsigned)(flen-pc-1)) |
530 | return -EINVAL; | 586 | return -EINVAL; |
531 | ftest->code = BPF_S_JMP_JA; | ||
532 | break; | ||
533 | |||
534 | case BPF_JMP|BPF_JEQ|BPF_K: | ||
535 | ftest->code = BPF_S_JMP_JEQ_K; | ||
536 | break; | ||
537 | case BPF_JMP|BPF_JEQ|BPF_X: | ||
538 | ftest->code = BPF_S_JMP_JEQ_X; | ||
539 | break; | ||
540 | case BPF_JMP|BPF_JGE|BPF_K: | ||
541 | ftest->code = BPF_S_JMP_JGE_K; | ||
542 | break; | ||
543 | case BPF_JMP|BPF_JGE|BPF_X: | ||
544 | ftest->code = BPF_S_JMP_JGE_X; | ||
545 | break; | ||
546 | case BPF_JMP|BPF_JGT|BPF_K: | ||
547 | ftest->code = BPF_S_JMP_JGT_K; | ||
548 | break; | ||
549 | case BPF_JMP|BPF_JGT|BPF_X: | ||
550 | ftest->code = BPF_S_JMP_JGT_X; | ||
551 | break; | ||
552 | case BPF_JMP|BPF_JSET|BPF_K: | ||
553 | ftest->code = BPF_S_JMP_JSET_K; | ||
554 | break; | ||
555 | case BPF_JMP|BPF_JSET|BPF_X: | ||
556 | ftest->code = BPF_S_JMP_JSET_X; | ||
557 | break; | 587 | break; |
558 | |||
559 | default: | ||
560 | return -EINVAL; | ||
561 | } | ||
562 | |||
563 | /* for conditionals both must be safe */ | ||
564 | switch (ftest->code) { | ||
565 | case BPF_S_JMP_JEQ_K: | 588 | case BPF_S_JMP_JEQ_K: |
566 | case BPF_S_JMP_JEQ_X: | 589 | case BPF_S_JMP_JEQ_X: |
567 | case BPF_S_JMP_JGE_K: | 590 | case BPF_S_JMP_JGE_K: |
@@ -570,21 +593,40 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
570 | case BPF_S_JMP_JGT_X: | 593 | case BPF_S_JMP_JGT_X: |
571 | case BPF_S_JMP_JSET_X: | 594 | case BPF_S_JMP_JSET_X: |
572 | case BPF_S_JMP_JSET_K: | 595 | case BPF_S_JMP_JSET_K: |
596 | /* for conditionals both must be safe */ | ||
573 | if (pc + ftest->jt + 1 >= flen || | 597 | if (pc + ftest->jt + 1 >= flen || |
574 | pc + ftest->jf + 1 >= flen) | 598 | pc + ftest->jf + 1 >= flen) |
575 | return -EINVAL; | 599 | return -EINVAL; |
600 | break; | ||
601 | case BPF_S_LD_W_ABS: | ||
602 | case BPF_S_LD_H_ABS: | ||
603 | case BPF_S_LD_B_ABS: | ||
604 | #define ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE: \ | ||
605 | code = BPF_S_ANC_##CODE; \ | ||
606 | break | ||
607 | switch (ftest->k) { | ||
608 | ANCILLARY(PROTOCOL); | ||
609 | ANCILLARY(PKTTYPE); | ||
610 | ANCILLARY(IFINDEX); | ||
611 | ANCILLARY(NLATTR); | ||
612 | ANCILLARY(NLATTR_NEST); | ||
613 | ANCILLARY(MARK); | ||
614 | ANCILLARY(QUEUE); | ||
615 | ANCILLARY(HATYPE); | ||
616 | ANCILLARY(RXHASH); | ||
617 | ANCILLARY(CPU); | ||
618 | } | ||
576 | } | 619 | } |
620 | ftest->code = code; | ||
577 | } | 621 | } |
578 | 622 | ||
579 | /* last instruction must be a RET code */ | 623 | /* last instruction must be a RET code */ |
580 | switch (filter[flen - 1].code) { | 624 | switch (filter[flen - 1].code) { |
581 | case BPF_S_RET_K: | 625 | case BPF_S_RET_K: |
582 | case BPF_S_RET_A: | 626 | case BPF_S_RET_A: |
583 | return 0; | 627 | return check_load_and_stores(filter, flen); |
584 | break; | 628 | } |
585 | default: | 629 | return -EINVAL; |
586 | return -EINVAL; | ||
587 | } | ||
588 | } | 630 | } |
589 | EXPORT_SYMBOL(sk_chk_filter); | 631 | EXPORT_SYMBOL(sk_chk_filter); |
590 | 632 | ||
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 8cc8f9a79db9..60a902913429 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | #define NEIGH_PRINTK(x...) printk(x) | 42 | #define NEIGH_PRINTK(x...) printk(x) |
43 | #define NEIGH_NOPRINTK(x...) do { ; } while(0) | 43 | #define NEIGH_NOPRINTK(x...) do { ; } while(0) |
44 | #define NEIGH_PRINTK0 NEIGH_PRINTK | ||
45 | #define NEIGH_PRINTK1 NEIGH_NOPRINTK | 44 | #define NEIGH_PRINTK1 NEIGH_NOPRINTK |
46 | #define NEIGH_PRINTK2 NEIGH_NOPRINTK | 45 | #define NEIGH_PRINTK2 NEIGH_NOPRINTK |
47 | 46 | ||
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7f902cad10f8..e23c01be5a5b 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -706,7 +706,6 @@ static struct attribute *rx_queue_default_attrs[] = { | |||
706 | static void rx_queue_release(struct kobject *kobj) | 706 | static void rx_queue_release(struct kobject *kobj) |
707 | { | 707 | { |
708 | struct netdev_rx_queue *queue = to_rx_queue(kobj); | 708 | struct netdev_rx_queue *queue = to_rx_queue(kobj); |
709 | struct netdev_rx_queue *first = queue->first; | ||
710 | struct rps_map *map; | 709 | struct rps_map *map; |
711 | struct rps_dev_flow_table *flow_table; | 710 | struct rps_dev_flow_table *flow_table; |
712 | 711 | ||
@@ -723,10 +722,8 @@ static void rx_queue_release(struct kobject *kobj) | |||
723 | call_rcu(&flow_table->rcu, rps_dev_flow_table_release); | 722 | call_rcu(&flow_table->rcu, rps_dev_flow_table_release); |
724 | } | 723 | } |
725 | 724 | ||
726 | if (atomic_dec_and_test(&first->count)) | 725 | memset(kobj, 0, sizeof(*kobj)); |
727 | kfree(first); | 726 | dev_put(queue->dev); |
728 | else | ||
729 | memset(kobj, 0, sizeof(*kobj)); | ||
730 | } | 727 | } |
731 | 728 | ||
732 | static struct kobj_type rx_queue_ktype = { | 729 | static struct kobj_type rx_queue_ktype = { |
@@ -738,7 +735,6 @@ static struct kobj_type rx_queue_ktype = { | |||
738 | static int rx_queue_add_kobject(struct net_device *net, int index) | 735 | static int rx_queue_add_kobject(struct net_device *net, int index) |
739 | { | 736 | { |
740 | struct netdev_rx_queue *queue = net->_rx + index; | 737 | struct netdev_rx_queue *queue = net->_rx + index; |
741 | struct netdev_rx_queue *first = queue->first; | ||
742 | struct kobject *kobj = &queue->kobj; | 738 | struct kobject *kobj = &queue->kobj; |
743 | int error = 0; | 739 | int error = 0; |
744 | 740 | ||
@@ -751,14 +747,16 @@ static int rx_queue_add_kobject(struct net_device *net, int index) | |||
751 | } | 747 | } |
752 | 748 | ||
753 | kobject_uevent(kobj, KOBJ_ADD); | 749 | kobject_uevent(kobj, KOBJ_ADD); |
754 | atomic_inc(&first->count); | 750 | dev_hold(queue->dev); |
755 | 751 | ||
756 | return error; | 752 | return error; |
757 | } | 753 | } |
754 | #endif /* CONFIG_RPS */ | ||
758 | 755 | ||
759 | int | 756 | int |
760 | net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | 757 | net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) |
761 | { | 758 | { |
759 | #ifdef CONFIG_RPS | ||
762 | int i; | 760 | int i; |
763 | int error = 0; | 761 | int error = 0; |
764 | 762 | ||
@@ -774,23 +772,423 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | |||
774 | kobject_put(&net->_rx[i].kobj); | 772 | kobject_put(&net->_rx[i].kobj); |
775 | 773 | ||
776 | return error; | 774 | return error; |
775 | #else | ||
776 | return 0; | ||
777 | #endif | ||
778 | } | ||
779 | |||
780 | #ifdef CONFIG_XPS | ||
781 | /* | ||
782 | * netdev_queue sysfs structures and functions. | ||
783 | */ | ||
784 | struct netdev_queue_attribute { | ||
785 | struct attribute attr; | ||
786 | ssize_t (*show)(struct netdev_queue *queue, | ||
787 | struct netdev_queue_attribute *attr, char *buf); | ||
788 | ssize_t (*store)(struct netdev_queue *queue, | ||
789 | struct netdev_queue_attribute *attr, const char *buf, size_t len); | ||
790 | }; | ||
791 | #define to_netdev_queue_attr(_attr) container_of(_attr, \ | ||
792 | struct netdev_queue_attribute, attr) | ||
793 | |||
794 | #define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) | ||
795 | |||
796 | static ssize_t netdev_queue_attr_show(struct kobject *kobj, | ||
797 | struct attribute *attr, char *buf) | ||
798 | { | ||
799 | struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr); | ||
800 | struct netdev_queue *queue = to_netdev_queue(kobj); | ||
801 | |||
802 | if (!attribute->show) | ||
803 | return -EIO; | ||
804 | |||
805 | return attribute->show(queue, attribute, buf); | ||
777 | } | 806 | } |
778 | 807 | ||
779 | static int rx_queue_register_kobjects(struct net_device *net) | 808 | static ssize_t netdev_queue_attr_store(struct kobject *kobj, |
809 | struct attribute *attr, | ||
810 | const char *buf, size_t count) | ||
780 | { | 811 | { |
812 | struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr); | ||
813 | struct netdev_queue *queue = to_netdev_queue(kobj); | ||
814 | |||
815 | if (!attribute->store) | ||
816 | return -EIO; | ||
817 | |||
818 | return attribute->store(queue, attribute, buf, count); | ||
819 | } | ||
820 | |||
821 | static const struct sysfs_ops netdev_queue_sysfs_ops = { | ||
822 | .show = netdev_queue_attr_show, | ||
823 | .store = netdev_queue_attr_store, | ||
824 | }; | ||
825 | |||
826 | static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue) | ||
827 | { | ||
828 | struct net_device *dev = queue->dev; | ||
829 | int i; | ||
830 | |||
831 | for (i = 0; i < dev->num_tx_queues; i++) | ||
832 | if (queue == &dev->_tx[i]) | ||
833 | break; | ||
834 | |||
835 | BUG_ON(i >= dev->num_tx_queues); | ||
836 | |||
837 | return i; | ||
838 | } | ||
839 | |||
840 | |||
841 | static ssize_t show_xps_map(struct netdev_queue *queue, | ||
842 | struct netdev_queue_attribute *attribute, char *buf) | ||
843 | { | ||
844 | struct net_device *dev = queue->dev; | ||
845 | struct xps_dev_maps *dev_maps; | ||
846 | cpumask_var_t mask; | ||
847 | unsigned long index; | ||
848 | size_t len = 0; | ||
849 | int i; | ||
850 | |||
851 | if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) | ||
852 | return -ENOMEM; | ||
853 | |||
854 | index = get_netdev_queue_index(queue); | ||
855 | |||
856 | rcu_read_lock(); | ||
857 | dev_maps = rcu_dereference(dev->xps_maps); | ||
858 | if (dev_maps) { | ||
859 | for_each_possible_cpu(i) { | ||
860 | struct xps_map *map = | ||
861 | rcu_dereference(dev_maps->cpu_map[i]); | ||
862 | if (map) { | ||
863 | int j; | ||
864 | for (j = 0; j < map->len; j++) { | ||
865 | if (map->queues[j] == index) { | ||
866 | cpumask_set_cpu(i, mask); | ||
867 | break; | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | rcu_read_unlock(); | ||
874 | |||
875 | len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask); | ||
876 | if (PAGE_SIZE - len < 3) { | ||
877 | free_cpumask_var(mask); | ||
878 | return -EINVAL; | ||
879 | } | ||
880 | |||
881 | free_cpumask_var(mask); | ||
882 | len += sprintf(buf + len, "\n"); | ||
883 | return len; | ||
884 | } | ||
885 | |||
886 | static void xps_map_release(struct rcu_head *rcu) | ||
887 | { | ||
888 | struct xps_map *map = container_of(rcu, struct xps_map, rcu); | ||
889 | |||
890 | kfree(map); | ||
891 | } | ||
892 | |||
893 | static void xps_dev_maps_release(struct rcu_head *rcu) | ||
894 | { | ||
895 | struct xps_dev_maps *dev_maps = | ||
896 | container_of(rcu, struct xps_dev_maps, rcu); | ||
897 | |||
898 | kfree(dev_maps); | ||
899 | } | ||
900 | |||
901 | static DEFINE_MUTEX(xps_map_mutex); | ||
902 | #define xmap_dereference(P) \ | ||
903 | rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex)) | ||
904 | |||
905 | static ssize_t store_xps_map(struct netdev_queue *queue, | ||
906 | struct netdev_queue_attribute *attribute, | ||
907 | const char *buf, size_t len) | ||
908 | { | ||
909 | struct net_device *dev = queue->dev; | ||
910 | cpumask_var_t mask; | ||
911 | int err, i, cpu, pos, map_len, alloc_len, need_set; | ||
912 | unsigned long index; | ||
913 | struct xps_map *map, *new_map; | ||
914 | struct xps_dev_maps *dev_maps, *new_dev_maps; | ||
915 | int nonempty = 0; | ||
916 | int numa_node = -2; | ||
917 | |||
918 | if (!capable(CAP_NET_ADMIN)) | ||
919 | return -EPERM; | ||
920 | |||
921 | if (!alloc_cpumask_var(&mask, GFP_KERNEL)) | ||
922 | return -ENOMEM; | ||
923 | |||
924 | index = get_netdev_queue_index(queue); | ||
925 | |||
926 | err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); | ||
927 | if (err) { | ||
928 | free_cpumask_var(mask); | ||
929 | return err; | ||
930 | } | ||
931 | |||
932 | new_dev_maps = kzalloc(max_t(unsigned, | ||
933 | XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES), GFP_KERNEL); | ||
934 | if (!new_dev_maps) { | ||
935 | free_cpumask_var(mask); | ||
936 | return -ENOMEM; | ||
937 | } | ||
938 | |||
939 | mutex_lock(&xps_map_mutex); | ||
940 | |||
941 | dev_maps = xmap_dereference(dev->xps_maps); | ||
942 | |||
943 | for_each_possible_cpu(cpu) { | ||
944 | map = dev_maps ? | ||
945 | xmap_dereference(dev_maps->cpu_map[cpu]) : NULL; | ||
946 | new_map = map; | ||
947 | if (map) { | ||
948 | for (pos = 0; pos < map->len; pos++) | ||
949 | if (map->queues[pos] == index) | ||
950 | break; | ||
951 | map_len = map->len; | ||
952 | alloc_len = map->alloc_len; | ||
953 | } else | ||
954 | pos = map_len = alloc_len = 0; | ||
955 | |||
956 | need_set = cpu_isset(cpu, *mask) && cpu_online(cpu); | ||
957 | #ifdef CONFIG_NUMA | ||
958 | if (need_set) { | ||
959 | if (numa_node == -2) | ||
960 | numa_node = cpu_to_node(cpu); | ||
961 | else if (numa_node != cpu_to_node(cpu)) | ||
962 | numa_node = -1; | ||
963 | } | ||
964 | #endif | ||
965 | if (need_set && pos >= map_len) { | ||
966 | /* Need to add queue to this CPU's map */ | ||
967 | if (map_len >= alloc_len) { | ||
968 | alloc_len = alloc_len ? | ||
969 | 2 * alloc_len : XPS_MIN_MAP_ALLOC; | ||
970 | new_map = kzalloc_node(XPS_MAP_SIZE(alloc_len), | ||
971 | GFP_KERNEL, | ||
972 | cpu_to_node(cpu)); | ||
973 | if (!new_map) | ||
974 | goto error; | ||
975 | new_map->alloc_len = alloc_len; | ||
976 | for (i = 0; i < map_len; i++) | ||
977 | new_map->queues[i] = map->queues[i]; | ||
978 | new_map->len = map_len; | ||
979 | } | ||
980 | new_map->queues[new_map->len++] = index; | ||
981 | } else if (!need_set && pos < map_len) { | ||
982 | /* Need to remove queue from this CPU's map */ | ||
983 | if (map_len > 1) | ||
984 | new_map->queues[pos] = | ||
985 | new_map->queues[--new_map->len]; | ||
986 | else | ||
987 | new_map = NULL; | ||
988 | } | ||
989 | RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], new_map); | ||
990 | } | ||
991 | |||
992 | /* Cleanup old maps */ | ||
993 | for_each_possible_cpu(cpu) { | ||
994 | map = dev_maps ? | ||
995 | xmap_dereference(dev_maps->cpu_map[cpu]) : NULL; | ||
996 | if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map) | ||
997 | call_rcu(&map->rcu, xps_map_release); | ||
998 | if (new_dev_maps->cpu_map[cpu]) | ||
999 | nonempty = 1; | ||
1000 | } | ||
1001 | |||
1002 | if (nonempty) | ||
1003 | rcu_assign_pointer(dev->xps_maps, new_dev_maps); | ||
1004 | else { | ||
1005 | kfree(new_dev_maps); | ||
1006 | rcu_assign_pointer(dev->xps_maps, NULL); | ||
1007 | } | ||
1008 | |||
1009 | if (dev_maps) | ||
1010 | call_rcu(&dev_maps->rcu, xps_dev_maps_release); | ||
1011 | |||
1012 | netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node : | ||
1013 | NUMA_NO_NODE); | ||
1014 | |||
1015 | mutex_unlock(&xps_map_mutex); | ||
1016 | |||
1017 | free_cpumask_var(mask); | ||
1018 | return len; | ||
1019 | |||
1020 | error: | ||
1021 | mutex_unlock(&xps_map_mutex); | ||
1022 | |||
1023 | if (new_dev_maps) | ||
1024 | for_each_possible_cpu(i) | ||
1025 | kfree(rcu_dereference_protected( | ||
1026 | new_dev_maps->cpu_map[i], | ||
1027 | 1)); | ||
1028 | kfree(new_dev_maps); | ||
1029 | free_cpumask_var(mask); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | |||
1033 | static struct netdev_queue_attribute xps_cpus_attribute = | ||
1034 | __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map); | ||
1035 | |||
1036 | static struct attribute *netdev_queue_default_attrs[] = { | ||
1037 | &xps_cpus_attribute.attr, | ||
1038 | NULL | ||
1039 | }; | ||
1040 | |||
1041 | static void netdev_queue_release(struct kobject *kobj) | ||
1042 | { | ||
1043 | struct netdev_queue *queue = to_netdev_queue(kobj); | ||
1044 | struct net_device *dev = queue->dev; | ||
1045 | struct xps_dev_maps *dev_maps; | ||
1046 | struct xps_map *map; | ||
1047 | unsigned long index; | ||
1048 | int i, pos, nonempty = 0; | ||
1049 | |||
1050 | index = get_netdev_queue_index(queue); | ||
1051 | |||
1052 | mutex_lock(&xps_map_mutex); | ||
1053 | dev_maps = xmap_dereference(dev->xps_maps); | ||
1054 | |||
1055 | if (dev_maps) { | ||
1056 | for_each_possible_cpu(i) { | ||
1057 | map = xmap_dereference(dev_maps->cpu_map[i]); | ||
1058 | if (!map) | ||
1059 | continue; | ||
1060 | |||
1061 | for (pos = 0; pos < map->len; pos++) | ||
1062 | if (map->queues[pos] == index) | ||
1063 | break; | ||
1064 | |||
1065 | if (pos < map->len) { | ||
1066 | if (map->len > 1) | ||
1067 | map->queues[pos] = | ||
1068 | map->queues[--map->len]; | ||
1069 | else { | ||
1070 | RCU_INIT_POINTER(dev_maps->cpu_map[i], | ||
1071 | NULL); | ||
1072 | call_rcu(&map->rcu, xps_map_release); | ||
1073 | map = NULL; | ||
1074 | } | ||
1075 | } | ||
1076 | if (map) | ||
1077 | nonempty = 1; | ||
1078 | } | ||
1079 | |||
1080 | if (!nonempty) { | ||
1081 | RCU_INIT_POINTER(dev->xps_maps, NULL); | ||
1082 | call_rcu(&dev_maps->rcu, xps_dev_maps_release); | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | mutex_unlock(&xps_map_mutex); | ||
1087 | |||
1088 | memset(kobj, 0, sizeof(*kobj)); | ||
1089 | dev_put(queue->dev); | ||
1090 | } | ||
1091 | |||
1092 | static struct kobj_type netdev_queue_ktype = { | ||
1093 | .sysfs_ops = &netdev_queue_sysfs_ops, | ||
1094 | .release = netdev_queue_release, | ||
1095 | .default_attrs = netdev_queue_default_attrs, | ||
1096 | }; | ||
1097 | |||
1098 | static int netdev_queue_add_kobject(struct net_device *net, int index) | ||
1099 | { | ||
1100 | struct netdev_queue *queue = net->_tx + index; | ||
1101 | struct kobject *kobj = &queue->kobj; | ||
1102 | int error = 0; | ||
1103 | |||
1104 | kobj->kset = net->queues_kset; | ||
1105 | error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, | ||
1106 | "tx-%u", index); | ||
1107 | if (error) { | ||
1108 | kobject_put(kobj); | ||
1109 | return error; | ||
1110 | } | ||
1111 | |||
1112 | kobject_uevent(kobj, KOBJ_ADD); | ||
1113 | dev_hold(queue->dev); | ||
1114 | |||
1115 | return error; | ||
1116 | } | ||
1117 | #endif /* CONFIG_XPS */ | ||
1118 | |||
1119 | int | ||
1120 | netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num) | ||
1121 | { | ||
1122 | #ifdef CONFIG_XPS | ||
1123 | int i; | ||
1124 | int error = 0; | ||
1125 | |||
1126 | for (i = old_num; i < new_num; i++) { | ||
1127 | error = netdev_queue_add_kobject(net, i); | ||
1128 | if (error) { | ||
1129 | new_num = old_num; | ||
1130 | break; | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | while (--i >= new_num) | ||
1135 | kobject_put(&net->_tx[i].kobj); | ||
1136 | |||
1137 | return error; | ||
1138 | #else | ||
1139 | return 0; | ||
1140 | #endif | ||
1141 | } | ||
1142 | |||
1143 | static int register_queue_kobjects(struct net_device *net) | ||
1144 | { | ||
1145 | int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; | ||
1146 | |||
1147 | #if defined(CONFIG_RPS) || defined(CONFIG_XPS) | ||
781 | net->queues_kset = kset_create_and_add("queues", | 1148 | net->queues_kset = kset_create_and_add("queues", |
782 | NULL, &net->dev.kobj); | 1149 | NULL, &net->dev.kobj); |
783 | if (!net->queues_kset) | 1150 | if (!net->queues_kset) |
784 | return -ENOMEM; | 1151 | return -ENOMEM; |
785 | return net_rx_queue_update_kobjects(net, 0, net->real_num_rx_queues); | 1152 | #endif |
1153 | |||
1154 | #ifdef CONFIG_RPS | ||
1155 | real_rx = net->real_num_rx_queues; | ||
1156 | #endif | ||
1157 | real_tx = net->real_num_tx_queues; | ||
1158 | |||
1159 | error = net_rx_queue_update_kobjects(net, 0, real_rx); | ||
1160 | if (error) | ||
1161 | goto error; | ||
1162 | rxq = real_rx; | ||
1163 | |||
1164 | error = netdev_queue_update_kobjects(net, 0, real_tx); | ||
1165 | if (error) | ||
1166 | goto error; | ||
1167 | txq = real_tx; | ||
1168 | |||
1169 | return 0; | ||
1170 | |||
1171 | error: | ||
1172 | netdev_queue_update_kobjects(net, txq, 0); | ||
1173 | net_rx_queue_update_kobjects(net, rxq, 0); | ||
1174 | return error; | ||
786 | } | 1175 | } |
787 | 1176 | ||
788 | static void rx_queue_remove_kobjects(struct net_device *net) | 1177 | static void remove_queue_kobjects(struct net_device *net) |
789 | { | 1178 | { |
790 | net_rx_queue_update_kobjects(net, net->real_num_rx_queues, 0); | 1179 | int real_rx = 0, real_tx = 0; |
1180 | |||
1181 | #ifdef CONFIG_RPS | ||
1182 | real_rx = net->real_num_rx_queues; | ||
1183 | #endif | ||
1184 | real_tx = net->real_num_tx_queues; | ||
1185 | |||
1186 | net_rx_queue_update_kobjects(net, real_rx, 0); | ||
1187 | netdev_queue_update_kobjects(net, real_tx, 0); | ||
1188 | #if defined(CONFIG_RPS) || defined(CONFIG_XPS) | ||
791 | kset_unregister(net->queues_kset); | 1189 | kset_unregister(net->queues_kset); |
1190 | #endif | ||
792 | } | 1191 | } |
793 | #endif /* CONFIG_RPS */ | ||
794 | 1192 | ||
795 | static const void *net_current_ns(void) | 1193 | static const void *net_current_ns(void) |
796 | { | 1194 | { |
@@ -889,9 +1287,7 @@ void netdev_unregister_kobject(struct net_device * net) | |||
889 | 1287 | ||
890 | kobject_get(&dev->kobj); | 1288 | kobject_get(&dev->kobj); |
891 | 1289 | ||
892 | #ifdef CONFIG_RPS | 1290 | remove_queue_kobjects(net); |
893 | rx_queue_remove_kobjects(net); | ||
894 | #endif | ||
895 | 1291 | ||
896 | device_del(dev); | 1292 | device_del(dev); |
897 | } | 1293 | } |
@@ -930,13 +1326,11 @@ int netdev_register_kobject(struct net_device *net) | |||
930 | if (error) | 1326 | if (error) |
931 | return error; | 1327 | return error; |
932 | 1328 | ||
933 | #ifdef CONFIG_RPS | 1329 | error = register_queue_kobjects(net); |
934 | error = rx_queue_register_kobjects(net); | ||
935 | if (error) { | 1330 | if (error) { |
936 | device_del(dev); | 1331 | device_del(dev); |
937 | return error; | 1332 | return error; |
938 | } | 1333 | } |
939 | #endif | ||
940 | 1334 | ||
941 | return error; | 1335 | return error; |
942 | } | 1336 | } |
diff --git a/net/core/net-sysfs.h b/net/core/net-sysfs.h index 778e1571548d..bd7751ec1c4d 100644 --- a/net/core/net-sysfs.h +++ b/net/core/net-sysfs.h | |||
@@ -4,8 +4,8 @@ | |||
4 | int netdev_kobject_init(void); | 4 | int netdev_kobject_init(void); |
5 | int netdev_register_kobject(struct net_device *); | 5 | int netdev_register_kobject(struct net_device *); |
6 | void netdev_unregister_kobject(struct net_device *); | 6 | void netdev_unregister_kobject(struct net_device *); |
7 | #ifdef CONFIG_RPS | ||
8 | int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num); | 7 | int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num); |
9 | #endif | 8 | int netdev_queue_update_kobjects(struct net_device *net, |
9 | int old_num, int new_num); | ||
10 | 10 | ||
11 | #endif | 11 | #endif |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 4e98ffac3af0..72d9b50109fc 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -35,7 +35,6 @@ | |||
35 | 35 | ||
36 | #define MAX_UDP_CHUNK 1460 | 36 | #define MAX_UDP_CHUNK 1460 |
37 | #define MAX_SKBS 32 | 37 | #define MAX_SKBS 32 |
38 | #define MAX_QUEUE_DEPTH (MAX_SKBS / 2) | ||
39 | 38 | ||
40 | static struct sk_buff_head skb_pool; | 39 | static struct sk_buff_head skb_pool; |
41 | 40 | ||
@@ -76,8 +75,7 @@ static void queue_process(struct work_struct *work) | |||
76 | 75 | ||
77 | local_irq_save(flags); | 76 | local_irq_save(flags); |
78 | __netif_tx_lock(txq, smp_processor_id()); | 77 | __netif_tx_lock(txq, smp_processor_id()); |
79 | if (netif_tx_queue_stopped(txq) || | 78 | if (netif_tx_queue_frozen_or_stopped(txq) || |
80 | netif_tx_queue_frozen(txq) || | ||
81 | ops->ndo_start_xmit(skb, dev) != NETDEV_TX_OK) { | 79 | ops->ndo_start_xmit(skb, dev) != NETDEV_TX_OK) { |
82 | skb_queue_head(&npinfo->txq, skb); | 80 | skb_queue_head(&npinfo->txq, skb); |
83 | __netif_tx_unlock(txq); | 81 | __netif_tx_unlock(txq); |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 33bc3823ac6f..a9e7fc4c461f 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -378,6 +378,7 @@ struct pktgen_dev { | |||
378 | 378 | ||
379 | u16 queue_map_min; | 379 | u16 queue_map_min; |
380 | u16 queue_map_max; | 380 | u16 queue_map_max; |
381 | __u32 skb_priority; /* skb priority field */ | ||
381 | int node; /* Memory node */ | 382 | int node; /* Memory node */ |
382 | 383 | ||
383 | #ifdef CONFIG_XFRM | 384 | #ifdef CONFIG_XFRM |
@@ -394,6 +395,8 @@ struct pktgen_hdr { | |||
394 | __be32 tv_usec; | 395 | __be32 tv_usec; |
395 | }; | 396 | }; |
396 | 397 | ||
398 | static bool pktgen_exiting __read_mostly; | ||
399 | |||
397 | struct pktgen_thread { | 400 | struct pktgen_thread { |
398 | spinlock_t if_lock; /* for list of devices */ | 401 | spinlock_t if_lock; /* for list of devices */ |
399 | struct list_head if_list; /* All device here */ | 402 | struct list_head if_list; /* All device here */ |
@@ -547,6 +550,10 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
547 | pkt_dev->queue_map_min, | 550 | pkt_dev->queue_map_min, |
548 | pkt_dev->queue_map_max); | 551 | pkt_dev->queue_map_max); |
549 | 552 | ||
553 | if (pkt_dev->skb_priority) | ||
554 | seq_printf(seq, " skb_priority: %u\n", | ||
555 | pkt_dev->skb_priority); | ||
556 | |||
550 | if (pkt_dev->flags & F_IPV6) { | 557 | if (pkt_dev->flags & F_IPV6) { |
551 | char b1[128], b2[128], b3[128]; | 558 | char b1[128], b2[128], b3[128]; |
552 | fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); | 559 | fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); |
@@ -1711,6 +1718,18 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1711 | return count; | 1718 | return count; |
1712 | } | 1719 | } |
1713 | 1720 | ||
1721 | if (!strcmp(name, "skb_priority")) { | ||
1722 | len = num_arg(&user_buffer[i], 9, &value); | ||
1723 | if (len < 0) | ||
1724 | return len; | ||
1725 | |||
1726 | i += len; | ||
1727 | pkt_dev->skb_priority = value; | ||
1728 | sprintf(pg_result, "OK: skb_priority=%i", | ||
1729 | pkt_dev->skb_priority); | ||
1730 | return count; | ||
1731 | } | ||
1732 | |||
1714 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); | 1733 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); |
1715 | return -EINVAL; | 1734 | return -EINVAL; |
1716 | } | 1735 | } |
@@ -2641,6 +2660,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2641 | sprintf(pkt_dev->result, "No memory"); | 2660 | sprintf(pkt_dev->result, "No memory"); |
2642 | return NULL; | 2661 | return NULL; |
2643 | } | 2662 | } |
2663 | prefetchw(skb->data); | ||
2644 | 2664 | ||
2645 | skb_reserve(skb, datalen); | 2665 | skb_reserve(skb, datalen); |
2646 | 2666 | ||
@@ -2671,6 +2691,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2671 | skb->transport_header = skb->network_header + sizeof(struct iphdr); | 2691 | skb->transport_header = skb->network_header + sizeof(struct iphdr); |
2672 | skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); | 2692 | skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); |
2673 | skb_set_queue_mapping(skb, queue_map); | 2693 | skb_set_queue_mapping(skb, queue_map); |
2694 | skb->priority = pkt_dev->skb_priority; | ||
2695 | |||
2674 | iph = ip_hdr(skb); | 2696 | iph = ip_hdr(skb); |
2675 | udph = udp_hdr(skb); | 2697 | udph = udp_hdr(skb); |
2676 | 2698 | ||
@@ -2986,6 +3008,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2986 | sprintf(pkt_dev->result, "No memory"); | 3008 | sprintf(pkt_dev->result, "No memory"); |
2987 | return NULL; | 3009 | return NULL; |
2988 | } | 3010 | } |
3011 | prefetchw(skb->data); | ||
2989 | 3012 | ||
2990 | skb_reserve(skb, 16); | 3013 | skb_reserve(skb, 16); |
2991 | 3014 | ||
@@ -3016,6 +3039,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
3016 | skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); | 3039 | skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); |
3017 | skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); | 3040 | skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); |
3018 | skb_set_queue_mapping(skb, queue_map); | 3041 | skb_set_queue_mapping(skb, queue_map); |
3042 | skb->priority = pkt_dev->skb_priority; | ||
3019 | iph = ipv6_hdr(skb); | 3043 | iph = ipv6_hdr(skb); |
3020 | udph = udp_hdr(skb); | 3044 | udph = udp_hdr(skb); |
3021 | 3045 | ||
@@ -3431,11 +3455,6 @@ static void pktgen_rem_thread(struct pktgen_thread *t) | |||
3431 | 3455 | ||
3432 | remove_proc_entry(t->tsk->comm, pg_proc_dir); | 3456 | remove_proc_entry(t->tsk->comm, pg_proc_dir); |
3433 | 3457 | ||
3434 | mutex_lock(&pktgen_thread_lock); | ||
3435 | |||
3436 | list_del(&t->th_list); | ||
3437 | |||
3438 | mutex_unlock(&pktgen_thread_lock); | ||
3439 | } | 3458 | } |
3440 | 3459 | ||
3441 | static void pktgen_resched(struct pktgen_dev *pkt_dev) | 3460 | static void pktgen_resched(struct pktgen_dev *pkt_dev) |
@@ -3510,7 +3529,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) | |||
3510 | 3529 | ||
3511 | __netif_tx_lock_bh(txq); | 3530 | __netif_tx_lock_bh(txq); |
3512 | 3531 | ||
3513 | if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) { | 3532 | if (unlikely(netif_tx_queue_frozen_or_stopped(txq))) { |
3514 | ret = NETDEV_TX_BUSY; | 3533 | ret = NETDEV_TX_BUSY; |
3515 | pkt_dev->last_ok = 0; | 3534 | pkt_dev->last_ok = 0; |
3516 | goto unlock; | 3535 | goto unlock; |
@@ -3534,8 +3553,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) | |||
3534 | break; | 3553 | break; |
3535 | default: /* Drivers are not supposed to return other values! */ | 3554 | default: /* Drivers are not supposed to return other values! */ |
3536 | if (net_ratelimit()) | 3555 | if (net_ratelimit()) |
3537 | pr_info("pktgen: %s xmit error: %d\n", | 3556 | pr_info("%s xmit error: %d\n", pkt_dev->odevname, ret); |
3538 | pkt_dev->odevname, ret); | ||
3539 | pkt_dev->errors++; | 3557 | pkt_dev->errors++; |
3540 | /* fallthru */ | 3558 | /* fallthru */ |
3541 | case NETDEV_TX_LOCKED: | 3559 | case NETDEV_TX_LOCKED: |
@@ -3582,6 +3600,8 @@ static int pktgen_thread_worker(void *arg) | |||
3582 | pkt_dev = next_to_run(t); | 3600 | pkt_dev = next_to_run(t); |
3583 | 3601 | ||
3584 | if (unlikely(!pkt_dev && t->control == 0)) { | 3602 | if (unlikely(!pkt_dev && t->control == 0)) { |
3603 | if (pktgen_exiting) | ||
3604 | break; | ||
3585 | wait_event_interruptible_timeout(t->queue, | 3605 | wait_event_interruptible_timeout(t->queue, |
3586 | t->control != 0, | 3606 | t->control != 0, |
3587 | HZ/10); | 3607 | HZ/10); |
@@ -3634,6 +3654,13 @@ static int pktgen_thread_worker(void *arg) | |||
3634 | pr_debug("%s removing thread\n", t->tsk->comm); | 3654 | pr_debug("%s removing thread\n", t->tsk->comm); |
3635 | pktgen_rem_thread(t); | 3655 | pktgen_rem_thread(t); |
3636 | 3656 | ||
3657 | /* Wait for kthread_stop */ | ||
3658 | while (!kthread_should_stop()) { | ||
3659 | set_current_state(TASK_INTERRUPTIBLE); | ||
3660 | schedule(); | ||
3661 | } | ||
3662 | __set_current_state(TASK_RUNNING); | ||
3663 | |||
3637 | return 0; | 3664 | return 0; |
3638 | } | 3665 | } |
3639 | 3666 | ||
@@ -3908,6 +3935,7 @@ static void __exit pg_cleanup(void) | |||
3908 | struct list_head *q, *n; | 3935 | struct list_head *q, *n; |
3909 | 3936 | ||
3910 | /* Stop all interfaces & threads */ | 3937 | /* Stop all interfaces & threads */ |
3938 | pktgen_exiting = true; | ||
3911 | 3939 | ||
3912 | list_for_each_safe(q, n, &pktgen_threads) { | 3940 | list_for_each_safe(q, n, &pktgen_threads) { |
3913 | t = list_entry(q, struct pktgen_thread, th_list); | 3941 | t = list_entry(q, struct pktgen_thread, th_list); |
diff --git a/net/core/request_sock.c b/net/core/request_sock.c index fceeb37d7161..182236b2510a 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c | |||
@@ -33,6 +33,7 @@ | |||
33 | * Note : Dont forget somaxconn that may limit backlog too. | 33 | * Note : Dont forget somaxconn that may limit backlog too. |
34 | */ | 34 | */ |
35 | int sysctl_max_syn_backlog = 256; | 35 | int sysctl_max_syn_backlog = 256; |
36 | EXPORT_SYMBOL(sysctl_max_syn_backlog); | ||
36 | 37 | ||
37 | int reqsk_queue_alloc(struct request_sock_queue *queue, | 38 | int reqsk_queue_alloc(struct request_sock_queue *queue, |
38 | unsigned int nr_table_entries) | 39 | unsigned int nr_table_entries) |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 841c287ef40a..750db57f3bb3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -362,6 +362,95 @@ static size_t rtnl_link_get_size(const struct net_device *dev) | |||
362 | return size; | 362 | return size; |
363 | } | 363 | } |
364 | 364 | ||
365 | static LIST_HEAD(rtnl_af_ops); | ||
366 | |||
367 | static const struct rtnl_af_ops *rtnl_af_lookup(const int family) | ||
368 | { | ||
369 | const struct rtnl_af_ops *ops; | ||
370 | |||
371 | list_for_each_entry(ops, &rtnl_af_ops, list) { | ||
372 | if (ops->family == family) | ||
373 | return ops; | ||
374 | } | ||
375 | |||
376 | return NULL; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * __rtnl_af_register - Register rtnl_af_ops with rtnetlink. | ||
381 | * @ops: struct rtnl_af_ops * to register | ||
382 | * | ||
383 | * The caller must hold the rtnl_mutex. | ||
384 | * | ||
385 | * Returns 0 on success or a negative error code. | ||
386 | */ | ||
387 | int __rtnl_af_register(struct rtnl_af_ops *ops) | ||
388 | { | ||
389 | list_add_tail(&ops->list, &rtnl_af_ops); | ||
390 | return 0; | ||
391 | } | ||
392 | EXPORT_SYMBOL_GPL(__rtnl_af_register); | ||
393 | |||
394 | /** | ||
395 | * rtnl_af_register - Register rtnl_af_ops with rtnetlink. | ||
396 | * @ops: struct rtnl_af_ops * to register | ||
397 | * | ||
398 | * Returns 0 on success or a negative error code. | ||
399 | */ | ||
400 | int rtnl_af_register(struct rtnl_af_ops *ops) | ||
401 | { | ||
402 | int err; | ||
403 | |||
404 | rtnl_lock(); | ||
405 | err = __rtnl_af_register(ops); | ||
406 | rtnl_unlock(); | ||
407 | return err; | ||
408 | } | ||
409 | EXPORT_SYMBOL_GPL(rtnl_af_register); | ||
410 | |||
411 | /** | ||
412 | * __rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink. | ||
413 | * @ops: struct rtnl_af_ops * to unregister | ||
414 | * | ||
415 | * The caller must hold the rtnl_mutex. | ||
416 | */ | ||
417 | void __rtnl_af_unregister(struct rtnl_af_ops *ops) | ||
418 | { | ||
419 | list_del(&ops->list); | ||
420 | } | ||
421 | EXPORT_SYMBOL_GPL(__rtnl_af_unregister); | ||
422 | |||
423 | /** | ||
424 | * rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink. | ||
425 | * @ops: struct rtnl_af_ops * to unregister | ||
426 | */ | ||
427 | void rtnl_af_unregister(struct rtnl_af_ops *ops) | ||
428 | { | ||
429 | rtnl_lock(); | ||
430 | __rtnl_af_unregister(ops); | ||
431 | rtnl_unlock(); | ||
432 | } | ||
433 | EXPORT_SYMBOL_GPL(rtnl_af_unregister); | ||
434 | |||
435 | static size_t rtnl_link_get_af_size(const struct net_device *dev) | ||
436 | { | ||
437 | struct rtnl_af_ops *af_ops; | ||
438 | size_t size; | ||
439 | |||
440 | /* IFLA_AF_SPEC */ | ||
441 | size = nla_total_size(sizeof(struct nlattr)); | ||
442 | |||
443 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | ||
444 | if (af_ops->get_link_af_size) { | ||
445 | /* AF_* + nested data */ | ||
446 | size += nla_total_size(sizeof(struct nlattr)) + | ||
447 | af_ops->get_link_af_size(dev); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | return size; | ||
452 | } | ||
453 | |||
365 | static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) | 454 | static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) |
366 | { | 455 | { |
367 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; | 456 | const struct rtnl_link_ops *ops = dev->rtnl_link_ops; |
@@ -671,7 +760,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev) | |||
671 | + nla_total_size(4) /* IFLA_NUM_VF */ | 760 | + nla_total_size(4) /* IFLA_NUM_VF */ |
672 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ | 761 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ |
673 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ | 762 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ |
674 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 763 | + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ |
764 | + rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */ | ||
675 | } | 765 | } |
676 | 766 | ||
677 | static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) | 767 | static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) |
@@ -757,7 +847,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
757 | struct nlmsghdr *nlh; | 847 | struct nlmsghdr *nlh; |
758 | struct rtnl_link_stats64 temp; | 848 | struct rtnl_link_stats64 temp; |
759 | const struct rtnl_link_stats64 *stats; | 849 | const struct rtnl_link_stats64 *stats; |
760 | struct nlattr *attr; | 850 | struct nlattr *attr, *af_spec; |
851 | struct rtnl_af_ops *af_ops; | ||
761 | 852 | ||
762 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); | 853 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
763 | if (nlh == NULL) | 854 | if (nlh == NULL) |
@@ -866,6 +957,36 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
866 | goto nla_put_failure; | 957 | goto nla_put_failure; |
867 | } | 958 | } |
868 | 959 | ||
960 | if (!(af_spec = nla_nest_start(skb, IFLA_AF_SPEC))) | ||
961 | goto nla_put_failure; | ||
962 | |||
963 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | ||
964 | if (af_ops->fill_link_af) { | ||
965 | struct nlattr *af; | ||
966 | int err; | ||
967 | |||
968 | if (!(af = nla_nest_start(skb, af_ops->family))) | ||
969 | goto nla_put_failure; | ||
970 | |||
971 | err = af_ops->fill_link_af(skb, dev); | ||
972 | |||
973 | /* | ||
974 | * Caller may return ENODATA to indicate that there | ||
975 | * was no data to be dumped. This is not an error, it | ||
976 | * means we should trim the attribute header and | ||
977 | * continue. | ||
978 | */ | ||
979 | if (err == -ENODATA) | ||
980 | nla_nest_cancel(skb, af); | ||
981 | else if (err < 0) | ||
982 | goto nla_put_failure; | ||
983 | |||
984 | nla_nest_end(skb, af); | ||
985 | } | ||
986 | } | ||
987 | |||
988 | nla_nest_end(skb, af_spec); | ||
989 | |||
869 | return nlmsg_end(skb, nlh); | 990 | return nlmsg_end(skb, nlh); |
870 | 991 | ||
871 | nla_put_failure: | 992 | nla_put_failure: |
@@ -924,6 +1045,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
924 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, | 1045 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
925 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, | 1046 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, |
926 | [IFLA_PORT_SELF] = { .type = NLA_NESTED }, | 1047 | [IFLA_PORT_SELF] = { .type = NLA_NESTED }, |
1048 | [IFLA_AF_SPEC] = { .type = NLA_NESTED }, | ||
927 | }; | 1049 | }; |
928 | EXPORT_SYMBOL(ifla_policy); | 1050 | EXPORT_SYMBOL(ifla_policy); |
929 | 1051 | ||
@@ -985,6 +1107,28 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | |||
985 | return -EINVAL; | 1107 | return -EINVAL; |
986 | } | 1108 | } |
987 | 1109 | ||
1110 | if (tb[IFLA_AF_SPEC]) { | ||
1111 | struct nlattr *af; | ||
1112 | int rem, err; | ||
1113 | |||
1114 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { | ||
1115 | const struct rtnl_af_ops *af_ops; | ||
1116 | |||
1117 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) | ||
1118 | return -EAFNOSUPPORT; | ||
1119 | |||
1120 | if (!af_ops->set_link_af) | ||
1121 | return -EOPNOTSUPP; | ||
1122 | |||
1123 | if (af_ops->validate_link_af) { | ||
1124 | err = af_ops->validate_link_af(dev, | ||
1125 | tb[IFLA_AF_SPEC]); | ||
1126 | if (err < 0) | ||
1127 | return err; | ||
1128 | } | ||
1129 | } | ||
1130 | } | ||
1131 | |||
988 | return 0; | 1132 | return 0; |
989 | } | 1133 | } |
990 | 1134 | ||
@@ -1225,6 +1369,24 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1225 | goto errout; | 1369 | goto errout; |
1226 | modified = 1; | 1370 | modified = 1; |
1227 | } | 1371 | } |
1372 | |||
1373 | if (tb[IFLA_AF_SPEC]) { | ||
1374 | struct nlattr *af; | ||
1375 | int rem; | ||
1376 | |||
1377 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { | ||
1378 | const struct rtnl_af_ops *af_ops; | ||
1379 | |||
1380 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) | ||
1381 | BUG(); | ||
1382 | |||
1383 | err = af_ops->set_link_af(dev, af); | ||
1384 | if (err < 0) | ||
1385 | goto errout; | ||
1386 | |||
1387 | modified = 1; | ||
1388 | } | ||
1389 | } | ||
1228 | err = 0; | 1390 | err = 0; |
1229 | 1391 | ||
1230 | errout: | 1392 | errout: |
diff --git a/net/core/scm.c b/net/core/scm.c index 413cab89017d..bbe454450801 100644 --- a/net/core/scm.c +++ b/net/core/scm.c | |||
@@ -79,10 +79,11 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) | |||
79 | return -ENOMEM; | 79 | return -ENOMEM; |
80 | *fplp = fpl; | 80 | *fplp = fpl; |
81 | fpl->count = 0; | 81 | fpl->count = 0; |
82 | fpl->max = SCM_MAX_FD; | ||
82 | } | 83 | } |
83 | fpp = &fpl->fp[fpl->count]; | 84 | fpp = &fpl->fp[fpl->count]; |
84 | 85 | ||
85 | if (fpl->count + num > SCM_MAX_FD) | 86 | if (fpl->count + num > fpl->max) |
86 | return -EINVAL; | 87 | return -EINVAL; |
87 | 88 | ||
88 | /* | 89 | /* |
@@ -331,11 +332,12 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) | |||
331 | if (!fpl) | 332 | if (!fpl) |
332 | return NULL; | 333 | return NULL; |
333 | 334 | ||
334 | new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL); | 335 | new_fpl = kmemdup(fpl, offsetof(struct scm_fp_list, fp[fpl->count]), |
336 | GFP_KERNEL); | ||
335 | if (new_fpl) { | 337 | if (new_fpl) { |
336 | for (i=fpl->count-1; i>=0; i--) | 338 | for (i = 0; i < fpl->count; i++) |
337 | get_file(fpl->fp[i]); | 339 | get_file(fpl->fp[i]); |
338 | memcpy(new_fpl, fpl, sizeof(*fpl)); | 340 | new_fpl->max = new_fpl->count; |
339 | } | 341 | } |
340 | return new_fpl; | 342 | return new_fpl; |
341 | } | 343 | } |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 104f8444754a..19d6c21220fd 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -778,6 +778,28 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
778 | 778 | ||
779 | size = SKB_DATA_ALIGN(size); | 779 | size = SKB_DATA_ALIGN(size); |
780 | 780 | ||
781 | /* Check if we can avoid taking references on fragments if we own | ||
782 | * the last reference on skb->head. (see skb_release_data()) | ||
783 | */ | ||
784 | if (!skb->cloned) | ||
785 | fastpath = true; | ||
786 | else { | ||
787 | int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1; | ||
788 | |||
789 | fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta; | ||
790 | } | ||
791 | |||
792 | if (fastpath && | ||
793 | size + sizeof(struct skb_shared_info) <= ksize(skb->head)) { | ||
794 | memmove(skb->head + size, skb_shinfo(skb), | ||
795 | offsetof(struct skb_shared_info, | ||
796 | frags[skb_shinfo(skb)->nr_frags])); | ||
797 | memmove(skb->head + nhead, skb->head, | ||
798 | skb_tail_pointer(skb) - skb->head); | ||
799 | off = nhead; | ||
800 | goto adjust_others; | ||
801 | } | ||
802 | |||
781 | data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); | 803 | data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); |
782 | if (!data) | 804 | if (!data) |
783 | goto nodata; | 805 | goto nodata; |
@@ -791,17 +813,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
791 | skb_shinfo(skb), | 813 | skb_shinfo(skb), |
792 | offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags])); | 814 | offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags])); |
793 | 815 | ||
794 | /* Check if we can avoid taking references on fragments if we own | ||
795 | * the last reference on skb->head. (see skb_release_data()) | ||
796 | */ | ||
797 | if (!skb->cloned) | ||
798 | fastpath = true; | ||
799 | else { | ||
800 | int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1; | ||
801 | |||
802 | fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta; | ||
803 | } | ||
804 | |||
805 | if (fastpath) { | 816 | if (fastpath) { |
806 | kfree(skb->head); | 817 | kfree(skb->head); |
807 | } else { | 818 | } else { |
@@ -816,6 +827,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
816 | off = (data + nhead) - skb->head; | 827 | off = (data + nhead) - skb->head; |
817 | 828 | ||
818 | skb->head = data; | 829 | skb->head = data; |
830 | adjust_others: | ||
819 | skb->data += off; | 831 | skb->data += off; |
820 | #ifdef NET_SKBUFF_DATA_USES_OFFSET | 832 | #ifdef NET_SKBUFF_DATA_USES_OFFSET |
821 | skb->end = size; | 833 | skb->end = size; |
@@ -1812,7 +1824,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) | |||
1812 | long csstart; | 1824 | long csstart; |
1813 | 1825 | ||
1814 | if (skb->ip_summed == CHECKSUM_PARTIAL) | 1826 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
1815 | csstart = skb->csum_start - skb_headroom(skb); | 1827 | csstart = skb_checksum_start_offset(skb); |
1816 | else | 1828 | else |
1817 | csstart = skb_headlen(skb); | 1829 | csstart = skb_headlen(skb); |
1818 | 1830 | ||
diff --git a/net/core/sock.c b/net/core/sock.c index e5af8d5d5b50..a6b9e8061f34 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -992,17 +992,18 @@ static inline void sock_lock_init(struct sock *sk) | |||
992 | /* | 992 | /* |
993 | * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet, | 993 | * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet, |
994 | * even temporarly, because of RCU lookups. sk_node should also be left as is. | 994 | * even temporarly, because of RCU lookups. sk_node should also be left as is. |
995 | * We must not copy fields between sk_dontcopy_begin and sk_dontcopy_end | ||
995 | */ | 996 | */ |
996 | static void sock_copy(struct sock *nsk, const struct sock *osk) | 997 | static void sock_copy(struct sock *nsk, const struct sock *osk) |
997 | { | 998 | { |
998 | #ifdef CONFIG_SECURITY_NETWORK | 999 | #ifdef CONFIG_SECURITY_NETWORK |
999 | void *sptr = nsk->sk_security; | 1000 | void *sptr = nsk->sk_security; |
1000 | #endif | 1001 | #endif |
1001 | BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) != | 1002 | memcpy(nsk, osk, offsetof(struct sock, sk_dontcopy_begin)); |
1002 | sizeof(osk->sk_node) + sizeof(osk->sk_refcnt) + | 1003 | |
1003 | sizeof(osk->sk_tx_queue_mapping)); | 1004 | memcpy(&nsk->sk_dontcopy_end, &osk->sk_dontcopy_end, |
1004 | memcpy(&nsk->sk_copy_start, &osk->sk_copy_start, | 1005 | osk->sk_prot->obj_size - offsetof(struct sock, sk_dontcopy_end)); |
1005 | osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start)); | 1006 | |
1006 | #ifdef CONFIG_SECURITY_NETWORK | 1007 | #ifdef CONFIG_SECURITY_NETWORK |
1007 | nsk->sk_security = sptr; | 1008 | nsk->sk_security = sptr; |
1008 | security_sk_clone(osk, nsk); | 1009 | security_sk_clone(osk, nsk); |
diff --git a/net/core/timestamping.c b/net/core/timestamping.c index c19bb4ee405e..7e7ca375d431 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c | |||
@@ -26,12 +26,12 @@ static struct sock_filter ptp_filter[] = { | |||
26 | PTP_FILTER | 26 | PTP_FILTER |
27 | }; | 27 | }; |
28 | 28 | ||
29 | static unsigned int classify(struct sk_buff *skb) | 29 | static unsigned int classify(const struct sk_buff *skb) |
30 | { | 30 | { |
31 | if (likely(skb->dev && | 31 | if (likely(skb->dev && |
32 | skb->dev->phydev && | 32 | skb->dev->phydev && |
33 | skb->dev->phydev->drv)) | 33 | skb->dev->phydev->drv)) |
34 | return sk_run_filter(skb, ptp_filter, ARRAY_SIZE(ptp_filter)); | 34 | return sk_run_filter(skb, ptp_filter); |
35 | else | 35 | else |
36 | return PTP_CLASS_NONE; | 36 | return PTP_CLASS_NONE; |
37 | } | 37 | } |
diff --git a/net/dcb/Makefile b/net/dcb/Makefile index 9930f4cde818..c1282c9e64fa 100644 --- a/net/dcb/Makefile +++ b/net/dcb/Makefile | |||
@@ -1 +1 @@ | |||
obj-$(CONFIG_DCB) += dcbnl.o | obj-$(CONFIG_DCB) += dcbnl.o dcbevent.o | ||
diff --git a/net/dcb/dcbevent.c b/net/dcb/dcbevent.c new file mode 100644 index 000000000000..665a8802105a --- /dev/null +++ b/net/dcb/dcbevent.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010, Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
16 | * | ||
17 | * Author: John Fastabend <john.r.fastabend@intel.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/rtnetlink.h> | ||
21 | #include <linux/notifier.h> | ||
22 | |||
23 | static ATOMIC_NOTIFIER_HEAD(dcbevent_notif_chain); | ||
24 | |||
25 | int register_dcbevent_notifier(struct notifier_block *nb) | ||
26 | { | ||
27 | return atomic_notifier_chain_register(&dcbevent_notif_chain, nb); | ||
28 | } | ||
29 | EXPORT_SYMBOL(register_dcbevent_notifier); | ||
30 | |||
31 | int unregister_dcbevent_notifier(struct notifier_block *nb) | ||
32 | { | ||
33 | return atomic_notifier_chain_unregister(&dcbevent_notif_chain, nb); | ||
34 | } | ||
35 | EXPORT_SYMBOL(unregister_dcbevent_notifier); | ||
36 | |||
37 | int call_dcbevent_notifiers(unsigned long val, void *v) | ||
38 | { | ||
39 | return atomic_notifier_call_chain(&dcbevent_notif_chain, val, v); | ||
40 | } | ||
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index 19ac2b985485..9399af565715 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <net/netlink.h> | 23 | #include <net/netlink.h> |
24 | #include <net/rtnetlink.h> | 24 | #include <net/rtnetlink.h> |
25 | #include <linux/dcbnl.h> | 25 | #include <linux/dcbnl.h> |
26 | #include <net/dcbevent.h> | ||
26 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
27 | #include <net/sock.h> | 28 | #include <net/sock.h> |
28 | 29 | ||
@@ -66,6 +67,9 @@ static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { | |||
66 | [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, | 67 | [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, |
67 | [DCB_ATTR_BCN] = {.type = NLA_NESTED}, | 68 | [DCB_ATTR_BCN] = {.type = NLA_NESTED}, |
68 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, | 69 | [DCB_ATTR_APP] = {.type = NLA_NESTED}, |
70 | [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, | ||
71 | [DCB_ATTR_DCBX] = {.type = NLA_U8}, | ||
72 | [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, | ||
69 | }; | 73 | }; |
70 | 74 | ||
71 | /* DCB priority flow control to User Priority nested attributes */ | 75 | /* DCB priority flow control to User Priority nested attributes */ |
@@ -122,6 +126,7 @@ static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { | |||
122 | [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, | 126 | [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, |
123 | [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, | 127 | [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, |
124 | [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, | 128 | [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, |
129 | [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, | ||
125 | }; | 130 | }; |
126 | 131 | ||
127 | /* DCB capabilities nested attributes. */ | 132 | /* DCB capabilities nested attributes. */ |
@@ -167,6 +172,28 @@ static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { | |||
167 | [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, | 172 | [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, |
168 | }; | 173 | }; |
169 | 174 | ||
175 | /* IEEE 802.1Qaz nested attributes. */ | ||
176 | static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { | ||
177 | [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, | ||
178 | [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, | ||
179 | [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, | ||
180 | }; | ||
181 | |||
182 | static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { | ||
183 | [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, | ||
184 | }; | ||
185 | |||
186 | /* DCB number of traffic classes nested attributes. */ | ||
187 | static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { | ||
188 | [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, | ||
189 | [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, | ||
190 | [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, | ||
191 | [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, | ||
192 | }; | ||
193 | |||
194 | static LIST_HEAD(dcb_app_list); | ||
195 | static DEFINE_SPINLOCK(dcb_lock); | ||
196 | |||
170 | /* standard netlink reply call */ | 197 | /* standard netlink reply call */ |
171 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, | 198 | static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, |
172 | u32 seq, u16 flags) | 199 | u32 seq, u16 flags) |
@@ -622,12 +649,12 @@ out: | |||
622 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | 649 | static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, |
623 | u32 pid, u32 seq, u16 flags) | 650 | u32 pid, u32 seq, u16 flags) |
624 | { | 651 | { |
625 | int ret = -EINVAL; | 652 | int err, ret = -EINVAL; |
626 | u16 id; | 653 | u16 id; |
627 | u8 up, idtype; | 654 | u8 up, idtype; |
628 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; | 655 | struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; |
629 | 656 | ||
630 | if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->setapp) | 657 | if (!tb[DCB_ATTR_APP]) |
631 | goto out; | 658 | goto out; |
632 | 659 | ||
633 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], | 660 | ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], |
@@ -651,9 +678,18 @@ static int dcbnl_setapp(struct net_device *netdev, struct nlattr **tb, | |||
651 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); | 678 | id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); |
652 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); | 679 | up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); |
653 | 680 | ||
654 | ret = dcbnl_reply(netdev->dcbnl_ops->setapp(netdev, idtype, id, up), | 681 | if (netdev->dcbnl_ops->setapp) { |
655 | RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | 682 | err = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); |
656 | pid, seq, flags); | 683 | } else { |
684 | struct dcb_app app; | ||
685 | app.selector = idtype; | ||
686 | app.protocol = id; | ||
687 | app.priority = up; | ||
688 | err = dcb_setapp(netdev, &app); | ||
689 | } | ||
690 | |||
691 | ret = dcbnl_reply(err, RTM_SETDCB, DCB_CMD_SAPP, DCB_ATTR_APP, | ||
692 | pid, seq, flags); | ||
657 | out: | 693 | out: |
658 | return ret; | 694 | return ret; |
659 | } | 695 | } |
@@ -1118,6 +1154,276 @@ err: | |||
1118 | return ret; | 1154 | return ret; |
1119 | } | 1155 | } |
1120 | 1156 | ||
1157 | /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not | ||
1158 | * be completed the entire msg is aborted and error value is returned. | ||
1159 | * No attempt is made to reconcile the case where only part of the | ||
1160 | * cmd can be completed. | ||
1161 | */ | ||
1162 | static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | ||
1163 | u32 pid, u32 seq, u16 flags) | ||
1164 | { | ||
1165 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1166 | struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; | ||
1167 | int err = -EOPNOTSUPP; | ||
1168 | |||
1169 | if (!ops) | ||
1170 | goto err; | ||
1171 | |||
1172 | err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, | ||
1173 | tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); | ||
1174 | if (err) | ||
1175 | goto err; | ||
1176 | |||
1177 | if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { | ||
1178 | struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); | ||
1179 | err = ops->ieee_setets(netdev, ets); | ||
1180 | if (err) | ||
1181 | goto err; | ||
1182 | } | ||
1183 | |||
1184 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) { | ||
1185 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | ||
1186 | err = ops->ieee_setpfc(netdev, pfc); | ||
1187 | if (err) | ||
1188 | goto err; | ||
1189 | } | ||
1190 | |||
1191 | if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { | ||
1192 | struct nlattr *attr; | ||
1193 | int rem; | ||
1194 | |||
1195 | nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { | ||
1196 | struct dcb_app *app_data; | ||
1197 | if (nla_type(attr) != DCB_ATTR_IEEE_APP) | ||
1198 | continue; | ||
1199 | app_data = nla_data(attr); | ||
1200 | if (ops->ieee_setapp) | ||
1201 | err = ops->ieee_setapp(netdev, app_data); | ||
1202 | else | ||
1203 | err = dcb_setapp(netdev, app_data); | ||
1204 | if (err) | ||
1205 | goto err; | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | err: | ||
1210 | dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE, | ||
1211 | pid, seq, flags); | ||
1212 | return err; | ||
1213 | } | ||
1214 | |||
1215 | |||
1216 | /* Handle IEEE 802.1Qaz GET commands. */ | ||
1217 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | ||
1218 | u32 pid, u32 seq, u16 flags) | ||
1219 | { | ||
1220 | struct sk_buff *skb; | ||
1221 | struct nlmsghdr *nlh; | ||
1222 | struct dcbmsg *dcb; | ||
1223 | struct nlattr *ieee, *app; | ||
1224 | struct dcb_app_type *itr; | ||
1225 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1226 | int err; | ||
1227 | |||
1228 | if (!ops) | ||
1229 | return -EOPNOTSUPP; | ||
1230 | |||
1231 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1232 | if (!skb) | ||
1233 | return -ENOBUFS; | ||
1234 | |||
1235 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1236 | |||
1237 | dcb = NLMSG_DATA(nlh); | ||
1238 | dcb->dcb_family = AF_UNSPEC; | ||
1239 | dcb->cmd = DCB_CMD_IEEE_GET; | ||
1240 | |||
1241 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | ||
1242 | |||
1243 | ieee = nla_nest_start(skb, DCB_ATTR_IEEE); | ||
1244 | if (!ieee) | ||
1245 | goto nla_put_failure; | ||
1246 | |||
1247 | if (ops->ieee_getets) { | ||
1248 | struct ieee_ets ets; | ||
1249 | err = ops->ieee_getets(netdev, &ets); | ||
1250 | if (!err) | ||
1251 | NLA_PUT(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets); | ||
1252 | } | ||
1253 | |||
1254 | if (ops->ieee_getpfc) { | ||
1255 | struct ieee_pfc pfc; | ||
1256 | err = ops->ieee_getpfc(netdev, &pfc); | ||
1257 | if (!err) | ||
1258 | NLA_PUT(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc); | ||
1259 | } | ||
1260 | |||
1261 | app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); | ||
1262 | if (!app) | ||
1263 | goto nla_put_failure; | ||
1264 | |||
1265 | spin_lock(&dcb_lock); | ||
1266 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1267 | if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) | ||
1268 | NLA_PUT(skb, DCB_ATTR_IEEE_APP, | ||
1269 | sizeof(itr->app), &itr->app); | ||
1270 | } | ||
1271 | spin_unlock(&dcb_lock); | ||
1272 | nla_nest_end(skb, app); | ||
1273 | |||
1274 | nla_nest_end(skb, ieee); | ||
1275 | nlmsg_end(skb, nlh); | ||
1276 | |||
1277 | return rtnl_unicast(skb, &init_net, pid); | ||
1278 | nla_put_failure: | ||
1279 | nlmsg_cancel(skb, nlh); | ||
1280 | nlmsg_failure: | ||
1281 | kfree_skb(skb); | ||
1282 | return -1; | ||
1283 | } | ||
1284 | |||
1285 | /* DCBX configuration */ | ||
1286 | static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb, | ||
1287 | u32 pid, u32 seq, u16 flags) | ||
1288 | { | ||
1289 | int ret; | ||
1290 | |||
1291 | if (!netdev->dcbnl_ops->getdcbx) | ||
1292 | return -EOPNOTSUPP; | ||
1293 | |||
1294 | ret = dcbnl_reply(netdev->dcbnl_ops->getdcbx(netdev), RTM_GETDCB, | ||
1295 | DCB_CMD_GDCBX, DCB_ATTR_DCBX, pid, seq, flags); | ||
1296 | |||
1297 | return ret; | ||
1298 | } | ||
1299 | |||
1300 | static int dcbnl_setdcbx(struct net_device *netdev, struct nlattr **tb, | ||
1301 | u32 pid, u32 seq, u16 flags) | ||
1302 | { | ||
1303 | int ret; | ||
1304 | u8 value; | ||
1305 | |||
1306 | if (!netdev->dcbnl_ops->setdcbx) | ||
1307 | return -EOPNOTSUPP; | ||
1308 | |||
1309 | if (!tb[DCB_ATTR_DCBX]) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | value = nla_get_u8(tb[DCB_ATTR_DCBX]); | ||
1313 | |||
1314 | ret = dcbnl_reply(netdev->dcbnl_ops->setdcbx(netdev, value), | ||
1315 | RTM_SETDCB, DCB_CMD_SDCBX, DCB_ATTR_DCBX, | ||
1316 | pid, seq, flags); | ||
1317 | |||
1318 | return ret; | ||
1319 | } | ||
1320 | |||
1321 | static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1322 | u32 pid, u32 seq, u16 flags) | ||
1323 | { | ||
1324 | struct sk_buff *dcbnl_skb; | ||
1325 | struct nlmsghdr *nlh; | ||
1326 | struct dcbmsg *dcb; | ||
1327 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; | ||
1328 | u8 value; | ||
1329 | int ret, i; | ||
1330 | int getall = 0; | ||
1331 | |||
1332 | if (!netdev->dcbnl_ops->getfeatcfg) | ||
1333 | return -EOPNOTSUPP; | ||
1334 | |||
1335 | if (!tb[DCB_ATTR_FEATCFG]) | ||
1336 | return -EINVAL; | ||
1337 | |||
1338 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1339 | dcbnl_featcfg_nest); | ||
1340 | if (ret) | ||
1341 | goto err_out; | ||
1342 | |||
1343 | dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1344 | if (!dcbnl_skb) { | ||
1345 | ret = -ENOBUFS; | ||
1346 | goto err_out; | ||
1347 | } | ||
1348 | |||
1349 | nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1350 | |||
1351 | dcb = NLMSG_DATA(nlh); | ||
1352 | dcb->dcb_family = AF_UNSPEC; | ||
1353 | dcb->cmd = DCB_CMD_GFEATCFG; | ||
1354 | |||
1355 | nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG); | ||
1356 | if (!nest) { | ||
1357 | ret = -EMSGSIZE; | ||
1358 | goto nla_put_failure; | ||
1359 | } | ||
1360 | |||
1361 | if (data[DCB_FEATCFG_ATTR_ALL]) | ||
1362 | getall = 1; | ||
1363 | |||
1364 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1365 | if (!getall && !data[i]) | ||
1366 | continue; | ||
1367 | |||
1368 | ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); | ||
1369 | if (!ret) | ||
1370 | ret = nla_put_u8(dcbnl_skb, i, value); | ||
1371 | |||
1372 | if (ret) { | ||
1373 | nla_nest_cancel(dcbnl_skb, nest); | ||
1374 | goto nla_put_failure; | ||
1375 | } | ||
1376 | } | ||
1377 | nla_nest_end(dcbnl_skb, nest); | ||
1378 | |||
1379 | nlmsg_end(dcbnl_skb, nlh); | ||
1380 | |||
1381 | return rtnl_unicast(dcbnl_skb, &init_net, pid); | ||
1382 | nla_put_failure: | ||
1383 | nlmsg_cancel(dcbnl_skb, nlh); | ||
1384 | nlmsg_failure: | ||
1385 | kfree_skb(dcbnl_skb); | ||
1386 | err_out: | ||
1387 | return ret; | ||
1388 | } | ||
1389 | |||
1390 | static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb, | ||
1391 | u32 pid, u32 seq, u16 flags) | ||
1392 | { | ||
1393 | struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; | ||
1394 | int ret, i; | ||
1395 | u8 value; | ||
1396 | |||
1397 | if (!netdev->dcbnl_ops->setfeatcfg) | ||
1398 | return -ENOTSUPP; | ||
1399 | |||
1400 | if (!tb[DCB_ATTR_FEATCFG]) | ||
1401 | return -EINVAL; | ||
1402 | |||
1403 | ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], | ||
1404 | dcbnl_featcfg_nest); | ||
1405 | |||
1406 | if (ret) | ||
1407 | goto err; | ||
1408 | |||
1409 | for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { | ||
1410 | if (data[i] == NULL) | ||
1411 | continue; | ||
1412 | |||
1413 | value = nla_get_u8(data[i]); | ||
1414 | |||
1415 | ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); | ||
1416 | |||
1417 | if (ret) | ||
1418 | goto err; | ||
1419 | } | ||
1420 | err: | ||
1421 | dcbnl_reply(ret, RTM_SETDCB, DCB_CMD_SFEATCFG, DCB_ATTR_FEATCFG, | ||
1422 | pid, seq, flags); | ||
1423 | |||
1424 | return ret; | ||
1425 | } | ||
1426 | |||
1121 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1427 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1122 | { | 1428 | { |
1123 | struct net *net = sock_net(skb->sk); | 1429 | struct net *net = sock_net(skb->sk); |
@@ -1223,6 +1529,30 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1223 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, | 1529 | ret = dcbnl_setapp(netdev, tb, pid, nlh->nlmsg_seq, |
1224 | nlh->nlmsg_flags); | 1530 | nlh->nlmsg_flags); |
1225 | goto out; | 1531 | goto out; |
1532 | case DCB_CMD_IEEE_SET: | ||
1533 | ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq, | ||
1534 | nlh->nlmsg_flags); | ||
1535 | goto out; | ||
1536 | case DCB_CMD_IEEE_GET: | ||
1537 | ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
1538 | nlh->nlmsg_flags); | ||
1539 | goto out; | ||
1540 | case DCB_CMD_GDCBX: | ||
1541 | ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
1542 | nlh->nlmsg_flags); | ||
1543 | goto out; | ||
1544 | case DCB_CMD_SDCBX: | ||
1545 | ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq, | ||
1546 | nlh->nlmsg_flags); | ||
1547 | goto out; | ||
1548 | case DCB_CMD_GFEATCFG: | ||
1549 | ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1550 | nlh->nlmsg_flags); | ||
1551 | goto out; | ||
1552 | case DCB_CMD_SFEATCFG: | ||
1553 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | ||
1554 | nlh->nlmsg_flags); | ||
1555 | goto out; | ||
1226 | default: | 1556 | default: |
1227 | goto errout; | 1557 | goto errout; |
1228 | } | 1558 | } |
@@ -1233,8 +1563,94 @@ out: | |||
1233 | return ret; | 1563 | return ret; |
1234 | } | 1564 | } |
1235 | 1565 | ||
1566 | /** | ||
1567 | * dcb_getapp - retrieve the DCBX application user priority | ||
1568 | * | ||
1569 | * On success returns a non-zero 802.1p user priority bitmap | ||
1570 | * otherwise returns 0 as the invalid user priority bitmap to | ||
1571 | * indicate an error. | ||
1572 | */ | ||
1573 | u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) | ||
1574 | { | ||
1575 | struct dcb_app_type *itr; | ||
1576 | u8 prio = 0; | ||
1577 | |||
1578 | spin_lock(&dcb_lock); | ||
1579 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1580 | if (itr->app.selector == app->selector && | ||
1581 | itr->app.protocol == app->protocol && | ||
1582 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1583 | prio = itr->app.priority; | ||
1584 | break; | ||
1585 | } | ||
1586 | } | ||
1587 | spin_unlock(&dcb_lock); | ||
1588 | |||
1589 | return prio; | ||
1590 | } | ||
1591 | EXPORT_SYMBOL(dcb_getapp); | ||
1592 | |||
1593 | /** | ||
1594 | * ixgbe_dcbnl_setapp - add dcb application data to app list | ||
1595 | * | ||
1596 | * Priority 0 is the default priority this removes applications | ||
1597 | * from the app list if the priority is set to zero. | ||
1598 | */ | ||
1599 | u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) | ||
1600 | { | ||
1601 | struct dcb_app_type *itr; | ||
1602 | |||
1603 | spin_lock(&dcb_lock); | ||
1604 | /* Search for existing match and replace */ | ||
1605 | list_for_each_entry(itr, &dcb_app_list, list) { | ||
1606 | if (itr->app.selector == new->selector && | ||
1607 | itr->app.protocol == new->protocol && | ||
1608 | (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) { | ||
1609 | if (new->priority) | ||
1610 | itr->app.priority = new->priority; | ||
1611 | else { | ||
1612 | list_del(&itr->list); | ||
1613 | kfree(itr); | ||
1614 | } | ||
1615 | goto out; | ||
1616 | } | ||
1617 | } | ||
1618 | /* App type does not exist add new application type */ | ||
1619 | if (new->priority) { | ||
1620 | struct dcb_app_type *entry; | ||
1621 | entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC); | ||
1622 | if (!entry) { | ||
1623 | spin_unlock(&dcb_lock); | ||
1624 | return -ENOMEM; | ||
1625 | } | ||
1626 | |||
1627 | memcpy(&entry->app, new, sizeof(*new)); | ||
1628 | strncpy(entry->name, dev->name, IFNAMSIZ); | ||
1629 | list_add(&entry->list, &dcb_app_list); | ||
1630 | } | ||
1631 | out: | ||
1632 | spin_unlock(&dcb_lock); | ||
1633 | call_dcbevent_notifiers(DCB_APP_EVENT, new); | ||
1634 | return 0; | ||
1635 | } | ||
1636 | EXPORT_SYMBOL(dcb_setapp); | ||
1637 | |||
1638 | static void dcb_flushapp(void) | ||
1639 | { | ||
1640 | struct dcb_app_type *app; | ||
1641 | |||
1642 | spin_lock(&dcb_lock); | ||
1643 | list_for_each_entry(app, &dcb_app_list, list) { | ||
1644 | list_del(&app->list); | ||
1645 | kfree(app); | ||
1646 | } | ||
1647 | spin_unlock(&dcb_lock); | ||
1648 | } | ||
1649 | |||
1236 | static int __init dcbnl_init(void) | 1650 | static int __init dcbnl_init(void) |
1237 | { | 1651 | { |
1652 | INIT_LIST_HEAD(&dcb_app_list); | ||
1653 | |||
1238 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); | 1654 | rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); |
1239 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); | 1655 | rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); |
1240 | 1656 | ||
@@ -1246,7 +1662,6 @@ static void __exit dcbnl_exit(void) | |||
1246 | { | 1662 | { |
1247 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); | 1663 | rtnl_unregister(PF_UNSPEC, RTM_GETDCB); |
1248 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); | 1664 | rtnl_unregister(PF_UNSPEC, RTM_SETDCB); |
1665 | dcb_flushapp(); | ||
1249 | } | 1666 | } |
1250 | module_exit(dcbnl_exit); | 1667 | module_exit(dcbnl_exit); |
1251 | |||
1252 | |||
diff --git a/net/dccp/Makefile b/net/dccp/Makefile index 2991efcc8dea..5c8362b037ed 100644 --- a/net/dccp/Makefile +++ b/net/dccp/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o | 1 | obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o |
2 | 2 | ||
3 | dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o | 3 | dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o \ |
4 | 4 | qpolicy.o | |
5 | # | 5 | # |
6 | # CCID algorithms to be used by dccp.ko | 6 | # CCID algorithms to be used by dccp.ko |
7 | # | 7 | # |
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 92a6fcb40d7d..25b7a8d1ad58 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -1,444 +1,375 @@ | |||
1 | /* | 1 | /* |
2 | * net/dccp/ackvec.c | 2 | * net/dccp/ackvec.c |
3 | * | 3 | * |
4 | * An implementation of the DCCP protocol | 4 | * An implementation of Ack Vectors for the DCCP protocol |
5 | * Copyright (c) 2007 University of Aberdeen, Scotland, UK | ||
5 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net> | 6 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net> |
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
9 | * Free Software Foundation; version 2 of the License; | 10 | * Free Software Foundation; version 2 of the License; |
10 | */ | 11 | */ |
11 | |||
12 | #include "ackvec.h" | ||
13 | #include "dccp.h" | 12 | #include "dccp.h" |
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
20 | 15 | ||
21 | #include <net/sock.h> | ||
22 | |||
23 | static struct kmem_cache *dccp_ackvec_slab; | 16 | static struct kmem_cache *dccp_ackvec_slab; |
24 | static struct kmem_cache *dccp_ackvec_record_slab; | 17 | static struct kmem_cache *dccp_ackvec_record_slab; |
25 | 18 | ||
26 | static struct dccp_ackvec_record *dccp_ackvec_record_new(void) | 19 | struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) |
27 | { | 20 | { |
28 | struct dccp_ackvec_record *avr = | 21 | struct dccp_ackvec *av = kmem_cache_zalloc(dccp_ackvec_slab, priority); |
29 | kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC); | ||
30 | 22 | ||
31 | if (avr != NULL) | 23 | if (av != NULL) { |
32 | INIT_LIST_HEAD(&avr->avr_node); | 24 | av->av_buf_head = av->av_buf_tail = DCCPAV_MAX_ACKVEC_LEN - 1; |
33 | 25 | INIT_LIST_HEAD(&av->av_records); | |
34 | return avr; | 26 | } |
27 | return av; | ||
35 | } | 28 | } |
36 | 29 | ||
37 | static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr) | 30 | static void dccp_ackvec_purge_records(struct dccp_ackvec *av) |
38 | { | 31 | { |
39 | if (unlikely(avr == NULL)) | 32 | struct dccp_ackvec_record *cur, *next; |
40 | return; | 33 | |
41 | /* Check if deleting a linked record */ | 34 | list_for_each_entry_safe(cur, next, &av->av_records, avr_node) |
42 | WARN_ON(!list_empty(&avr->avr_node)); | 35 | kmem_cache_free(dccp_ackvec_record_slab, cur); |
43 | kmem_cache_free(dccp_ackvec_record_slab, avr); | 36 | INIT_LIST_HEAD(&av->av_records); |
44 | } | 37 | } |
45 | 38 | ||
46 | static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, | 39 | void dccp_ackvec_free(struct dccp_ackvec *av) |
47 | struct dccp_ackvec_record *avr) | ||
48 | { | 40 | { |
49 | /* | 41 | if (likely(av != NULL)) { |
50 | * AVRs are sorted by seqno. Since we are sending them in order, we | 42 | dccp_ackvec_purge_records(av); |
51 | * just add the AVR at the head of the list. | 43 | kmem_cache_free(dccp_ackvec_slab, av); |
52 | * -sorbo. | ||
53 | */ | ||
54 | if (!list_empty(&av->av_records)) { | ||
55 | const struct dccp_ackvec_record *head = | ||
56 | list_entry(av->av_records.next, | ||
57 | struct dccp_ackvec_record, | ||
58 | avr_node); | ||
59 | BUG_ON(before48(avr->avr_ack_seqno, head->avr_ack_seqno)); | ||
60 | } | 44 | } |
61 | |||
62 | list_add(&avr->avr_node, &av->av_records); | ||
63 | } | 45 | } |
64 | 46 | ||
65 | int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | 47 | /** |
48 | * dccp_ackvec_update_records - Record information about sent Ack Vectors | ||
49 | * @av: Ack Vector records to update | ||
50 | * @seqno: Sequence number of the packet carrying the Ack Vector just sent | ||
51 | * @nonce_sum: The sum of all buffer nonces contained in the Ack Vector | ||
52 | */ | ||
53 | int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum) | ||
66 | { | 54 | { |
67 | struct dccp_sock *dp = dccp_sk(sk); | ||
68 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | ||
69 | /* Figure out how many options do we need to represent the ackvec */ | ||
70 | const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); | ||
71 | u16 len = av->av_vec_len + 2 * nr_opts, i; | ||
72 | u32 elapsed_time; | ||
73 | const unsigned char *tail, *from; | ||
74 | unsigned char *to; | ||
75 | struct dccp_ackvec_record *avr; | 55 | struct dccp_ackvec_record *avr; |
76 | suseconds_t delta; | ||
77 | |||
78 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
79 | return -1; | ||
80 | |||
81 | delta = ktime_us_delta(ktime_get_real(), av->av_time); | ||
82 | elapsed_time = delta / 10; | ||
83 | 56 | ||
84 | if (elapsed_time != 0 && | 57 | avr = kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC); |
85 | dccp_insert_option_elapsed_time(skb, elapsed_time)) | ||
86 | return -1; | ||
87 | |||
88 | avr = dccp_ackvec_record_new(); | ||
89 | if (avr == NULL) | 58 | if (avr == NULL) |
90 | return -1; | 59 | return -ENOBUFS; |
91 | |||
92 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | ||
93 | |||
94 | to = skb_push(skb, len); | ||
95 | len = av->av_vec_len; | ||
96 | from = av->av_buf + av->av_buf_head; | ||
97 | tail = av->av_buf + DCCP_MAX_ACKVEC_LEN; | ||
98 | |||
99 | for (i = 0; i < nr_opts; ++i) { | ||
100 | int copylen = len; | ||
101 | |||
102 | if (len > DCCP_SINGLE_OPT_MAXLEN) | ||
103 | copylen = DCCP_SINGLE_OPT_MAXLEN; | ||
104 | |||
105 | *to++ = DCCPO_ACK_VECTOR_0; | ||
106 | *to++ = copylen + 2; | ||
107 | |||
108 | /* Check if buf_head wraps */ | ||
109 | if (from + copylen > tail) { | ||
110 | const u16 tailsize = tail - from; | ||
111 | |||
112 | memcpy(to, from, tailsize); | ||
113 | to += tailsize; | ||
114 | len -= tailsize; | ||
115 | copylen -= tailsize; | ||
116 | from = av->av_buf; | ||
117 | } | ||
118 | |||
119 | memcpy(to, from, copylen); | ||
120 | from += copylen; | ||
121 | to += copylen; | ||
122 | len -= copylen; | ||
123 | } | ||
124 | 60 | ||
61 | avr->avr_ack_seqno = seqno; | ||
62 | avr->avr_ack_ptr = av->av_buf_head; | ||
63 | avr->avr_ack_ackno = av->av_buf_ackno; | ||
64 | avr->avr_ack_nonce = nonce_sum; | ||
65 | avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head); | ||
125 | /* | 66 | /* |
126 | * From RFC 4340, A.2: | 67 | * When the buffer overflows, we keep no more than one record. This is |
127 | * | 68 | * the simplest way of disambiguating sender-Acks dating from before the |
128 | * For each acknowledgement it sends, the HC-Receiver will add an | 69 | * overflow from sender-Acks which refer to after the overflow; a simple |
129 | * acknowledgement record. ack_seqno will equal the HC-Receiver | 70 | * solution is preferable here since we are handling an exception. |
130 | * sequence number it used for the ack packet; ack_ptr will equal | ||
131 | * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will | ||
132 | * equal buf_nonce. | ||
133 | */ | 71 | */ |
134 | avr->avr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; | 72 | if (av->av_overflow) |
135 | avr->avr_ack_ptr = av->av_buf_head; | 73 | dccp_ackvec_purge_records(av); |
136 | avr->avr_ack_ackno = av->av_buf_ackno; | 74 | /* |
137 | avr->avr_ack_nonce = av->av_buf_nonce; | 75 | * Since GSS is incremented for each packet, the list is automatically |
138 | avr->avr_sent_len = av->av_vec_len; | 76 | * arranged in descending order of @ack_seqno. |
139 | 77 | */ | |
140 | dccp_ackvec_insert_avr(av, avr); | 78 | list_add(&avr->avr_node, &av->av_records); |
141 | 79 | ||
142 | dccp_pr_debug("%s ACK Vector 0, len=%d, ack_seqno=%llu, " | 80 | dccp_pr_debug("Added Vector, ack_seqno=%llu, ack_ackno=%llu (rl=%u)\n", |
143 | "ack_ackno=%llu\n", | ||
144 | dccp_role(sk), avr->avr_sent_len, | ||
145 | (unsigned long long)avr->avr_ack_seqno, | 81 | (unsigned long long)avr->avr_ack_seqno, |
146 | (unsigned long long)avr->avr_ack_ackno); | 82 | (unsigned long long)avr->avr_ack_ackno, |
83 | avr->avr_ack_runlen); | ||
147 | return 0; | 84 | return 0; |
148 | } | 85 | } |
149 | 86 | ||
150 | struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) | 87 | static struct dccp_ackvec_record *dccp_ackvec_lookup(struct list_head *av_list, |
88 | const u64 ackno) | ||
151 | { | 89 | { |
152 | struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority); | 90 | struct dccp_ackvec_record *avr; |
153 | 91 | /* | |
154 | if (av != NULL) { | 92 | * Exploit that records are inserted in descending order of sequence |
155 | av->av_buf_head = DCCP_MAX_ACKVEC_LEN - 1; | 93 | * number, start with the oldest record first. If @ackno is `before' |
156 | av->av_buf_ackno = UINT48_MAX + 1; | 94 | * the earliest ack_ackno, the packet is too old to be considered. |
157 | av->av_buf_nonce = 0; | 95 | */ |
158 | av->av_time = ktime_set(0, 0); | 96 | list_for_each_entry_reverse(avr, av_list, avr_node) { |
159 | av->av_vec_len = 0; | 97 | if (avr->avr_ack_seqno == ackno) |
160 | INIT_LIST_HEAD(&av->av_records); | 98 | return avr; |
99 | if (before48(ackno, avr->avr_ack_seqno)) | ||
100 | break; | ||
161 | } | 101 | } |
162 | 102 | return NULL; | |
163 | return av; | ||
164 | } | 103 | } |
165 | 104 | ||
166 | void dccp_ackvec_free(struct dccp_ackvec *av) | 105 | /* |
106 | * Buffer index and length computation using modulo-buffersize arithmetic. | ||
107 | * Note that, as pointers move from right to left, head is `before' tail. | ||
108 | */ | ||
109 | static inline u16 __ackvec_idx_add(const u16 a, const u16 b) | ||
167 | { | 110 | { |
168 | if (unlikely(av == NULL)) | 111 | return (a + b) % DCCPAV_MAX_ACKVEC_LEN; |
169 | return; | ||
170 | |||
171 | if (!list_empty(&av->av_records)) { | ||
172 | struct dccp_ackvec_record *avr, *next; | ||
173 | |||
174 | list_for_each_entry_safe(avr, next, &av->av_records, avr_node) { | ||
175 | list_del_init(&avr->avr_node); | ||
176 | dccp_ackvec_record_delete(avr); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | kmem_cache_free(dccp_ackvec_slab, av); | ||
181 | } | 112 | } |
182 | 113 | ||
183 | static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av, | 114 | static inline u16 __ackvec_idx_sub(const u16 a, const u16 b) |
184 | const u32 index) | ||
185 | { | 115 | { |
186 | return av->av_buf[index] & DCCP_ACKVEC_STATE_MASK; | 116 | return __ackvec_idx_add(a, DCCPAV_MAX_ACKVEC_LEN - b); |
187 | } | 117 | } |
188 | 118 | ||
189 | static inline u8 dccp_ackvec_len(const struct dccp_ackvec *av, | 119 | u16 dccp_ackvec_buflen(const struct dccp_ackvec *av) |
190 | const u32 index) | ||
191 | { | 120 | { |
192 | return av->av_buf[index] & DCCP_ACKVEC_LEN_MASK; | 121 | if (unlikely(av->av_overflow)) |
122 | return DCCPAV_MAX_ACKVEC_LEN; | ||
123 | return __ackvec_idx_sub(av->av_buf_tail, av->av_buf_head); | ||
193 | } | 124 | } |
194 | 125 | ||
195 | /* | 126 | /** |
196 | * If several packets are missing, the HC-Receiver may prefer to enter multiple | 127 | * dccp_ackvec_update_old - Update previous state as per RFC 4340, 11.4.1 |
197 | * bytes with run length 0, rather than a single byte with a larger run length; | 128 | * @av: non-empty buffer to update |
198 | * this simplifies table updates if one of the missing packets arrives. | 129 | * @distance: negative or zero distance of @seqno from buf_ackno downward |
130 | * @seqno: the (old) sequence number whose record is to be updated | ||
131 | * @state: state in which packet carrying @seqno was received | ||
199 | */ | 132 | */ |
200 | static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, | 133 | static void dccp_ackvec_update_old(struct dccp_ackvec *av, s64 distance, |
201 | const unsigned int packets, | 134 | u64 seqno, enum dccp_ackvec_states state) |
202 | const unsigned char state) | ||
203 | { | 135 | { |
204 | long gap; | 136 | u16 ptr = av->av_buf_head; |
205 | long new_head; | ||
206 | 137 | ||
207 | if (av->av_vec_len + packets > DCCP_MAX_ACKVEC_LEN) | 138 | BUG_ON(distance > 0); |
208 | return -ENOBUFS; | 139 | if (unlikely(dccp_ackvec_is_empty(av))) |
140 | return; | ||
209 | 141 | ||
210 | gap = packets - 1; | 142 | do { |
211 | new_head = av->av_buf_head - packets; | 143 | u8 runlen = dccp_ackvec_runlen(av->av_buf + ptr); |
212 | 144 | ||
213 | if (new_head < 0) { | 145 | if (distance + runlen >= 0) { |
214 | if (gap > 0) { | 146 | /* |
215 | memset(av->av_buf, DCCP_ACKVEC_STATE_NOT_RECEIVED, | 147 | * Only update the state if packet has not been received |
216 | gap + new_head + 1); | 148 | * yet. This is OK as per the second table in RFC 4340, |
217 | gap = -new_head; | 149 | * 11.4.1; i.e. here we are using the following table: |
150 | * RECEIVED | ||
151 | * 0 1 3 | ||
152 | * S +---+---+---+ | ||
153 | * T 0 | 0 | 0 | 0 | | ||
154 | * O +---+---+---+ | ||
155 | * R 1 | 1 | 1 | 1 | | ||
156 | * E +---+---+---+ | ||
157 | * D 3 | 0 | 1 | 3 | | ||
158 | * +---+---+---+ | ||
159 | * The "Not Received" state was set by reserve_seats(). | ||
160 | */ | ||
161 | if (av->av_buf[ptr] == DCCPAV_NOT_RECEIVED) | ||
162 | av->av_buf[ptr] = state; | ||
163 | else | ||
164 | dccp_pr_debug("Not changing %llu state to %u\n", | ||
165 | (unsigned long long)seqno, state); | ||
166 | break; | ||
218 | } | 167 | } |
219 | new_head += DCCP_MAX_ACKVEC_LEN; | ||
220 | } | ||
221 | 168 | ||
222 | av->av_buf_head = new_head; | 169 | distance += runlen + 1; |
170 | ptr = __ackvec_idx_add(ptr, 1); | ||
223 | 171 | ||
224 | if (gap > 0) | 172 | } while (ptr != av->av_buf_tail); |
225 | memset(av->av_buf + av->av_buf_head + 1, | 173 | } |
226 | DCCP_ACKVEC_STATE_NOT_RECEIVED, gap); | ||
227 | 174 | ||
228 | av->av_buf[av->av_buf_head] = state; | 175 | /* Mark @num entries after buf_head as "Not yet received". */ |
229 | av->av_vec_len += packets; | 176 | static void dccp_ackvec_reserve_seats(struct dccp_ackvec *av, u16 num) |
230 | return 0; | 177 | { |
178 | u16 start = __ackvec_idx_add(av->av_buf_head, 1), | ||
179 | len = DCCPAV_MAX_ACKVEC_LEN - start; | ||
180 | |||
181 | /* check for buffer wrap-around */ | ||
182 | if (num > len) { | ||
183 | memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, len); | ||
184 | start = 0; | ||
185 | num -= len; | ||
186 | } | ||
187 | if (num) | ||
188 | memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, num); | ||
231 | } | 189 | } |
232 | 190 | ||
233 | /* | 191 | /** |
234 | * Implements the RFC 4340, Appendix A | 192 | * dccp_ackvec_add_new - Record one or more new entries in Ack Vector buffer |
193 | * @av: container of buffer to update (can be empty or non-empty) | ||
194 | * @num_packets: number of packets to register (must be >= 1) | ||
195 | * @seqno: sequence number of the first packet in @num_packets | ||
196 | * @state: state in which packet carrying @seqno was received | ||
235 | */ | 197 | */ |
236 | int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | 198 | static void dccp_ackvec_add_new(struct dccp_ackvec *av, u32 num_packets, |
237 | const u64 ackno, const u8 state) | 199 | u64 seqno, enum dccp_ackvec_states state) |
238 | { | 200 | { |
239 | /* | 201 | u32 num_cells = num_packets; |
240 | * Check at the right places if the buffer is full, if it is, tell the | ||
241 | * caller to start dropping packets till the HC-Sender acks our ACK | ||
242 | * vectors, when we will free up space in av_buf. | ||
243 | * | ||
244 | * We may well decide to do buffer compression, etc, but for now lets | ||
245 | * just drop. | ||
246 | * | ||
247 | * From Appendix A.1.1 (`New Packets'): | ||
248 | * | ||
249 | * Of course, the circular buffer may overflow, either when the | ||
250 | * HC-Sender is sending data at a very high rate, when the | ||
251 | * HC-Receiver's acknowledgements are not reaching the HC-Sender, | ||
252 | * or when the HC-Sender is forgetting to acknowledge those acks | ||
253 | * (so the HC-Receiver is unable to clean up old state). In this | ||
254 | * case, the HC-Receiver should either compress the buffer (by | ||
255 | * increasing run lengths when possible), transfer its state to | ||
256 | * a larger buffer, or, as a last resort, drop all received | ||
257 | * packets, without processing them whatsoever, until its buffer | ||
258 | * shrinks again. | ||
259 | */ | ||
260 | 202 | ||
261 | /* See if this is the first ackno being inserted */ | 203 | if (num_packets > DCCPAV_BURST_THRESH) { |
262 | if (av->av_vec_len == 0) { | 204 | u32 lost_packets = num_packets - 1; |
263 | av->av_buf[av->av_buf_head] = state; | ||
264 | av->av_vec_len = 1; | ||
265 | } else if (after48(ackno, av->av_buf_ackno)) { | ||
266 | const u64 delta = dccp_delta_seqno(av->av_buf_ackno, ackno); | ||
267 | 205 | ||
206 | DCCP_WARN("Warning: large burst loss (%u)\n", lost_packets); | ||
268 | /* | 207 | /* |
269 | * Look if the state of this packet is the same as the | 208 | * We received 1 packet and have a loss of size "num_packets-1" |
270 | * previous ackno and if so if we can bump the head len. | 209 | * which we squeeze into num_cells-1 rather than reserving an |
210 | * entire byte for each lost packet. | ||
211 | * The reason is that the vector grows in O(burst_length); when | ||
212 | * it grows too large there will no room left for the payload. | ||
213 | * This is a trade-off: if a few packets out of the burst show | ||
214 | * up later, their state will not be changed; it is simply too | ||
215 | * costly to reshuffle/reallocate/copy the buffer each time. | ||
216 | * Should such problems persist, we will need to switch to a | ||
217 | * different underlying data structure. | ||
271 | */ | 218 | */ |
272 | if (delta == 1 && | 219 | for (num_packets = num_cells = 1; lost_packets; ++num_cells) { |
273 | dccp_ackvec_state(av, av->av_buf_head) == state && | 220 | u8 len = min(lost_packets, (u32)DCCPAV_MAX_RUNLEN); |
274 | dccp_ackvec_len(av, av->av_buf_head) < DCCP_ACKVEC_LEN_MASK) | ||
275 | av->av_buf[av->av_buf_head]++; | ||
276 | else if (dccp_ackvec_set_buf_head_state(av, delta, state)) | ||
277 | return -ENOBUFS; | ||
278 | } else { | ||
279 | /* | ||
280 | * A.1.2. Old Packets | ||
281 | * | ||
282 | * When a packet with Sequence Number S <= buf_ackno | ||
283 | * arrives, the HC-Receiver will scan the table for | ||
284 | * the byte corresponding to S. (Indexing structures | ||
285 | * could reduce the complexity of this scan.) | ||
286 | */ | ||
287 | u64 delta = dccp_delta_seqno(ackno, av->av_buf_ackno); | ||
288 | u32 index = av->av_buf_head; | ||
289 | 221 | ||
290 | while (1) { | 222 | av->av_buf_head = __ackvec_idx_sub(av->av_buf_head, 1); |
291 | const u8 len = dccp_ackvec_len(av, index); | 223 | av->av_buf[av->av_buf_head] = DCCPAV_NOT_RECEIVED | len; |
292 | const u8 av_state = dccp_ackvec_state(av, index); | 224 | |
293 | /* | 225 | lost_packets -= len; |
294 | * valid packets not yet in av_buf have a reserved | ||
295 | * entry, with a len equal to 0. | ||
296 | */ | ||
297 | if (av_state == DCCP_ACKVEC_STATE_NOT_RECEIVED && | ||
298 | len == 0 && delta == 0) { /* Found our | ||
299 | reserved seat! */ | ||
300 | dccp_pr_debug("Found %llu reserved seat!\n", | ||
301 | (unsigned long long)ackno); | ||
302 | av->av_buf[index] = state; | ||
303 | goto out; | ||
304 | } | ||
305 | /* len == 0 means one packet */ | ||
306 | if (delta < len + 1) | ||
307 | goto out_duplicate; | ||
308 | |||
309 | delta -= len + 1; | ||
310 | if (++index == DCCP_MAX_ACKVEC_LEN) | ||
311 | index = 0; | ||
312 | } | 226 | } |
313 | } | 227 | } |
314 | 228 | ||
315 | av->av_buf_ackno = ackno; | 229 | if (num_cells + dccp_ackvec_buflen(av) >= DCCPAV_MAX_ACKVEC_LEN) { |
316 | av->av_time = ktime_get_real(); | 230 | DCCP_CRIT("Ack Vector buffer overflow: dropping old entries\n"); |
317 | out: | 231 | av->av_overflow = true; |
318 | return 0; | 232 | } |
233 | |||
234 | av->av_buf_head = __ackvec_idx_sub(av->av_buf_head, num_packets); | ||
235 | if (av->av_overflow) | ||
236 | av->av_buf_tail = av->av_buf_head; | ||
319 | 237 | ||
320 | out_duplicate: | 238 | av->av_buf[av->av_buf_head] = state; |
321 | /* Duplicate packet */ | 239 | av->av_buf_ackno = seqno; |
322 | dccp_pr_debug("Received a dup or already considered lost " | 240 | |
323 | "packet: %llu\n", (unsigned long long)ackno); | 241 | if (num_packets > 1) |
324 | return -EILSEQ; | 242 | dccp_ackvec_reserve_seats(av, num_packets - 1); |
325 | } | 243 | } |
326 | 244 | ||
327 | static void dccp_ackvec_throw_record(struct dccp_ackvec *av, | 245 | /** |
328 | struct dccp_ackvec_record *avr) | 246 | * dccp_ackvec_input - Register incoming packet in the buffer |
247 | */ | ||
248 | void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb) | ||
329 | { | 249 | { |
330 | struct dccp_ackvec_record *next; | 250 | u64 seqno = DCCP_SKB_CB(skb)->dccpd_seq; |
251 | enum dccp_ackvec_states state = DCCPAV_RECEIVED; | ||
331 | 252 | ||
332 | /* sort out vector length */ | 253 | if (dccp_ackvec_is_empty(av)) { |
333 | if (av->av_buf_head <= avr->avr_ack_ptr) | 254 | dccp_ackvec_add_new(av, 1, seqno, state); |
334 | av->av_vec_len = avr->avr_ack_ptr - av->av_buf_head; | 255 | av->av_tail_ackno = seqno; |
335 | else | ||
336 | av->av_vec_len = DCCP_MAX_ACKVEC_LEN - 1 - | ||
337 | av->av_buf_head + avr->avr_ack_ptr; | ||
338 | 256 | ||
339 | /* free records */ | 257 | } else { |
340 | list_for_each_entry_safe_from(avr, next, &av->av_records, avr_node) { | 258 | s64 num_packets = dccp_delta_seqno(av->av_buf_ackno, seqno); |
341 | list_del_init(&avr->avr_node); | 259 | u8 *current_head = av->av_buf + av->av_buf_head; |
342 | dccp_ackvec_record_delete(avr); | ||
343 | } | ||
344 | } | ||
345 | 260 | ||
346 | void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, | 261 | if (num_packets == 1 && |
347 | const u64 ackno) | 262 | dccp_ackvec_state(current_head) == state && |
348 | { | 263 | dccp_ackvec_runlen(current_head) < DCCPAV_MAX_RUNLEN) { |
349 | struct dccp_ackvec_record *avr; | ||
350 | 264 | ||
351 | /* | 265 | *current_head += 1; |
352 | * If we traverse backwards, it should be faster when we have large | 266 | av->av_buf_ackno = seqno; |
353 | * windows. We will be receiving ACKs for stuff we sent a while back | 267 | |
354 | * -sorbo. | 268 | } else if (num_packets > 0) { |
355 | */ | 269 | dccp_ackvec_add_new(av, num_packets, seqno, state); |
356 | list_for_each_entry_reverse(avr, &av->av_records, avr_node) { | 270 | } else { |
357 | if (ackno == avr->avr_ack_seqno) { | 271 | dccp_ackvec_update_old(av, num_packets, seqno, state); |
358 | dccp_pr_debug("%s ACK packet 0, len=%d, ack_seqno=%llu, " | 272 | } |
359 | "ack_ackno=%llu, ACKED!\n", | ||
360 | dccp_role(sk), 1, | ||
361 | (unsigned long long)avr->avr_ack_seqno, | ||
362 | (unsigned long long)avr->avr_ack_ackno); | ||
363 | dccp_ackvec_throw_record(av, avr); | ||
364 | break; | ||
365 | } else if (avr->avr_ack_seqno > ackno) | ||
366 | break; /* old news */ | ||
367 | } | 273 | } |
368 | } | 274 | } |
369 | 275 | ||
370 | static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | 276 | /** |
371 | struct sock *sk, u64 *ackno, | 277 | * dccp_ackvec_clear_state - Perform house-keeping / garbage-collection |
372 | const unsigned char len, | 278 | * This routine is called when the peer acknowledges the receipt of Ack Vectors |
373 | const unsigned char *vector) | 279 | * up to and including @ackno. While based on on section A.3 of RFC 4340, here |
280 | * are additional precautions to prevent corrupted buffer state. In particular, | ||
281 | * we use tail_ackno to identify outdated records; it always marks the earliest | ||
282 | * packet of group (2) in 11.4.2. | ||
283 | */ | ||
284 | void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno) | ||
374 | { | 285 | { |
375 | unsigned char i; | 286 | struct dccp_ackvec_record *avr, *next; |
376 | struct dccp_ackvec_record *avr; | 287 | u8 runlen_now, eff_runlen; |
288 | s64 delta; | ||
377 | 289 | ||
378 | /* Check if we actually sent an ACK vector */ | 290 | avr = dccp_ackvec_lookup(&av->av_records, ackno); |
379 | if (list_empty(&av->av_records)) | 291 | if (avr == NULL) |
380 | return; | 292 | return; |
293 | /* | ||
294 | * Deal with outdated acknowledgments: this arises when e.g. there are | ||
295 | * several old records and the acks from the peer come in slowly. In | ||
296 | * that case we may still have records that pre-date tail_ackno. | ||
297 | */ | ||
298 | delta = dccp_delta_seqno(av->av_tail_ackno, avr->avr_ack_ackno); | ||
299 | if (delta < 0) | ||
300 | goto free_records; | ||
301 | /* | ||
302 | * Deal with overlapping Ack Vectors: don't subtract more than the | ||
303 | * number of packets between tail_ackno and ack_ackno. | ||
304 | */ | ||
305 | eff_runlen = delta < avr->avr_ack_runlen ? delta : avr->avr_ack_runlen; | ||
381 | 306 | ||
382 | i = len; | 307 | runlen_now = dccp_ackvec_runlen(av->av_buf + avr->avr_ack_ptr); |
383 | /* | 308 | /* |
384 | * XXX | 309 | * The run length of Ack Vector cells does not decrease over time. If |
385 | * I think it might be more efficient to work backwards. See comment on | 310 | * the run length is the same as at the time the Ack Vector was sent, we |
386 | * rcv_ackno. -sorbo. | 311 | * free the ack_ptr cell. That cell can however not be freed if the run |
312 | * length has increased: in this case we need to move the tail pointer | ||
313 | * backwards (towards higher indices), to its next-oldest neighbour. | ||
387 | */ | 314 | */ |
388 | avr = list_entry(av->av_records.next, struct dccp_ackvec_record, avr_node); | 315 | if (runlen_now > eff_runlen) { |
389 | while (i--) { | ||
390 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; | ||
391 | u64 ackno_end_rl; | ||
392 | 316 | ||
393 | dccp_set_seqno(&ackno_end_rl, *ackno - rl); | 317 | av->av_buf[avr->avr_ack_ptr] -= eff_runlen + 1; |
318 | av->av_buf_tail = __ackvec_idx_add(avr->avr_ack_ptr, 1); | ||
394 | 319 | ||
320 | /* This move may not have cleared the overflow flag. */ | ||
321 | if (av->av_overflow) | ||
322 | av->av_overflow = (av->av_buf_head == av->av_buf_tail); | ||
323 | } else { | ||
324 | av->av_buf_tail = avr->avr_ack_ptr; | ||
395 | /* | 325 | /* |
396 | * If our AVR sequence number is greater than the ack, go | 326 | * We have made sure that avr points to a valid cell within the |
397 | * forward in the AVR list until it is not so. | 327 | * buffer. This cell is either older than head, or equals head |
328 | * (empty buffer): in both cases we no longer have any overflow. | ||
398 | */ | 329 | */ |
399 | list_for_each_entry_from(avr, &av->av_records, avr_node) { | 330 | av->av_overflow = 0; |
400 | if (!after48(avr->avr_ack_seqno, *ackno)) | 331 | } |
401 | goto found; | ||
402 | } | ||
403 | /* End of the av_records list, not found, exit */ | ||
404 | break; | ||
405 | found: | ||
406 | if (between48(avr->avr_ack_seqno, ackno_end_rl, *ackno)) { | ||
407 | const u8 state = *vector & DCCP_ACKVEC_STATE_MASK; | ||
408 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { | ||
409 | dccp_pr_debug("%s ACK vector 0, len=%d, " | ||
410 | "ack_seqno=%llu, ack_ackno=%llu, " | ||
411 | "ACKED!\n", | ||
412 | dccp_role(sk), len, | ||
413 | (unsigned long long) | ||
414 | avr->avr_ack_seqno, | ||
415 | (unsigned long long) | ||
416 | avr->avr_ack_ackno); | ||
417 | dccp_ackvec_throw_record(av, avr); | ||
418 | break; | ||
419 | } | ||
420 | /* | ||
421 | * If it wasn't received, continue scanning... we might | ||
422 | * find another one. | ||
423 | */ | ||
424 | } | ||
425 | 332 | ||
426 | dccp_set_seqno(ackno, ackno_end_rl - 1); | 333 | /* |
427 | ++vector; | 334 | * The peer has acknowledged up to and including ack_ackno. Hence the |
335 | * first packet in group (2) of 11.4.2 is the successor of ack_ackno. | ||
336 | */ | ||
337 | av->av_tail_ackno = ADD48(avr->avr_ack_ackno, 1); | ||
338 | |||
339 | free_records: | ||
340 | list_for_each_entry_safe_from(avr, next, &av->av_records, avr_node) { | ||
341 | list_del(&avr->avr_node); | ||
342 | kmem_cache_free(dccp_ackvec_record_slab, avr); | ||
428 | } | 343 | } |
429 | } | 344 | } |
430 | 345 | ||
431 | int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, | 346 | /* |
432 | u64 *ackno, const u8 opt, const u8 *value, const u8 len) | 347 | * Routines to keep track of Ack Vectors received in an skb |
348 | */ | ||
349 | int dccp_ackvec_parsed_add(struct list_head *head, u8 *vec, u8 len, u8 nonce) | ||
433 | { | 350 | { |
434 | if (len > DCCP_SINGLE_OPT_MAXLEN) | 351 | struct dccp_ackvec_parsed *new = kmalloc(sizeof(*new), GFP_ATOMIC); |
435 | return -1; | 352 | |
353 | if (new == NULL) | ||
354 | return -ENOBUFS; | ||
355 | new->vec = vec; | ||
356 | new->len = len; | ||
357 | new->nonce = nonce; | ||
436 | 358 | ||
437 | /* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */ | 359 | list_add_tail(&new->node, head); |
438 | dccp_ackvec_check_rcv_ackvector(dccp_sk(sk)->dccps_hc_rx_ackvec, sk, | ||
439 | ackno, len, value); | ||
440 | return 0; | 360 | return 0; |
441 | } | 361 | } |
362 | EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_add); | ||
363 | |||
364 | void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks) | ||
365 | { | ||
366 | struct dccp_ackvec_parsed *cur, *next; | ||
367 | |||
368 | list_for_each_entry_safe(cur, next, parsed_chunks, node) | ||
369 | kfree(cur); | ||
370 | INIT_LIST_HEAD(parsed_chunks); | ||
371 | } | ||
372 | EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_cleanup); | ||
442 | 373 | ||
443 | int __init dccp_ackvec_init(void) | 374 | int __init dccp_ackvec_init(void) |
444 | { | 375 | { |
@@ -448,10 +379,9 @@ int __init dccp_ackvec_init(void) | |||
448 | if (dccp_ackvec_slab == NULL) | 379 | if (dccp_ackvec_slab == NULL) |
449 | goto out_err; | 380 | goto out_err; |
450 | 381 | ||
451 | dccp_ackvec_record_slab = | 382 | dccp_ackvec_record_slab = kmem_cache_create("dccp_ackvec_record", |
452 | kmem_cache_create("dccp_ackvec_record", | 383 | sizeof(struct dccp_ackvec_record), |
453 | sizeof(struct dccp_ackvec_record), | 384 | 0, SLAB_HWCACHE_ALIGN, NULL); |
454 | 0, SLAB_HWCACHE_ALIGN, NULL); | ||
455 | if (dccp_ackvec_record_slab == NULL) | 385 | if (dccp_ackvec_record_slab == NULL) |
456 | goto out_destroy_slab; | 386 | goto out_destroy_slab; |
457 | 387 | ||
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 7ea557b7c6b1..e2ab0627a5ff 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h | |||
@@ -3,9 +3,9 @@ | |||
3 | /* | 3 | /* |
4 | * net/dccp/ackvec.h | 4 | * net/dccp/ackvec.h |
5 | * | 5 | * |
6 | * An implementation of the DCCP protocol | 6 | * An implementation of Ack Vectors for the DCCP protocol |
7 | * Copyright (c) 2007 University of Aberdeen, Scotland, UK | ||
7 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@mandriva.com> | 8 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@mandriva.com> |
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License version 2 as | 10 | * under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -13,99 +13,124 @@ | |||
13 | 13 | ||
14 | #include <linux/dccp.h> | 14 | #include <linux/dccp.h> |
15 | #include <linux/compiler.h> | 15 | #include <linux/compiler.h> |
16 | #include <linux/ktime.h> | ||
17 | #include <linux/list.h> | 16 | #include <linux/list.h> |
18 | #include <linux/types.h> | 17 | #include <linux/types.h> |
19 | 18 | ||
20 | /* We can spread an ack vector across multiple options */ | 19 | /* |
21 | #define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2) | 20 | * Ack Vector buffer space is static, in multiples of %DCCP_SINGLE_OPT_MAXLEN, |
21 | * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1 | ||
22 | * will be sufficient for most cases of low Ack Ratios, using a value of 2 gives | ||
23 | * more headroom if Ack Ratio is higher or when the sender acknowledges slowly. | ||
24 | * The maximum value is bounded by the u16 types for indices and functions. | ||
25 | */ | ||
26 | #define DCCPAV_NUM_ACKVECS 2 | ||
27 | #define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS) | ||
22 | 28 | ||
23 | /* Estimated minimum average Ack Vector length - used for updating MPS */ | 29 | /* Estimated minimum average Ack Vector length - used for updating MPS */ |
24 | #define DCCPAV_MIN_OPTLEN 16 | 30 | #define DCCPAV_MIN_OPTLEN 16 |
25 | 31 | ||
26 | #define DCCP_ACKVEC_STATE_RECEIVED 0 | 32 | /* Threshold for coping with large bursts of losses */ |
27 | #define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6) | 33 | #define DCCPAV_BURST_THRESH (DCCPAV_MAX_ACKVEC_LEN / 8) |
28 | #define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6) | ||
29 | 34 | ||
30 | #define DCCP_ACKVEC_STATE_MASK 0xC0 /* 11000000 */ | 35 | enum dccp_ackvec_states { |
31 | #define DCCP_ACKVEC_LEN_MASK 0x3F /* 00111111 */ | 36 | DCCPAV_RECEIVED = 0x00, |
37 | DCCPAV_ECN_MARKED = 0x40, | ||
38 | DCCPAV_RESERVED = 0x80, | ||
39 | DCCPAV_NOT_RECEIVED = 0xC0 | ||
40 | }; | ||
41 | #define DCCPAV_MAX_RUNLEN 0x3F | ||
32 | 42 | ||
33 | /** struct dccp_ackvec - ack vector | 43 | static inline u8 dccp_ackvec_runlen(const u8 *cell) |
34 | * | 44 | { |
35 | * This data structure is the one defined in RFC 4340, Appendix A. | 45 | return *cell & DCCPAV_MAX_RUNLEN; |
36 | * | 46 | } |
37 | * @av_buf_head - circular buffer head | 47 | |
38 | * @av_buf_tail - circular buffer tail | 48 | static inline u8 dccp_ackvec_state(const u8 *cell) |
39 | * @av_buf_ackno - ack # of the most recent packet acknowledgeable in the | 49 | { |
40 | * buffer (i.e. %av_buf_head) | 50 | return *cell & ~DCCPAV_MAX_RUNLEN; |
41 | * @av_buf_nonce - the one-bit sum of the ECN Nonces on all packets acked | 51 | } |
42 | * by the buffer with State 0 | 52 | |
43 | * | 53 | /** struct dccp_ackvec - Ack Vector main data structure |
44 | * Additionally, the HC-Receiver must keep some information about the | ||
45 | * Ack Vectors it has recently sent. For each packet sent carrying an | ||
46 | * Ack Vector, it remembers four variables: | ||
47 | * | 54 | * |
48 | * @av_records - list of dccp_ackvec_record | 55 | * This implements a fixed-size circular buffer within an array and is largely |
49 | * @av_ack_nonce - the one-bit sum of the ECN Nonces for all State 0. | 56 | * based on Appendix A of RFC 4340. |
50 | * | 57 | * |
51 | * @av_time - the time in usecs | 58 | * @av_buf: circular buffer storage area |
52 | * @av_buf - circular buffer of acknowledgeable packets | 59 | * @av_buf_head: head index; begin of live portion in @av_buf |
60 | * @av_buf_tail: tail index; first index _after_ the live portion in @av_buf | ||
61 | * @av_buf_ackno: highest seqno of acknowledgeable packet recorded in @av_buf | ||
62 | * @av_tail_ackno: lowest seqno of acknowledgeable packet recorded in @av_buf | ||
63 | * @av_buf_nonce: ECN nonce sums, each covering subsequent segments of up to | ||
64 | * %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf | ||
65 | * @av_overflow: if 1 then buf_head == buf_tail indicates buffer wraparound | ||
66 | * @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously) | ||
53 | */ | 67 | */ |
54 | struct dccp_ackvec { | 68 | struct dccp_ackvec { |
55 | u64 av_buf_ackno; | 69 | u8 av_buf[DCCPAV_MAX_ACKVEC_LEN]; |
56 | struct list_head av_records; | ||
57 | ktime_t av_time; | ||
58 | u16 av_buf_head; | 70 | u16 av_buf_head; |
59 | u16 av_vec_len; | 71 | u16 av_buf_tail; |
60 | u8 av_buf_nonce; | 72 | u64 av_buf_ackno:48; |
61 | u8 av_ack_nonce; | 73 | u64 av_tail_ackno:48; |
62 | u8 av_buf[DCCP_MAX_ACKVEC_LEN]; | 74 | bool av_buf_nonce[DCCPAV_NUM_ACKVECS]; |
75 | u8 av_overflow:1; | ||
76 | struct list_head av_records; | ||
63 | }; | 77 | }; |
64 | 78 | ||
65 | /** struct dccp_ackvec_record - ack vector record | 79 | /** struct dccp_ackvec_record - Records information about sent Ack Vectors |
66 | * | 80 | * |
67 | * ACK vector record as defined in Appendix A of spec. | 81 | * These list entries define the additional information which the HC-Receiver |
82 | * keeps about recently-sent Ack Vectors; again refer to RFC 4340, Appendix A. | ||
68 | * | 83 | * |
69 | * The list is sorted by avr_ack_seqno | 84 | * @avr_node: the list node in @av_records |
85 | * @avr_ack_seqno: sequence number of the packet the Ack Vector was sent on | ||
86 | * @avr_ack_ackno: the Ack number that this record/Ack Vector refers to | ||
87 | * @avr_ack_ptr: pointer into @av_buf where this record starts | ||
88 | * @avr_ack_runlen: run length of @avr_ack_ptr at the time of sending | ||
89 | * @avr_ack_nonce: the sum of @av_buf_nonce's at the time this record was sent | ||
70 | * | 90 | * |
71 | * @avr_node - node in av_records | 91 | * The list as a whole is sorted in descending order by @avr_ack_seqno. |
72 | * @avr_ack_seqno - sequence number of the packet this record was sent on | ||
73 | * @avr_ack_ackno - sequence number being acknowledged | ||
74 | * @avr_ack_ptr - pointer into av_buf where this record starts | ||
75 | * @avr_ack_nonce - av_ack_nonce at the time this record was sent | ||
76 | * @avr_sent_len - lenght of the record in av_buf | ||
77 | */ | 92 | */ |
78 | struct dccp_ackvec_record { | 93 | struct dccp_ackvec_record { |
79 | struct list_head avr_node; | 94 | struct list_head avr_node; |
80 | u64 avr_ack_seqno; | 95 | u64 avr_ack_seqno:48; |
81 | u64 avr_ack_ackno; | 96 | u64 avr_ack_ackno:48; |
82 | u16 avr_ack_ptr; | 97 | u16 avr_ack_ptr; |
83 | u16 avr_sent_len; | 98 | u8 avr_ack_runlen; |
84 | u8 avr_ack_nonce; | 99 | u8 avr_ack_nonce:1; |
85 | }; | 100 | }; |
86 | 101 | ||
87 | struct sock; | ||
88 | struct sk_buff; | ||
89 | |||
90 | extern int dccp_ackvec_init(void); | 102 | extern int dccp_ackvec_init(void); |
91 | extern void dccp_ackvec_exit(void); | 103 | extern void dccp_ackvec_exit(void); |
92 | 104 | ||
93 | extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority); | 105 | extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority); |
94 | extern void dccp_ackvec_free(struct dccp_ackvec *av); | 106 | extern void dccp_ackvec_free(struct dccp_ackvec *av); |
95 | 107 | ||
96 | extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | 108 | extern void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb); |
97 | const u64 ackno, const u8 state); | 109 | extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); |
98 | 110 | extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno); | |
99 | extern void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, | 111 | extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); |
100 | struct sock *sk, const u64 ackno); | ||
101 | extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, | ||
102 | u64 *ackno, const u8 opt, | ||
103 | const u8 *value, const u8 len); | ||
104 | 112 | ||
105 | extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb); | 113 | static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av) |
106 | |||
107 | static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) | ||
108 | { | 114 | { |
109 | return av->av_vec_len; | 115 | return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; |
110 | } | 116 | } |
117 | |||
118 | /** | ||
119 | * struct dccp_ackvec_parsed - Record offsets of Ack Vectors in skb | ||
120 | * @vec: start of vector (offset into skb) | ||
121 | * @len: length of @vec | ||
122 | * @nonce: whether @vec had an ECN nonce of 0 or 1 | ||
123 | * @node: FIFO - arranged in descending order of ack_ackno | ||
124 | * This structure is used by CCIDs to access Ack Vectors in a received skb. | ||
125 | */ | ||
126 | struct dccp_ackvec_parsed { | ||
127 | u8 *vec, | ||
128 | len, | ||
129 | nonce:1; | ||
130 | struct list_head node; | ||
131 | }; | ||
132 | |||
133 | extern int dccp_ackvec_parsed_add(struct list_head *head, | ||
134 | u8 *vec, u8 len, u8 nonce); | ||
135 | extern void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks); | ||
111 | #endif /* _ACKVEC_H */ | 136 | #endif /* _ACKVEC_H */ |
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 6576eae9e779..e96d5e810039 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -246,68 +246,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) | |||
246 | #endif | 246 | #endif |
247 | } | 247 | } |
248 | 248 | ||
249 | /* XXX Lame code duplication! | ||
250 | * returns -1 if none was found. | ||
251 | * else returns the next offset to use in the function call. | ||
252 | */ | ||
253 | static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset, | ||
254 | unsigned char **vec, unsigned char *veclen) | ||
255 | { | ||
256 | const struct dccp_hdr *dh = dccp_hdr(skb); | ||
257 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); | ||
258 | unsigned char *opt_ptr; | ||
259 | const unsigned char *opt_end = (unsigned char *)dh + | ||
260 | (dh->dccph_doff * 4); | ||
261 | unsigned char opt, len; | ||
262 | unsigned char *value; | ||
263 | |||
264 | BUG_ON(offset < 0); | ||
265 | options += offset; | ||
266 | opt_ptr = options; | ||
267 | if (opt_ptr >= opt_end) | ||
268 | return -1; | ||
269 | |||
270 | while (opt_ptr != opt_end) { | ||
271 | opt = *opt_ptr++; | ||
272 | len = 0; | ||
273 | value = NULL; | ||
274 | |||
275 | /* Check if this isn't a single byte option */ | ||
276 | if (opt > DCCPO_MAX_RESERVED) { | ||
277 | if (opt_ptr == opt_end) | ||
278 | goto out_invalid_option; | ||
279 | |||
280 | len = *opt_ptr++; | ||
281 | if (len < 3) | ||
282 | goto out_invalid_option; | ||
283 | /* | ||
284 | * Remove the type and len fields, leaving | ||
285 | * just the value size | ||
286 | */ | ||
287 | len -= 2; | ||
288 | value = opt_ptr; | ||
289 | opt_ptr += len; | ||
290 | |||
291 | if (opt_ptr > opt_end) | ||
292 | goto out_invalid_option; | ||
293 | } | ||
294 | |||
295 | switch (opt) { | ||
296 | case DCCPO_ACK_VECTOR_0: | ||
297 | case DCCPO_ACK_VECTOR_1: | ||
298 | *vec = value; | ||
299 | *veclen = len; | ||
300 | return offset + (opt_ptr - options); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | return -1; | ||
305 | |||
306 | out_invalid_option: | ||
307 | DCCP_BUG("Invalid option - this should not happen (previous parsing)!"); | ||
308 | return -1; | ||
309 | } | ||
310 | |||
311 | /** | 249 | /** |
312 | * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm | 250 | * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm |
313 | * This code is almost identical with TCP's tcp_rtt_estimator(), since | 251 | * This code is almost identical with TCP's tcp_rtt_estimator(), since |
@@ -432,16 +370,28 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp) | |||
432 | ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); | 370 | ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); |
433 | } | 371 | } |
434 | 372 | ||
373 | static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type, | ||
374 | u8 option, u8 *optval, u8 optlen) | ||
375 | { | ||
376 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); | ||
377 | |||
378 | switch (option) { | ||
379 | case DCCPO_ACK_VECTOR_0: | ||
380 | case DCCPO_ACK_VECTOR_1: | ||
381 | return dccp_ackvec_parsed_add(&hc->tx_av_chunks, optval, optlen, | ||
382 | option - DCCPO_ACK_VECTOR_0); | ||
383 | } | ||
384 | return 0; | ||
385 | } | ||
386 | |||
435 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | 387 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) |
436 | { | 388 | { |
437 | struct dccp_sock *dp = dccp_sk(sk); | 389 | struct dccp_sock *dp = dccp_sk(sk); |
438 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); | 390 | struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); |
439 | const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); | 391 | const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); |
392 | struct dccp_ackvec_parsed *avp; | ||
440 | u64 ackno, seqno; | 393 | u64 ackno, seqno; |
441 | struct ccid2_seq *seqp; | 394 | struct ccid2_seq *seqp; |
442 | unsigned char *vector; | ||
443 | unsigned char veclen; | ||
444 | int offset = 0; | ||
445 | int done = 0; | 395 | int done = 0; |
446 | unsigned int maxincr = 0; | 396 | unsigned int maxincr = 0; |
447 | 397 | ||
@@ -475,17 +425,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
475 | } | 425 | } |
476 | 426 | ||
477 | /* check forward path congestion */ | 427 | /* check forward path congestion */ |
478 | /* still didn't send out new data packets */ | 428 | if (dccp_packet_without_ack(skb)) |
479 | if (hc->tx_seqh == hc->tx_seqt) | ||
480 | return; | 429 | return; |
481 | 430 | ||
482 | switch (DCCP_SKB_CB(skb)->dccpd_type) { | 431 | /* still didn't send out new data packets */ |
483 | case DCCP_PKT_ACK: | 432 | if (hc->tx_seqh == hc->tx_seqt) |
484 | case DCCP_PKT_DATAACK: | 433 | goto done; |
485 | break; | ||
486 | default: | ||
487 | return; | ||
488 | } | ||
489 | 434 | ||
490 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; | 435 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; |
491 | if (after48(ackno, hc->tx_high_ack)) | 436 | if (after48(ackno, hc->tx_high_ack)) |
@@ -509,16 +454,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
509 | maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); | 454 | maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); |
510 | 455 | ||
511 | /* go through all ack vectors */ | 456 | /* go through all ack vectors */ |
512 | while ((offset = ccid2_ackvector(sk, skb, offset, | 457 | list_for_each_entry(avp, &hc->tx_av_chunks, node) { |
513 | &vector, &veclen)) != -1) { | ||
514 | /* go through this ack vector */ | 458 | /* go through this ack vector */ |
515 | while (veclen--) { | 459 | for (; avp->len--; avp->vec++) { |
516 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; | 460 | u64 ackno_end_rl = SUB48(ackno, |
517 | u64 ackno_end_rl = SUB48(ackno, rl); | 461 | dccp_ackvec_runlen(avp->vec)); |
518 | 462 | ||
519 | ccid2_pr_debug("ackvec start:%llu end:%llu\n", | 463 | ccid2_pr_debug("ackvec %llu |%u,%u|\n", |
520 | (unsigned long long)ackno, | 464 | (unsigned long long)ackno, |
521 | (unsigned long long)ackno_end_rl); | 465 | dccp_ackvec_state(avp->vec) >> 6, |
466 | dccp_ackvec_runlen(avp->vec)); | ||
522 | /* if the seqno we are analyzing is larger than the | 467 | /* if the seqno we are analyzing is larger than the |
523 | * current ackno, then move towards the tail of our | 468 | * current ackno, then move towards the tail of our |
524 | * seqnos. | 469 | * seqnos. |
@@ -537,17 +482,15 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
537 | * run length | 482 | * run length |
538 | */ | 483 | */ |
539 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { | 484 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { |
540 | const u8 state = *vector & | 485 | const u8 state = dccp_ackvec_state(avp->vec); |
541 | DCCP_ACKVEC_STATE_MASK; | ||
542 | 486 | ||
543 | /* new packet received or marked */ | 487 | /* new packet received or marked */ |
544 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED && | 488 | if (state != DCCPAV_NOT_RECEIVED && |
545 | !seqp->ccid2s_acked) { | 489 | !seqp->ccid2s_acked) { |
546 | if (state == | 490 | if (state == DCCPAV_ECN_MARKED) |
547 | DCCP_ACKVEC_STATE_ECN_MARKED) { | ||
548 | ccid2_congestion_event(sk, | 491 | ccid2_congestion_event(sk, |
549 | seqp); | 492 | seqp); |
550 | } else | 493 | else |
551 | ccid2_new_ack(sk, seqp, | 494 | ccid2_new_ack(sk, seqp, |
552 | &maxincr); | 495 | &maxincr); |
553 | 496 | ||
@@ -566,7 +509,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
566 | break; | 509 | break; |
567 | 510 | ||
568 | ackno = SUB48(ackno_end_rl, 1); | 511 | ackno = SUB48(ackno_end_rl, 1); |
569 | vector++; | ||
570 | } | 512 | } |
571 | if (done) | 513 | if (done) |
572 | break; | 514 | break; |
@@ -634,10 +576,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
634 | sk_stop_timer(sk, &hc->tx_rtotimer); | 576 | sk_stop_timer(sk, &hc->tx_rtotimer); |
635 | else | 577 | else |
636 | sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); | 578 | sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); |
637 | 579 | done: | |
638 | /* check if incoming Acks allow pending packets to be sent */ | 580 | /* check if incoming Acks allow pending packets to be sent */ |
639 | if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) | 581 | if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) |
640 | tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); | 582 | tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); |
583 | dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks); | ||
641 | } | 584 | } |
642 | 585 | ||
643 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | 586 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) |
@@ -666,6 +609,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | |||
666 | hc->tx_last_cong = ccid2_time_stamp; | 609 | hc->tx_last_cong = ccid2_time_stamp; |
667 | setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, | 610 | setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, |
668 | (unsigned long)sk); | 611 | (unsigned long)sk); |
612 | INIT_LIST_HEAD(&hc->tx_av_chunks); | ||
669 | return 0; | 613 | return 0; |
670 | } | 614 | } |
671 | 615 | ||
@@ -699,16 +643,17 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
699 | } | 643 | } |
700 | 644 | ||
701 | struct ccid_operations ccid2_ops = { | 645 | struct ccid_operations ccid2_ops = { |
702 | .ccid_id = DCCPC_CCID2, | 646 | .ccid_id = DCCPC_CCID2, |
703 | .ccid_name = "TCP-like", | 647 | .ccid_name = "TCP-like", |
704 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), | 648 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), |
705 | .ccid_hc_tx_init = ccid2_hc_tx_init, | 649 | .ccid_hc_tx_init = ccid2_hc_tx_init, |
706 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, | 650 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, |
707 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, | 651 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, |
708 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, | 652 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, |
709 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, | 653 | .ccid_hc_tx_parse_options = ccid2_hc_tx_parse_options, |
710 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), | 654 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, |
711 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | 655 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), |
656 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | ||
712 | }; | 657 | }; |
713 | 658 | ||
714 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG | 659 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index 25cb6b216eda..e9985dafc2c7 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h | |||
@@ -55,6 +55,7 @@ struct ccid2_seq { | |||
55 | * @tx_rtt_seq: to decay RTTVAR at most once per flight | 55 | * @tx_rtt_seq: to decay RTTVAR at most once per flight |
56 | * @tx_rpseq: last consecutive seqno | 56 | * @tx_rpseq: last consecutive seqno |
57 | * @tx_rpdupack: dupacks since rpseq | 57 | * @tx_rpdupack: dupacks since rpseq |
58 | * @tx_av_chunks: list of Ack Vectors received on current skb | ||
58 | */ | 59 | */ |
59 | struct ccid2_hc_tx_sock { | 60 | struct ccid2_hc_tx_sock { |
60 | u32 tx_cwnd; | 61 | u32 tx_cwnd; |
@@ -79,6 +80,7 @@ struct ccid2_hc_tx_sock { | |||
79 | int tx_rpdupack; | 80 | int tx_rpdupack; |
80 | u32 tx_last_cong; | 81 | u32 tx_last_cong; |
81 | u64 tx_high_ack; | 82 | u64 tx_high_ack; |
83 | struct list_head tx_av_chunks; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc) | 86 | static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc) |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index a8ed459508b2..45087052d894 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -93,9 +93,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo); | |||
93 | #define DCCP_FALLBACK_RTT (USEC_PER_SEC / 5) | 93 | #define DCCP_FALLBACK_RTT (USEC_PER_SEC / 5) |
94 | #define DCCP_SANE_RTT_MAX (3 * USEC_PER_SEC) | 94 | #define DCCP_SANE_RTT_MAX (3 * USEC_PER_SEC) |
95 | 95 | ||
96 | /* Maximal interval between probes for local resources. */ | ||
97 | #define DCCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ / 2U)) | ||
98 | |||
99 | /* sysctl variables for DCCP */ | 96 | /* sysctl variables for DCCP */ |
100 | extern int sysctl_dccp_request_retries; | 97 | extern int sysctl_dccp_request_retries; |
101 | extern int sysctl_dccp_retries1; | 98 | extern int sysctl_dccp_retries1; |
@@ -203,12 +200,7 @@ struct dccp_mib { | |||
203 | DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); | 200 | DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); |
204 | #define DCCP_INC_STATS(field) SNMP_INC_STATS(dccp_statistics, field) | 201 | #define DCCP_INC_STATS(field) SNMP_INC_STATS(dccp_statistics, field) |
205 | #define DCCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(dccp_statistics, field) | 202 | #define DCCP_INC_STATS_BH(field) SNMP_INC_STATS_BH(dccp_statistics, field) |
206 | #define DCCP_INC_STATS_USER(field) SNMP_INC_STATS_USER(dccp_statistics, field) | ||
207 | #define DCCP_DEC_STATS(field) SNMP_DEC_STATS(dccp_statistics, field) | 203 | #define DCCP_DEC_STATS(field) SNMP_DEC_STATS(dccp_statistics, field) |
208 | #define DCCP_ADD_STATS_BH(field, val) \ | ||
209 | SNMP_ADD_STATS_BH(dccp_statistics, field, val) | ||
210 | #define DCCP_ADD_STATS_USER(field, val) \ | ||
211 | SNMP_ADD_STATS_USER(dccp_statistics, field, val) | ||
212 | 204 | ||
213 | /* | 205 | /* |
214 | * Checksumming routines | 206 | * Checksumming routines |
@@ -243,6 +235,19 @@ extern void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
243 | extern void dccp_send_sync(struct sock *sk, const u64 seq, | 235 | extern void dccp_send_sync(struct sock *sk, const u64 seq, |
244 | const enum dccp_pkt_type pkt_type); | 236 | const enum dccp_pkt_type pkt_type); |
245 | 237 | ||
238 | /* | ||
239 | * TX Packet Dequeueing Interface | ||
240 | */ | ||
241 | extern void dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb); | ||
242 | extern bool dccp_qpolicy_full(struct sock *sk); | ||
243 | extern void dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb); | ||
244 | extern struct sk_buff *dccp_qpolicy_top(struct sock *sk); | ||
245 | extern struct sk_buff *dccp_qpolicy_pop(struct sock *sk); | ||
246 | extern bool dccp_qpolicy_param_ok(struct sock *sk, __be32 param); | ||
247 | |||
248 | /* | ||
249 | * TX Packet Output and TX Timers | ||
250 | */ | ||
246 | extern void dccp_write_xmit(struct sock *sk); | 251 | extern void dccp_write_xmit(struct sock *sk); |
247 | extern void dccp_write_space(struct sock *sk); | 252 | extern void dccp_write_space(struct sock *sk); |
248 | extern void dccp_flush_write_queue(struct sock *sk, long *time_budget); | 253 | extern void dccp_flush_write_queue(struct sock *sk, long *time_budget); |
@@ -457,12 +462,15 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq) | |||
457 | dp->dccps_awh = dp->dccps_gss; | 462 | dp->dccps_awh = dp->dccps_gss; |
458 | } | 463 | } |
459 | 464 | ||
465 | static inline int dccp_ackvec_pending(const struct sock *sk) | ||
466 | { | ||
467 | return dccp_sk(sk)->dccps_hc_rx_ackvec != NULL && | ||
468 | !dccp_ackvec_is_empty(dccp_sk(sk)->dccps_hc_rx_ackvec); | ||
469 | } | ||
470 | |||
460 | static inline int dccp_ack_pending(const struct sock *sk) | 471 | static inline int dccp_ack_pending(const struct sock *sk) |
461 | { | 472 | { |
462 | const struct dccp_sock *dp = dccp_sk(sk); | 473 | return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk); |
463 | return (dp->dccps_hc_rx_ackvec != NULL && | ||
464 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) || | ||
465 | inet_csk_ack_scheduled(sk); | ||
466 | } | 474 | } |
467 | 475 | ||
468 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); | 476 | extern int dccp_feat_finalise_settings(struct dccp_sock *dp); |
diff --git a/net/dccp/input.c b/net/dccp/input.c index e424a09e83f6..15af247ea007 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c | |||
@@ -160,13 +160,15 @@ static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb) | |||
160 | dccp_time_wait(sk, DCCP_TIME_WAIT, 0); | 160 | dccp_time_wait(sk, DCCP_TIME_WAIT, 0); |
161 | } | 161 | } |
162 | 162 | ||
163 | static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) | 163 | static void dccp_handle_ackvec_processing(struct sock *sk, struct sk_buff *skb) |
164 | { | 164 | { |
165 | struct dccp_sock *dp = dccp_sk(sk); | 165 | struct dccp_ackvec *av = dccp_sk(sk)->dccps_hc_rx_ackvec; |
166 | 166 | ||
167 | if (dp->dccps_hc_rx_ackvec != NULL) | 167 | if (av == NULL) |
168 | dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk, | 168 | return; |
169 | DCCP_SKB_CB(skb)->dccpd_ack_seq); | 169 | if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) |
170 | dccp_ackvec_clear_state(av, DCCP_SKB_CB(skb)->dccpd_ack_seq); | ||
171 | dccp_ackvec_input(av, skb); | ||
170 | } | 172 | } |
171 | 173 | ||
172 | static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb) | 174 | static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb) |
@@ -366,22 +368,13 @@ discard: | |||
366 | int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, | 368 | int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, |
367 | const struct dccp_hdr *dh, const unsigned len) | 369 | const struct dccp_hdr *dh, const unsigned len) |
368 | { | 370 | { |
369 | struct dccp_sock *dp = dccp_sk(sk); | ||
370 | |||
371 | if (dccp_check_seqno(sk, skb)) | 371 | if (dccp_check_seqno(sk, skb)) |
372 | goto discard; | 372 | goto discard; |
373 | 373 | ||
374 | if (dccp_parse_options(sk, NULL, skb)) | 374 | if (dccp_parse_options(sk, NULL, skb)) |
375 | return 1; | 375 | return 1; |
376 | 376 | ||
377 | if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) | 377 | dccp_handle_ackvec_processing(sk, skb); |
378 | dccp_event_ack_recv(sk, skb); | ||
379 | |||
380 | if (dp->dccps_hc_rx_ackvec != NULL && | ||
381 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, | ||
382 | DCCP_SKB_CB(skb)->dccpd_seq, | ||
383 | DCCP_ACKVEC_STATE_RECEIVED)) | ||
384 | goto discard; | ||
385 | dccp_deliver_input_to_ccids(sk, skb); | 378 | dccp_deliver_input_to_ccids(sk, skb); |
386 | 379 | ||
387 | return __dccp_rcv_established(sk, skb, dh, len); | 380 | return __dccp_rcv_established(sk, skb, dh, len); |
@@ -633,15 +626,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
633 | if (dccp_parse_options(sk, NULL, skb)) | 626 | if (dccp_parse_options(sk, NULL, skb)) |
634 | return 1; | 627 | return 1; |
635 | 628 | ||
636 | if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) | 629 | dccp_handle_ackvec_processing(sk, skb); |
637 | dccp_event_ack_recv(sk, skb); | ||
638 | |||
639 | if (dp->dccps_hc_rx_ackvec != NULL && | ||
640 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, | ||
641 | DCCP_SKB_CB(skb)->dccpd_seq, | ||
642 | DCCP_ACKVEC_STATE_RECEIVED)) | ||
643 | goto discard; | ||
644 | |||
645 | dccp_deliver_input_to_ccids(sk, skb); | 630 | dccp_deliver_input_to_ccids(sk, skb); |
646 | } | 631 | } |
647 | 632 | ||
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 3f69ea114829..45a434f94169 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -462,15 +462,12 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, | |||
462 | { | 462 | { |
463 | struct rtable *rt; | 463 | struct rtable *rt; |
464 | struct flowi fl = { .oif = skb_rtable(skb)->rt_iif, | 464 | struct flowi fl = { .oif = skb_rtable(skb)->rt_iif, |
465 | .nl_u = { .ip4_u = | 465 | .fl4_dst = ip_hdr(skb)->saddr, |
466 | { .daddr = ip_hdr(skb)->saddr, | 466 | .fl4_src = ip_hdr(skb)->daddr, |
467 | .saddr = ip_hdr(skb)->daddr, | 467 | .fl4_tos = RT_CONN_FLAGS(sk), |
468 | .tos = RT_CONN_FLAGS(sk) } }, | ||
469 | .proto = sk->sk_protocol, | 468 | .proto = sk->sk_protocol, |
470 | .uli_u = { .ports = | 469 | .fl_ip_sport = dccp_hdr(skb)->dccph_dport, |
471 | { .sport = dccp_hdr(skb)->dccph_dport, | 470 | .fl_ip_dport = dccp_hdr(skb)->dccph_sport |
472 | .dport = dccp_hdr(skb)->dccph_sport } | ||
473 | } | ||
474 | }; | 471 | }; |
475 | 472 | ||
476 | security_skb_classify_flow(skb, &fl); | 473 | security_skb_classify_flow(skb, &fl); |
diff --git a/net/dccp/options.c b/net/dccp/options.c index cd3061813009..f06ffcfc8d71 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -54,7 +54,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
54 | struct dccp_sock *dp = dccp_sk(sk); | 54 | struct dccp_sock *dp = dccp_sk(sk); |
55 | const struct dccp_hdr *dh = dccp_hdr(skb); | 55 | const struct dccp_hdr *dh = dccp_hdr(skb); |
56 | const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; | 56 | const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; |
57 | u64 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; | ||
58 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); | 57 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); |
59 | unsigned char *opt_ptr = options; | 58 | unsigned char *opt_ptr = options; |
60 | const unsigned char *opt_end = (unsigned char *)dh + | 59 | const unsigned char *opt_end = (unsigned char *)dh + |
@@ -129,14 +128,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
129 | if (rc) | 128 | if (rc) |
130 | goto out_featneg_failed; | 129 | goto out_featneg_failed; |
131 | break; | 130 | break; |
132 | case DCCPO_ACK_VECTOR_0: | ||
133 | case DCCPO_ACK_VECTOR_1: | ||
134 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
135 | break; | ||
136 | if (dp->dccps_hc_rx_ackvec != NULL && | ||
137 | dccp_ackvec_parse(sk, skb, &ackno, opt, value, len)) | ||
138 | goto out_invalid_option; | ||
139 | break; | ||
140 | case DCCPO_TIMESTAMP: | 131 | case DCCPO_TIMESTAMP: |
141 | if (len != 4) | 132 | if (len != 4) |
142 | goto out_invalid_option; | 133 | goto out_invalid_option; |
@@ -226,6 +217,16 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
226 | pkt_type, opt, value, len)) | 217 | pkt_type, opt, value, len)) |
227 | goto out_invalid_option; | 218 | goto out_invalid_option; |
228 | break; | 219 | break; |
220 | case DCCPO_ACK_VECTOR_0: | ||
221 | case DCCPO_ACK_VECTOR_1: | ||
222 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
223 | break; | ||
224 | /* | ||
225 | * Ack vectors are processed by the TX CCID if it is | ||
226 | * interested. The RX CCID need not parse Ack Vectors, | ||
227 | * since it is only interested in clearing old state. | ||
228 | * Fall through. | ||
229 | */ | ||
229 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: | 230 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: |
230 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, | 231 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, |
231 | pkt_type, opt, value, len)) | 232 | pkt_type, opt, value, len)) |
@@ -340,6 +341,7 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time) | |||
340 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; | 341 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; |
341 | } | 342 | } |
342 | 343 | ||
344 | /* FIXME: This function is currently not used anywhere */ | ||
343 | int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time) | 345 | int dccp_insert_option_elapsed_time(struct sk_buff *skb, u32 elapsed_time) |
344 | { | 346 | { |
345 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 347 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
@@ -424,6 +426,83 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, | |||
424 | return 0; | 426 | return 0; |
425 | } | 427 | } |
426 | 428 | ||
429 | static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | ||
430 | { | ||
431 | struct dccp_sock *dp = dccp_sk(sk); | ||
432 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | ||
433 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
434 | const u16 buflen = dccp_ackvec_buflen(av); | ||
435 | /* Figure out how many options do we need to represent the ackvec */ | ||
436 | const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); | ||
437 | u16 len = buflen + 2 * nr_opts; | ||
438 | u8 i, nonce = 0; | ||
439 | const unsigned char *tail, *from; | ||
440 | unsigned char *to; | ||
441 | |||
442 | if (dcb->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { | ||
443 | DCCP_WARN("Lacking space for %u bytes on %s packet\n", len, | ||
444 | dccp_packet_name(dcb->dccpd_type)); | ||
445 | return -1; | ||
446 | } | ||
447 | /* | ||
448 | * Since Ack Vectors are variable-length, we can not always predict | ||
449 | * their size. To catch exception cases where the space is running out | ||
450 | * on the skb, a separate Sync is scheduled to carry the Ack Vector. | ||
451 | */ | ||
452 | if (len > DCCPAV_MIN_OPTLEN && | ||
453 | len + dcb->dccpd_opt_len + skb->len > dp->dccps_mss_cache) { | ||
454 | DCCP_WARN("No space left for Ack Vector (%u) on skb (%u+%u), " | ||
455 | "MPS=%u ==> reduce payload size?\n", len, skb->len, | ||
456 | dcb->dccpd_opt_len, dp->dccps_mss_cache); | ||
457 | dp->dccps_sync_scheduled = 1; | ||
458 | return 0; | ||
459 | } | ||
460 | dcb->dccpd_opt_len += len; | ||
461 | |||
462 | to = skb_push(skb, len); | ||
463 | len = buflen; | ||
464 | from = av->av_buf + av->av_buf_head; | ||
465 | tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; | ||
466 | |||
467 | for (i = 0; i < nr_opts; ++i) { | ||
468 | int copylen = len; | ||
469 | |||
470 | if (len > DCCP_SINGLE_OPT_MAXLEN) | ||
471 | copylen = DCCP_SINGLE_OPT_MAXLEN; | ||
472 | |||
473 | /* | ||
474 | * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via | ||
475 | * its type; ack_nonce is the sum of all individual buf_nonce's. | ||
476 | */ | ||
477 | nonce ^= av->av_buf_nonce[i]; | ||
478 | |||
479 | *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i]; | ||
480 | *to++ = copylen + 2; | ||
481 | |||
482 | /* Check if buf_head wraps */ | ||
483 | if (from + copylen > tail) { | ||
484 | const u16 tailsize = tail - from; | ||
485 | |||
486 | memcpy(to, from, tailsize); | ||
487 | to += tailsize; | ||
488 | len -= tailsize; | ||
489 | copylen -= tailsize; | ||
490 | from = av->av_buf; | ||
491 | } | ||
492 | |||
493 | memcpy(to, from, copylen); | ||
494 | from += copylen; | ||
495 | to += copylen; | ||
496 | len -= copylen; | ||
497 | } | ||
498 | /* | ||
499 | * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. | ||
500 | */ | ||
501 | if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce)) | ||
502 | return -ENOBUFS; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
427 | /** | 506 | /** |
428 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) | 507 | * dccp_insert_option_mandatory - Mandatory option (5.8.2) |
429 | * Note that since we are using skb_push, this function needs to be called | 508 | * Note that since we are using skb_push, this function needs to be called |
@@ -519,8 +598,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
519 | if (dccp_insert_option_timestamp(skb)) | 598 | if (dccp_insert_option_timestamp(skb)) |
520 | return -1; | 599 | return -1; |
521 | 600 | ||
522 | } else if (dp->dccps_hc_rx_ackvec != NULL && | 601 | } else if (dccp_ackvec_pending(sk) && |
523 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && | ||
524 | dccp_insert_option_ackvec(sk, skb)) { | 602 | dccp_insert_option_ackvec(sk, skb)) { |
525 | return -1; | 603 | return -1; |
526 | } | 604 | } |
diff --git a/net/dccp/output.c b/net/dccp/output.c index 45b91853f5ae..784d30210543 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -242,7 +242,7 @@ static void dccp_xmit_packet(struct sock *sk) | |||
242 | { | 242 | { |
243 | int err, len; | 243 | int err, len; |
244 | struct dccp_sock *dp = dccp_sk(sk); | 244 | struct dccp_sock *dp = dccp_sk(sk); |
245 | struct sk_buff *skb = skb_dequeue(&sk->sk_write_queue); | 245 | struct sk_buff *skb = dccp_qpolicy_pop(sk); |
246 | 246 | ||
247 | if (unlikely(skb == NULL)) | 247 | if (unlikely(skb == NULL)) |
248 | return; | 248 | return; |
@@ -283,6 +283,15 @@ static void dccp_xmit_packet(struct sock *sk) | |||
283 | * any local drop will eventually be reported via receiver feedback. | 283 | * any local drop will eventually be reported via receiver feedback. |
284 | */ | 284 | */ |
285 | ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); | 285 | ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); |
286 | |||
287 | /* | ||
288 | * If the CCID needs to transfer additional header options out-of-band | ||
289 | * (e.g. Ack Vectors or feature-negotiation options), it activates this | ||
290 | * flag to schedule a Sync. The Sync will automatically incorporate all | ||
291 | * currently pending header options, thus clearing the backlog. | ||
292 | */ | ||
293 | if (dp->dccps_sync_scheduled) | ||
294 | dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC); | ||
286 | } | 295 | } |
287 | 296 | ||
288 | /** | 297 | /** |
@@ -336,7 +345,7 @@ void dccp_write_xmit(struct sock *sk) | |||
336 | struct dccp_sock *dp = dccp_sk(sk); | 345 | struct dccp_sock *dp = dccp_sk(sk); |
337 | struct sk_buff *skb; | 346 | struct sk_buff *skb; |
338 | 347 | ||
339 | while ((skb = skb_peek(&sk->sk_write_queue))) { | 348 | while ((skb = dccp_qpolicy_top(sk))) { |
340 | int rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); | 349 | int rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); |
341 | 350 | ||
342 | switch (ccid_packet_dequeue_eval(rc)) { | 351 | switch (ccid_packet_dequeue_eval(rc)) { |
@@ -350,8 +359,7 @@ void dccp_write_xmit(struct sock *sk) | |||
350 | dccp_xmit_packet(sk); | 359 | dccp_xmit_packet(sk); |
351 | break; | 360 | break; |
352 | case CCID_PACKET_ERR: | 361 | case CCID_PACKET_ERR: |
353 | skb_dequeue(&sk->sk_write_queue); | 362 | dccp_qpolicy_drop(sk, skb); |
354 | kfree_skb(skb); | ||
355 | dccp_pr_debug("packet discarded due to err=%d\n", rc); | 363 | dccp_pr_debug("packet discarded due to err=%d\n", rc); |
356 | } | 364 | } |
357 | } | 365 | } |
@@ -636,6 +644,12 @@ void dccp_send_sync(struct sock *sk, const u64 ackno, | |||
636 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; | 644 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; |
637 | DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno; | 645 | DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno; |
638 | 646 | ||
647 | /* | ||
648 | * Clear the flag in case the Sync was scheduled for out-of-band data, | ||
649 | * such as carrying a long Ack Vector. | ||
650 | */ | ||
651 | dccp_sk(sk)->dccps_sync_scheduled = 0; | ||
652 | |||
639 | dccp_transmit_skb(sk, skb); | 653 | dccp_transmit_skb(sk, skb); |
640 | } | 654 | } |
641 | 655 | ||
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index ef343d53fcea..152975d942d9 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -185,6 +185,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | |||
185 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 185 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
186 | dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; | 186 | dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; |
187 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; | 187 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; |
188 | dp->dccps_tx_qlen = sysctl_dccp_tx_qlen; | ||
188 | 189 | ||
189 | dccp_init_xmit_timers(sk); | 190 | dccp_init_xmit_timers(sk); |
190 | 191 | ||
@@ -532,6 +533,20 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | |||
532 | case DCCP_SOCKOPT_RECV_CSCOV: | 533 | case DCCP_SOCKOPT_RECV_CSCOV: |
533 | err = dccp_setsockopt_cscov(sk, val, true); | 534 | err = dccp_setsockopt_cscov(sk, val, true); |
534 | break; | 535 | break; |
536 | case DCCP_SOCKOPT_QPOLICY_ID: | ||
537 | if (sk->sk_state != DCCP_CLOSED) | ||
538 | err = -EISCONN; | ||
539 | else if (val < 0 || val >= DCCPQ_POLICY_MAX) | ||
540 | err = -EINVAL; | ||
541 | else | ||
542 | dp->dccps_qpolicy = val; | ||
543 | break; | ||
544 | case DCCP_SOCKOPT_QPOLICY_TXQLEN: | ||
545 | if (val < 0) | ||
546 | err = -EINVAL; | ||
547 | else | ||
548 | dp->dccps_tx_qlen = val; | ||
549 | break; | ||
535 | default: | 550 | default: |
536 | err = -ENOPROTOOPT; | 551 | err = -ENOPROTOOPT; |
537 | break; | 552 | break; |
@@ -639,6 +654,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, | |||
639 | case DCCP_SOCKOPT_RECV_CSCOV: | 654 | case DCCP_SOCKOPT_RECV_CSCOV: |
640 | val = dp->dccps_pcrlen; | 655 | val = dp->dccps_pcrlen; |
641 | break; | 656 | break; |
657 | case DCCP_SOCKOPT_QPOLICY_ID: | ||
658 | val = dp->dccps_qpolicy; | ||
659 | break; | ||
660 | case DCCP_SOCKOPT_QPOLICY_TXQLEN: | ||
661 | val = dp->dccps_tx_qlen; | ||
662 | break; | ||
642 | case 128 ... 191: | 663 | case 128 ... 191: |
643 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, | 664 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, |
644 | len, (u32 __user *)optval, optlen); | 665 | len, (u32 __user *)optval, optlen); |
@@ -681,6 +702,47 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname, | |||
681 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); | 702 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); |
682 | #endif | 703 | #endif |
683 | 704 | ||
705 | static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb) | ||
706 | { | ||
707 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); | ||
708 | |||
709 | /* | ||
710 | * Assign an (opaque) qpolicy priority value to skb->priority. | ||
711 | * | ||
712 | * We are overloading this skb field for use with the qpolicy subystem. | ||
713 | * The skb->priority is normally used for the SO_PRIORITY option, which | ||
714 | * is initialised from sk_priority. Since the assignment of sk_priority | ||
715 | * to skb->priority happens later (on layer 3), we overload this field | ||
716 | * for use with queueing priorities as long as the skb is on layer 4. | ||
717 | * The default priority value (if nothing is set) is 0. | ||
718 | */ | ||
719 | skb->priority = 0; | ||
720 | |||
721 | for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { | ||
722 | |||
723 | if (!CMSG_OK(msg, cmsg)) | ||
724 | return -EINVAL; | ||
725 | |||
726 | if (cmsg->cmsg_level != SOL_DCCP) | ||
727 | continue; | ||
728 | |||
729 | if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX && | ||
730 | !dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type)) | ||
731 | return -EINVAL; | ||
732 | |||
733 | switch (cmsg->cmsg_type) { | ||
734 | case DCCP_SCM_PRIORITY: | ||
735 | if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32))) | ||
736 | return -EINVAL; | ||
737 | skb->priority = *(__u32 *)CMSG_DATA(cmsg); | ||
738 | break; | ||
739 | default: | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | } | ||
743 | return 0; | ||
744 | } | ||
745 | |||
684 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 746 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
685 | size_t len) | 747 | size_t len) |
686 | { | 748 | { |
@@ -696,8 +758,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
696 | 758 | ||
697 | lock_sock(sk); | 759 | lock_sock(sk); |
698 | 760 | ||
699 | if (sysctl_dccp_tx_qlen && | 761 | if (dccp_qpolicy_full(sk)) { |
700 | (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) { | ||
701 | rc = -EAGAIN; | 762 | rc = -EAGAIN; |
702 | goto out_release; | 763 | goto out_release; |
703 | } | 764 | } |
@@ -725,7 +786,11 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
725 | if (rc != 0) | 786 | if (rc != 0) |
726 | goto out_discard; | 787 | goto out_discard; |
727 | 788 | ||
728 | skb_queue_tail(&sk->sk_write_queue, skb); | 789 | rc = dccp_msghdr_parse(msg, skb); |
790 | if (rc != 0) | ||
791 | goto out_discard; | ||
792 | |||
793 | dccp_qpolicy_push(sk, skb); | ||
729 | /* | 794 | /* |
730 | * The xmit_timer is set if the TX CCID is rate-based and will expire | 795 | * The xmit_timer is set if the TX CCID is rate-based and will expire |
731 | * when congestion control permits to release further packets into the | 796 | * when congestion control permits to release further packets into the |
diff --git a/net/dccp/qpolicy.c b/net/dccp/qpolicy.c new file mode 100644 index 000000000000..63c30bfa4703 --- /dev/null +++ b/net/dccp/qpolicy.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * net/dccp/qpolicy.c | ||
3 | * | ||
4 | * Policy-based packet dequeueing interface for DCCP. | ||
5 | * | ||
6 | * Copyright (c) 2008 Tomasz Grobelny <tomasz@grobelny.oswiecenia.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License v2 | ||
10 | * as published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include "dccp.h" | ||
13 | |||
14 | /* | ||
15 | * Simple Dequeueing Policy: | ||
16 | * If tx_qlen is different from 0, enqueue up to tx_qlen elements. | ||
17 | */ | ||
18 | static void qpolicy_simple_push(struct sock *sk, struct sk_buff *skb) | ||
19 | { | ||
20 | skb_queue_tail(&sk->sk_write_queue, skb); | ||
21 | } | ||
22 | |||
23 | static bool qpolicy_simple_full(struct sock *sk) | ||
24 | { | ||
25 | return dccp_sk(sk)->dccps_tx_qlen && | ||
26 | sk->sk_write_queue.qlen >= dccp_sk(sk)->dccps_tx_qlen; | ||
27 | } | ||
28 | |||
29 | static struct sk_buff *qpolicy_simple_top(struct sock *sk) | ||
30 | { | ||
31 | return skb_peek(&sk->sk_write_queue); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Priority-based Dequeueing Policy: | ||
36 | * If tx_qlen is different from 0 and the queue has reached its upper bound | ||
37 | * of tx_qlen elements, replace older packets lowest-priority-first. | ||
38 | */ | ||
39 | static struct sk_buff *qpolicy_prio_best_skb(struct sock *sk) | ||
40 | { | ||
41 | struct sk_buff *skb, *best = NULL; | ||
42 | |||
43 | skb_queue_walk(&sk->sk_write_queue, skb) | ||
44 | if (best == NULL || skb->priority > best->priority) | ||
45 | best = skb; | ||
46 | return best; | ||
47 | } | ||
48 | |||
49 | static struct sk_buff *qpolicy_prio_worst_skb(struct sock *sk) | ||
50 | { | ||
51 | struct sk_buff *skb, *worst = NULL; | ||
52 | |||
53 | skb_queue_walk(&sk->sk_write_queue, skb) | ||
54 | if (worst == NULL || skb->priority < worst->priority) | ||
55 | worst = skb; | ||
56 | return worst; | ||
57 | } | ||
58 | |||
59 | static bool qpolicy_prio_full(struct sock *sk) | ||
60 | { | ||
61 | if (qpolicy_simple_full(sk)) | ||
62 | dccp_qpolicy_drop(sk, qpolicy_prio_worst_skb(sk)); | ||
63 | return false; | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * struct dccp_qpolicy_operations - TX Packet Dequeueing Interface | ||
68 | * @push: add a new @skb to the write queue | ||
69 | * @full: indicates that no more packets will be admitted | ||
70 | * @top: peeks at whatever the queueing policy defines as its `top' | ||
71 | */ | ||
72 | static struct dccp_qpolicy_operations { | ||
73 | void (*push) (struct sock *sk, struct sk_buff *skb); | ||
74 | bool (*full) (struct sock *sk); | ||
75 | struct sk_buff* (*top) (struct sock *sk); | ||
76 | __be32 params; | ||
77 | |||
78 | } qpol_table[DCCPQ_POLICY_MAX] = { | ||
79 | [DCCPQ_POLICY_SIMPLE] = { | ||
80 | .push = qpolicy_simple_push, | ||
81 | .full = qpolicy_simple_full, | ||
82 | .top = qpolicy_simple_top, | ||
83 | .params = 0, | ||
84 | }, | ||
85 | [DCCPQ_POLICY_PRIO] = { | ||
86 | .push = qpolicy_simple_push, | ||
87 | .full = qpolicy_prio_full, | ||
88 | .top = qpolicy_prio_best_skb, | ||
89 | .params = DCCP_SCM_PRIORITY, | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | /* | ||
94 | * Externally visible interface | ||
95 | */ | ||
96 | void dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb) | ||
97 | { | ||
98 | qpol_table[dccp_sk(sk)->dccps_qpolicy].push(sk, skb); | ||
99 | } | ||
100 | |||
101 | bool dccp_qpolicy_full(struct sock *sk) | ||
102 | { | ||
103 | return qpol_table[dccp_sk(sk)->dccps_qpolicy].full(sk); | ||
104 | } | ||
105 | |||
106 | void dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb) | ||
107 | { | ||
108 | if (skb != NULL) { | ||
109 | skb_unlink(skb, &sk->sk_write_queue); | ||
110 | kfree_skb(skb); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | struct sk_buff *dccp_qpolicy_top(struct sock *sk) | ||
115 | { | ||
116 | return qpol_table[dccp_sk(sk)->dccps_qpolicy].top(sk); | ||
117 | } | ||
118 | |||
119 | struct sk_buff *dccp_qpolicy_pop(struct sock *sk) | ||
120 | { | ||
121 | struct sk_buff *skb = dccp_qpolicy_top(sk); | ||
122 | |||
123 | if (skb != NULL) { | ||
124 | /* Clear any skb fields that we used internally */ | ||
125 | skb->priority = 0; | ||
126 | skb_unlink(skb, &sk->sk_write_queue); | ||
127 | } | ||
128 | return skb; | ||
129 | } | ||
130 | |||
131 | bool dccp_qpolicy_param_ok(struct sock *sk, __be32 param) | ||
132 | { | ||
133 | /* check if exactly one bit is set */ | ||
134 | if (!param || (param & (param - 1))) | ||
135 | return false; | ||
136 | return (qpol_table[dccp_sk(sk)->dccps_qpolicy].params & param) == param; | ||
137 | } | ||
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 6f97268ed85f..2af15b15d1fa 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c | |||
@@ -829,7 +829,7 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation) | |||
829 | return -EINVAL; | 829 | return -EINVAL; |
830 | 830 | ||
831 | scp->state = DN_CC; | 831 | scp->state = DN_CC; |
832 | scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS); | 832 | scp->segsize_loc = dst_metric_advmss(__sk_dst_get(sk)); |
833 | dn_send_conn_conf(sk, allocation); | 833 | dn_send_conn_conf(sk, allocation); |
834 | 834 | ||
835 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 835 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
@@ -958,7 +958,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, | |||
958 | sk->sk_route_caps = sk->sk_dst_cache->dev->features; | 958 | sk->sk_route_caps = sk->sk_dst_cache->dev->features; |
959 | sock->state = SS_CONNECTING; | 959 | sock->state = SS_CONNECTING; |
960 | scp->state = DN_CI; | 960 | scp->state = DN_CI; |
961 | scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS); | 961 | scp->segsize_loc = dst_metric_advmss(sk->sk_dst_cache); |
962 | 962 | ||
963 | dn_nsp_send_conninit(sk, NSP_CI); | 963 | dn_nsp_send_conninit(sk, NSP_CI); |
964 | err = -EINPROGRESS; | 964 | err = -EINPROGRESS; |
@@ -1850,7 +1850,7 @@ unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu) | |||
1850 | { | 1850 | { |
1851 | unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER; | 1851 | unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER; |
1852 | if (dev) { | 1852 | if (dev) { |
1853 | struct dn_dev *dn_db = dev->dn_ptr; | 1853 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1854 | mtu -= LL_RESERVED_SPACE(dev); | 1854 | mtu -= LL_RESERVED_SPACE(dev); |
1855 | if (dn_db->use_long) | 1855 | if (dn_db->use_long) |
1856 | mtu -= 21; | 1856 | mtu -= 21; |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 4c409b46aa35..0ba15633c418 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -267,7 +267,7 @@ static int dn_forwarding_proc(ctl_table *table, int write, | |||
267 | if (table->extra1 == NULL) | 267 | if (table->extra1 == NULL) |
268 | return -EINVAL; | 268 | return -EINVAL; |
269 | 269 | ||
270 | dn_db = dev->dn_ptr; | 270 | dn_db = rcu_dereference_raw(dev->dn_ptr); |
271 | old = dn_db->parms.forwarding; | 271 | old = dn_db->parms.forwarding; |
272 | 272 | ||
273 | err = proc_dointvec(table, write, buffer, lenp, ppos); | 273 | err = proc_dointvec(table, write, buffer, lenp, ppos); |
@@ -332,14 +332,19 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void) | |||
332 | return ifa; | 332 | return ifa; |
333 | } | 333 | } |
334 | 334 | ||
335 | static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa) | 335 | static void dn_dev_free_ifa_rcu(struct rcu_head *head) |
336 | { | 336 | { |
337 | kfree(ifa); | 337 | kfree(container_of(head, struct dn_ifaddr, rcu)); |
338 | } | 338 | } |
339 | 339 | ||
340 | static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy) | 340 | static void dn_dev_free_ifa(struct dn_ifaddr *ifa) |
341 | { | 341 | { |
342 | struct dn_ifaddr *ifa1 = *ifap; | 342 | call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu); |
343 | } | ||
344 | |||
345 | static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy) | ||
346 | { | ||
347 | struct dn_ifaddr *ifa1 = rtnl_dereference(*ifap); | ||
343 | unsigned char mac_addr[6]; | 348 | unsigned char mac_addr[6]; |
344 | struct net_device *dev = dn_db->dev; | 349 | struct net_device *dev = dn_db->dev; |
345 | 350 | ||
@@ -373,7 +378,9 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
373 | ASSERT_RTNL(); | 378 | ASSERT_RTNL(); |
374 | 379 | ||
375 | /* Check for duplicates */ | 380 | /* Check for duplicates */ |
376 | for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { | 381 | for (ifa1 = rtnl_dereference(dn_db->ifa_list); |
382 | ifa1 != NULL; | ||
383 | ifa1 = rtnl_dereference(ifa1->ifa_next)) { | ||
377 | if (ifa1->ifa_local == ifa->ifa_local) | 384 | if (ifa1->ifa_local == ifa->ifa_local) |
378 | return -EEXIST; | 385 | return -EEXIST; |
379 | } | 386 | } |
@@ -386,7 +393,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
386 | } | 393 | } |
387 | 394 | ||
388 | ifa->ifa_next = dn_db->ifa_list; | 395 | ifa->ifa_next = dn_db->ifa_list; |
389 | dn_db->ifa_list = ifa; | 396 | rcu_assign_pointer(dn_db->ifa_list, ifa); |
390 | 397 | ||
391 | dn_ifaddr_notify(RTM_NEWADDR, ifa); | 398 | dn_ifaddr_notify(RTM_NEWADDR, ifa); |
392 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); | 399 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); |
@@ -396,7 +403,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
396 | 403 | ||
397 | static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa) | 404 | static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa) |
398 | { | 405 | { |
399 | struct dn_dev *dn_db = dev->dn_ptr; | 406 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
400 | int rv; | 407 | int rv; |
401 | 408 | ||
402 | if (dn_db == NULL) { | 409 | if (dn_db == NULL) { |
@@ -425,7 +432,8 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) | |||
425 | struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr; | 432 | struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr; |
426 | struct dn_dev *dn_db; | 433 | struct dn_dev *dn_db; |
427 | struct net_device *dev; | 434 | struct net_device *dev; |
428 | struct dn_ifaddr *ifa = NULL, **ifap = NULL; | 435 | struct dn_ifaddr *ifa = NULL; |
436 | struct dn_ifaddr __rcu **ifap = NULL; | ||
429 | int ret = 0; | 437 | int ret = 0; |
430 | 438 | ||
431 | if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) | 439 | if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) |
@@ -454,8 +462,10 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) | |||
454 | goto done; | 462 | goto done; |
455 | } | 463 | } |
456 | 464 | ||
457 | if ((dn_db = dev->dn_ptr) != NULL) { | 465 | if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) { |
458 | for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) | 466 | for (ifap = &dn_db->ifa_list; |
467 | (ifa = rtnl_dereference(*ifap)) != NULL; | ||
468 | ifap = &ifa->ifa_next) | ||
459 | if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0) | 469 | if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0) |
460 | break; | 470 | break; |
461 | } | 471 | } |
@@ -558,7 +568,7 @@ static struct dn_dev *dn_dev_by_index(int ifindex) | |||
558 | 568 | ||
559 | dev = __dev_get_by_index(&init_net, ifindex); | 569 | dev = __dev_get_by_index(&init_net, ifindex); |
560 | if (dev) | 570 | if (dev) |
561 | dn_dev = dev->dn_ptr; | 571 | dn_dev = rtnl_dereference(dev->dn_ptr); |
562 | 572 | ||
563 | return dn_dev; | 573 | return dn_dev; |
564 | } | 574 | } |
@@ -576,7 +586,8 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
576 | struct nlattr *tb[IFA_MAX+1]; | 586 | struct nlattr *tb[IFA_MAX+1]; |
577 | struct dn_dev *dn_db; | 587 | struct dn_dev *dn_db; |
578 | struct ifaddrmsg *ifm; | 588 | struct ifaddrmsg *ifm; |
579 | struct dn_ifaddr *ifa, **ifap; | 589 | struct dn_ifaddr *ifa; |
590 | struct dn_ifaddr __rcu **ifap; | ||
580 | int err = -EINVAL; | 591 | int err = -EINVAL; |
581 | 592 | ||
582 | if (!net_eq(net, &init_net)) | 593 | if (!net_eq(net, &init_net)) |
@@ -592,7 +603,9 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
592 | goto errout; | 603 | goto errout; |
593 | 604 | ||
594 | err = -EADDRNOTAVAIL; | 605 | err = -EADDRNOTAVAIL; |
595 | for (ifap = &dn_db->ifa_list; (ifa = *ifap); ifap = &ifa->ifa_next) { | 606 | for (ifap = &dn_db->ifa_list; |
607 | (ifa = rtnl_dereference(*ifap)) != NULL; | ||
608 | ifap = &ifa->ifa_next) { | ||
596 | if (tb[IFA_LOCAL] && | 609 | if (tb[IFA_LOCAL] && |
597 | nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2)) | 610 | nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2)) |
598 | continue; | 611 | continue; |
@@ -632,7 +645,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
632 | if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) | 645 | if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL) |
633 | return -ENODEV; | 646 | return -ENODEV; |
634 | 647 | ||
635 | if ((dn_db = dev->dn_ptr) == NULL) { | 648 | if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) { |
636 | dn_db = dn_dev_create(dev, &err); | 649 | dn_db = dn_dev_create(dev, &err); |
637 | if (!dn_db) | 650 | if (!dn_db) |
638 | return err; | 651 | return err; |
@@ -748,11 +761,11 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
748 | skip_naddr = 0; | 761 | skip_naddr = 0; |
749 | } | 762 | } |
750 | 763 | ||
751 | if ((dn_db = dev->dn_ptr) == NULL) | 764 | if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) |
752 | goto cont; | 765 | goto cont; |
753 | 766 | ||
754 | for (ifa = dn_db->ifa_list, dn_idx = 0; ifa; | 767 | for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa; |
755 | ifa = ifa->ifa_next, dn_idx++) { | 768 | ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) { |
756 | if (dn_idx < skip_naddr) | 769 | if (dn_idx < skip_naddr) |
757 | continue; | 770 | continue; |
758 | 771 | ||
@@ -773,21 +786,22 @@ done: | |||
773 | 786 | ||
774 | static int dn_dev_get_first(struct net_device *dev, __le16 *addr) | 787 | static int dn_dev_get_first(struct net_device *dev, __le16 *addr) |
775 | { | 788 | { |
776 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 789 | struct dn_dev *dn_db; |
777 | struct dn_ifaddr *ifa; | 790 | struct dn_ifaddr *ifa; |
778 | int rv = -ENODEV; | 791 | int rv = -ENODEV; |
779 | 792 | ||
793 | rcu_read_lock(); | ||
794 | dn_db = rcu_dereference(dev->dn_ptr); | ||
780 | if (dn_db == NULL) | 795 | if (dn_db == NULL) |
781 | goto out; | 796 | goto out; |
782 | 797 | ||
783 | rtnl_lock(); | 798 | ifa = rcu_dereference(dn_db->ifa_list); |
784 | ifa = dn_db->ifa_list; | ||
785 | if (ifa != NULL) { | 799 | if (ifa != NULL) { |
786 | *addr = ifa->ifa_local; | 800 | *addr = ifa->ifa_local; |
787 | rv = 0; | 801 | rv = 0; |
788 | } | 802 | } |
789 | rtnl_unlock(); | ||
790 | out: | 803 | out: |
804 | rcu_read_unlock(); | ||
791 | return rv; | 805 | return rv; |
792 | } | 806 | } |
793 | 807 | ||
@@ -823,7 +837,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
823 | struct endnode_hello_message *msg; | 837 | struct endnode_hello_message *msg; |
824 | struct sk_buff *skb = NULL; | 838 | struct sk_buff *skb = NULL; |
825 | __le16 *pktlen; | 839 | __le16 *pktlen; |
826 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 840 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
827 | 841 | ||
828 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) | 842 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) |
829 | return; | 843 | return; |
@@ -889,7 +903,7 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn | |||
889 | static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | 903 | static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) |
890 | { | 904 | { |
891 | int n; | 905 | int n; |
892 | struct dn_dev *dn_db = dev->dn_ptr; | 906 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
893 | struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; | 907 | struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; |
894 | struct sk_buff *skb; | 908 | struct sk_buff *skb; |
895 | size_t size; | 909 | size_t size; |
@@ -960,7 +974,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
960 | 974 | ||
961 | static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa) | 975 | static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa) |
962 | { | 976 | { |
963 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 977 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
964 | 978 | ||
965 | if (dn_db->parms.forwarding == 0) | 979 | if (dn_db->parms.forwarding == 0) |
966 | dn_send_endnode_hello(dev, ifa); | 980 | dn_send_endnode_hello(dev, ifa); |
@@ -998,7 +1012,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
998 | 1012 | ||
999 | static int dn_eth_up(struct net_device *dev) | 1013 | static int dn_eth_up(struct net_device *dev) |
1000 | { | 1014 | { |
1001 | struct dn_dev *dn_db = dev->dn_ptr; | 1015 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1002 | 1016 | ||
1003 | if (dn_db->parms.forwarding == 0) | 1017 | if (dn_db->parms.forwarding == 0) |
1004 | dev_mc_add(dev, dn_rt_all_end_mcast); | 1018 | dev_mc_add(dev, dn_rt_all_end_mcast); |
@@ -1012,7 +1026,7 @@ static int dn_eth_up(struct net_device *dev) | |||
1012 | 1026 | ||
1013 | static void dn_eth_down(struct net_device *dev) | 1027 | static void dn_eth_down(struct net_device *dev) |
1014 | { | 1028 | { |
1015 | struct dn_dev *dn_db = dev->dn_ptr; | 1029 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1016 | 1030 | ||
1017 | if (dn_db->parms.forwarding == 0) | 1031 | if (dn_db->parms.forwarding == 0) |
1018 | dev_mc_del(dev, dn_rt_all_end_mcast); | 1032 | dev_mc_del(dev, dn_rt_all_end_mcast); |
@@ -1025,12 +1039,16 @@ static void dn_dev_set_timer(struct net_device *dev); | |||
1025 | static void dn_dev_timer_func(unsigned long arg) | 1039 | static void dn_dev_timer_func(unsigned long arg) |
1026 | { | 1040 | { |
1027 | struct net_device *dev = (struct net_device *)arg; | 1041 | struct net_device *dev = (struct net_device *)arg; |
1028 | struct dn_dev *dn_db = dev->dn_ptr; | 1042 | struct dn_dev *dn_db; |
1029 | struct dn_ifaddr *ifa; | 1043 | struct dn_ifaddr *ifa; |
1030 | 1044 | ||
1045 | rcu_read_lock(); | ||
1046 | dn_db = rcu_dereference(dev->dn_ptr); | ||
1031 | if (dn_db->t3 <= dn_db->parms.t2) { | 1047 | if (dn_db->t3 <= dn_db->parms.t2) { |
1032 | if (dn_db->parms.timer3) { | 1048 | if (dn_db->parms.timer3) { |
1033 | for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { | 1049 | for (ifa = rcu_dereference(dn_db->ifa_list); |
1050 | ifa; | ||
1051 | ifa = rcu_dereference(ifa->ifa_next)) { | ||
1034 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) | 1052 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) |
1035 | dn_db->parms.timer3(dev, ifa); | 1053 | dn_db->parms.timer3(dev, ifa); |
1036 | } | 1054 | } |
@@ -1039,13 +1057,13 @@ static void dn_dev_timer_func(unsigned long arg) | |||
1039 | } else { | 1057 | } else { |
1040 | dn_db->t3 -= dn_db->parms.t2; | 1058 | dn_db->t3 -= dn_db->parms.t2; |
1041 | } | 1059 | } |
1042 | 1060 | rcu_read_unlock(); | |
1043 | dn_dev_set_timer(dev); | 1061 | dn_dev_set_timer(dev); |
1044 | } | 1062 | } |
1045 | 1063 | ||
1046 | static void dn_dev_set_timer(struct net_device *dev) | 1064 | static void dn_dev_set_timer(struct net_device *dev) |
1047 | { | 1065 | { |
1048 | struct dn_dev *dn_db = dev->dn_ptr; | 1066 | struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr); |
1049 | 1067 | ||
1050 | if (dn_db->parms.t2 > dn_db->parms.t3) | 1068 | if (dn_db->parms.t2 > dn_db->parms.t3) |
1051 | dn_db->parms.t2 = dn_db->parms.t3; | 1069 | dn_db->parms.t2 = dn_db->parms.t3; |
@@ -1077,8 +1095,8 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err) | |||
1077 | return NULL; | 1095 | return NULL; |
1078 | 1096 | ||
1079 | memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); | 1097 | memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); |
1080 | smp_wmb(); | 1098 | |
1081 | dev->dn_ptr = dn_db; | 1099 | rcu_assign_pointer(dev->dn_ptr, dn_db); |
1082 | dn_db->dev = dev; | 1100 | dn_db->dev = dev; |
1083 | init_timer(&dn_db->timer); | 1101 | init_timer(&dn_db->timer); |
1084 | 1102 | ||
@@ -1086,7 +1104,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err) | |||
1086 | 1104 | ||
1087 | dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); | 1105 | dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); |
1088 | if (!dn_db->neigh_parms) { | 1106 | if (!dn_db->neigh_parms) { |
1089 | dev->dn_ptr = NULL; | 1107 | rcu_assign_pointer(dev->dn_ptr, NULL); |
1090 | kfree(dn_db); | 1108 | kfree(dn_db); |
1091 | return NULL; | 1109 | return NULL; |
1092 | } | 1110 | } |
@@ -1125,7 +1143,7 @@ void dn_dev_up(struct net_device *dev) | |||
1125 | struct dn_ifaddr *ifa; | 1143 | struct dn_ifaddr *ifa; |
1126 | __le16 addr = decnet_address; | 1144 | __le16 addr = decnet_address; |
1127 | int maybe_default = 0; | 1145 | int maybe_default = 0; |
1128 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 1146 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
1129 | 1147 | ||
1130 | if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) | 1148 | if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) |
1131 | return; | 1149 | return; |
@@ -1176,7 +1194,7 @@ void dn_dev_up(struct net_device *dev) | |||
1176 | 1194 | ||
1177 | static void dn_dev_delete(struct net_device *dev) | 1195 | static void dn_dev_delete(struct net_device *dev) |
1178 | { | 1196 | { |
1179 | struct dn_dev *dn_db = dev->dn_ptr; | 1197 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
1180 | 1198 | ||
1181 | if (dn_db == NULL) | 1199 | if (dn_db == NULL) |
1182 | return; | 1200 | return; |
@@ -1204,13 +1222,13 @@ static void dn_dev_delete(struct net_device *dev) | |||
1204 | 1222 | ||
1205 | void dn_dev_down(struct net_device *dev) | 1223 | void dn_dev_down(struct net_device *dev) |
1206 | { | 1224 | { |
1207 | struct dn_dev *dn_db = dev->dn_ptr; | 1225 | struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr); |
1208 | struct dn_ifaddr *ifa; | 1226 | struct dn_ifaddr *ifa; |
1209 | 1227 | ||
1210 | if (dn_db == NULL) | 1228 | if (dn_db == NULL) |
1211 | return; | 1229 | return; |
1212 | 1230 | ||
1213 | while((ifa = dn_db->ifa_list) != NULL) { | 1231 | while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) { |
1214 | dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0); | 1232 | dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0); |
1215 | dn_dev_free_ifa(ifa); | 1233 | dn_dev_free_ifa(ifa); |
1216 | } | 1234 | } |
@@ -1270,7 +1288,7 @@ static inline int is_dn_dev(struct net_device *dev) | |||
1270 | } | 1288 | } |
1271 | 1289 | ||
1272 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) | 1290 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) |
1273 | __acquires(rcu) | 1291 | __acquires(RCU) |
1274 | { | 1292 | { |
1275 | int i; | 1293 | int i; |
1276 | struct net_device *dev; | 1294 | struct net_device *dev; |
@@ -1313,7 +1331,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1313 | } | 1331 | } |
1314 | 1332 | ||
1315 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) | 1333 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) |
1316 | __releases(rcu) | 1334 | __releases(RCU) |
1317 | { | 1335 | { |
1318 | rcu_read_unlock(); | 1336 | rcu_read_unlock(); |
1319 | } | 1337 | } |
@@ -1340,7 +1358,7 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v) | |||
1340 | struct net_device *dev = v; | 1358 | struct net_device *dev = v; |
1341 | char peer_buf[DN_ASCBUF_LEN]; | 1359 | char peer_buf[DN_ASCBUF_LEN]; |
1342 | char router_buf[DN_ASCBUF_LEN]; | 1360 | char router_buf[DN_ASCBUF_LEN]; |
1343 | struct dn_dev *dn_db = dev->dn_ptr; | 1361 | struct dn_dev *dn_db = rcu_dereference(dev->dn_ptr); |
1344 | 1362 | ||
1345 | seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" | 1363 | seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" |
1346 | " %04hu %03d %02x %-10s %-7s %-7s\n", | 1364 | " %04hu %03d %02x %-10s %-7s %-7s\n", |
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 4ab96c15166d..0ef0a81bcd72 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c | |||
@@ -610,10 +610,12 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) | |||
610 | /* Scan device list */ | 610 | /* Scan device list */ |
611 | rcu_read_lock(); | 611 | rcu_read_lock(); |
612 | for_each_netdev_rcu(&init_net, dev) { | 612 | for_each_netdev_rcu(&init_net, dev) { |
613 | dn_db = dev->dn_ptr; | 613 | dn_db = rcu_dereference(dev->dn_ptr); |
614 | if (dn_db == NULL) | 614 | if (dn_db == NULL) |
615 | continue; | 615 | continue; |
616 | for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) { | 616 | for (ifa2 = rcu_dereference(dn_db->ifa_list); |
617 | ifa2 != NULL; | ||
618 | ifa2 = rcu_dereference(ifa2->ifa_next)) { | ||
617 | if (ifa2->ifa_local == ifa->ifa_local) { | 619 | if (ifa2->ifa_local == ifa->ifa_local) { |
618 | found_it = 1; | 620 | found_it = 1; |
619 | break; | 621 | break; |
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index a085dbcf5c7f..602dade7e9a3 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c | |||
@@ -391,7 +391,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) | |||
391 | write_lock(&neigh->lock); | 391 | write_lock(&neigh->lock); |
392 | 392 | ||
393 | neigh->used = jiffies; | 393 | neigh->used = jiffies; |
394 | dn_db = (struct dn_dev *)neigh->dev->dn_ptr; | 394 | dn_db = rcu_dereference(neigh->dev->dn_ptr); |
395 | 395 | ||
396 | if (!(neigh->nud_state & NUD_PERMANENT)) { | 396 | if (!(neigh->nud_state & NUD_PERMANENT)) { |
397 | neigh->updated = jiffies; | 397 | neigh->updated = jiffies; |
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index df0f3e54ff8a..5e636365d33c 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c | |||
@@ -93,7 +93,7 @@ | |||
93 | 93 | ||
94 | struct dn_rt_hash_bucket | 94 | struct dn_rt_hash_bucket |
95 | { | 95 | { |
96 | struct dn_route *chain; | 96 | struct dn_route __rcu *chain; |
97 | spinlock_t lock; | 97 | spinlock_t lock; |
98 | }; | 98 | }; |
99 | 99 | ||
@@ -110,6 +110,8 @@ static unsigned long dn_rt_deadline; | |||
110 | 110 | ||
111 | static int dn_dst_gc(struct dst_ops *ops); | 111 | static int dn_dst_gc(struct dst_ops *ops); |
112 | static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); | 112 | static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); |
113 | static unsigned int dn_dst_default_advmss(const struct dst_entry *dst); | ||
114 | static unsigned int dn_dst_default_mtu(const struct dst_entry *dst); | ||
113 | static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); | 115 | static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); |
114 | static void dn_dst_link_failure(struct sk_buff *); | 116 | static void dn_dst_link_failure(struct sk_buff *); |
115 | static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu); | 117 | static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu); |
@@ -129,6 +131,8 @@ static struct dst_ops dn_dst_ops = { | |||
129 | .gc_thresh = 128, | 131 | .gc_thresh = 128, |
130 | .gc = dn_dst_gc, | 132 | .gc = dn_dst_gc, |
131 | .check = dn_dst_check, | 133 | .check = dn_dst_check, |
134 | .default_advmss = dn_dst_default_advmss, | ||
135 | .default_mtu = dn_dst_default_mtu, | ||
132 | .negative_advice = dn_dst_negative_advice, | 136 | .negative_advice = dn_dst_negative_advice, |
133 | .link_failure = dn_dst_link_failure, | 137 | .link_failure = dn_dst_link_failure, |
134 | .update_pmtu = dn_dst_update_pmtu, | 138 | .update_pmtu = dn_dst_update_pmtu, |
@@ -157,15 +161,17 @@ static inline void dnrt_drop(struct dn_route *rt) | |||
157 | static void dn_dst_check_expire(unsigned long dummy) | 161 | static void dn_dst_check_expire(unsigned long dummy) |
158 | { | 162 | { |
159 | int i; | 163 | int i; |
160 | struct dn_route *rt, **rtp; | 164 | struct dn_route *rt; |
165 | struct dn_route __rcu **rtp; | ||
161 | unsigned long now = jiffies; | 166 | unsigned long now = jiffies; |
162 | unsigned long expire = 120 * HZ; | 167 | unsigned long expire = 120 * HZ; |
163 | 168 | ||
164 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 169 | for (i = 0; i <= dn_rt_hash_mask; i++) { |
165 | rtp = &dn_rt_hash_table[i].chain; | 170 | rtp = &dn_rt_hash_table[i].chain; |
166 | 171 | ||
167 | spin_lock(&dn_rt_hash_table[i].lock); | 172 | spin_lock(&dn_rt_hash_table[i].lock); |
168 | while((rt=*rtp) != NULL) { | 173 | while ((rt = rcu_dereference_protected(*rtp, |
174 | lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) { | ||
169 | if (atomic_read(&rt->dst.__refcnt) || | 175 | if (atomic_read(&rt->dst.__refcnt) || |
170 | (now - rt->dst.lastuse) < expire) { | 176 | (now - rt->dst.lastuse) < expire) { |
171 | rtp = &rt->dst.dn_next; | 177 | rtp = &rt->dst.dn_next; |
@@ -186,17 +192,19 @@ static void dn_dst_check_expire(unsigned long dummy) | |||
186 | 192 | ||
187 | static int dn_dst_gc(struct dst_ops *ops) | 193 | static int dn_dst_gc(struct dst_ops *ops) |
188 | { | 194 | { |
189 | struct dn_route *rt, **rtp; | 195 | struct dn_route *rt; |
196 | struct dn_route __rcu **rtp; | ||
190 | int i; | 197 | int i; |
191 | unsigned long now = jiffies; | 198 | unsigned long now = jiffies; |
192 | unsigned long expire = 10 * HZ; | 199 | unsigned long expire = 10 * HZ; |
193 | 200 | ||
194 | for(i = 0; i <= dn_rt_hash_mask; i++) { | 201 | for (i = 0; i <= dn_rt_hash_mask; i++) { |
195 | 202 | ||
196 | spin_lock_bh(&dn_rt_hash_table[i].lock); | 203 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
197 | rtp = &dn_rt_hash_table[i].chain; | 204 | rtp = &dn_rt_hash_table[i].chain; |
198 | 205 | ||
199 | while((rt=*rtp) != NULL) { | 206 | while ((rt = rcu_dereference_protected(*rtp, |
207 | lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) { | ||
200 | if (atomic_read(&rt->dst.__refcnt) || | 208 | if (atomic_read(&rt->dst.__refcnt) || |
201 | (now - rt->dst.lastuse) < expire) { | 209 | (now - rt->dst.lastuse) < expire) { |
202 | rtp = &rt->dst.dn_next; | 210 | rtp = &rt->dst.dn_next; |
@@ -227,7 +235,7 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
227 | { | 235 | { |
228 | u32 min_mtu = 230; | 236 | u32 min_mtu = 230; |
229 | struct dn_dev *dn = dst->neighbour ? | 237 | struct dn_dev *dn = dst->neighbour ? |
230 | (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL; | 238 | rcu_dereference_raw(dst->neighbour->dev->dn_ptr) : NULL; |
231 | 239 | ||
232 | if (dn && dn->use_long == 0) | 240 | if (dn && dn->use_long == 0) |
233 | min_mtu -= 6; | 241 | min_mtu -= 6; |
@@ -236,13 +244,14 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
236 | 244 | ||
237 | if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) { | 245 | if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) { |
238 | if (!(dst_metric_locked(dst, RTAX_MTU))) { | 246 | if (!(dst_metric_locked(dst, RTAX_MTU))) { |
239 | dst->metrics[RTAX_MTU-1] = mtu; | 247 | dst_metric_set(dst, RTAX_MTU, mtu); |
240 | dst_set_expires(dst, dn_rt_mtu_expires); | 248 | dst_set_expires(dst, dn_rt_mtu_expires); |
241 | } | 249 | } |
242 | if (!(dst_metric_locked(dst, RTAX_ADVMSS))) { | 250 | if (!(dst_metric_locked(dst, RTAX_ADVMSS))) { |
243 | u32 mss = mtu - DN_MAX_NSP_DATA_HEADER; | 251 | u32 mss = mtu - DN_MAX_NSP_DATA_HEADER; |
244 | if (dst_metric(dst, RTAX_ADVMSS) > mss) | 252 | u32 existing_mss = dst_metric_raw(dst, RTAX_ADVMSS); |
245 | dst->metrics[RTAX_ADVMSS-1] = mss; | 253 | if (!existing_mss || existing_mss > mss) |
254 | dst_metric_set(dst, RTAX_ADVMSS, mss); | ||
246 | } | 255 | } |
247 | } | 256 | } |
248 | } | 257 | } |
@@ -267,23 +276,25 @@ static void dn_dst_link_failure(struct sk_buff *skb) | |||
267 | 276 | ||
268 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | 277 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) |
269 | { | 278 | { |
270 | return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) | | 279 | return ((fl1->fld_dst ^ fl2->fld_dst) | |
271 | (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) | | 280 | (fl1->fld_src ^ fl2->fld_src) | |
272 | (fl1->mark ^ fl2->mark) | | 281 | (fl1->mark ^ fl2->mark) | |
273 | (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) | | 282 | (fl1->fld_scope ^ fl2->fld_scope) | |
274 | (fl1->oif ^ fl2->oif) | | 283 | (fl1->oif ^ fl2->oif) | |
275 | (fl1->iif ^ fl2->iif)) == 0; | 284 | (fl1->iif ^ fl2->iif)) == 0; |
276 | } | 285 | } |
277 | 286 | ||
278 | static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) | 287 | static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) |
279 | { | 288 | { |
280 | struct dn_route *rth, **rthp; | 289 | struct dn_route *rth; |
290 | struct dn_route __rcu **rthp; | ||
281 | unsigned long now = jiffies; | 291 | unsigned long now = jiffies; |
282 | 292 | ||
283 | rthp = &dn_rt_hash_table[hash].chain; | 293 | rthp = &dn_rt_hash_table[hash].chain; |
284 | 294 | ||
285 | spin_lock_bh(&dn_rt_hash_table[hash].lock); | 295 | spin_lock_bh(&dn_rt_hash_table[hash].lock); |
286 | while((rth = *rthp) != NULL) { | 296 | while ((rth = rcu_dereference_protected(*rthp, |
297 | lockdep_is_held(&dn_rt_hash_table[hash].lock))) != NULL) { | ||
287 | if (compare_keys(&rth->fl, &rt->fl)) { | 298 | if (compare_keys(&rth->fl, &rt->fl)) { |
288 | /* Put it first */ | 299 | /* Put it first */ |
289 | *rthp = rth->dst.dn_next; | 300 | *rthp = rth->dst.dn_next; |
@@ -315,15 +326,15 @@ static void dn_run_flush(unsigned long dummy) | |||
315 | int i; | 326 | int i; |
316 | struct dn_route *rt, *next; | 327 | struct dn_route *rt, *next; |
317 | 328 | ||
318 | for(i = 0; i < dn_rt_hash_mask; i++) { | 329 | for (i = 0; i < dn_rt_hash_mask; i++) { |
319 | spin_lock_bh(&dn_rt_hash_table[i].lock); | 330 | spin_lock_bh(&dn_rt_hash_table[i].lock); |
320 | 331 | ||
321 | if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL) | 332 | if ((rt = xchg((struct dn_route **)&dn_rt_hash_table[i].chain, NULL)) == NULL) |
322 | goto nothing_to_declare; | 333 | goto nothing_to_declare; |
323 | 334 | ||
324 | for(; rt; rt=next) { | 335 | for(; rt; rt = next) { |
325 | next = rt->dst.dn_next; | 336 | next = rcu_dereference_raw(rt->dst.dn_next); |
326 | rt->dst.dn_next = NULL; | 337 | RCU_INIT_POINTER(rt->dst.dn_next, NULL); |
327 | dst_free((struct dst_entry *)rt); | 338 | dst_free((struct dst_entry *)rt); |
328 | } | 339 | } |
329 | 340 | ||
@@ -458,15 +469,16 @@ static int dn_return_long(struct sk_buff *skb) | |||
458 | */ | 469 | */ |
459 | static int dn_route_rx_packet(struct sk_buff *skb) | 470 | static int dn_route_rx_packet(struct sk_buff *skb) |
460 | { | 471 | { |
461 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 472 | struct dn_skb_cb *cb; |
462 | int err; | 473 | int err; |
463 | 474 | ||
464 | if ((err = dn_route_input(skb)) == 0) | 475 | if ((err = dn_route_input(skb)) == 0) |
465 | return dst_input(skb); | 476 | return dst_input(skb); |
466 | 477 | ||
478 | cb = DN_SKB_CB(skb); | ||
467 | if (decnet_debug_level & 4) { | 479 | if (decnet_debug_level & 4) { |
468 | char *devname = skb->dev ? skb->dev->name : "???"; | 480 | char *devname = skb->dev ? skb->dev->name : "???"; |
469 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 481 | |
470 | printk(KERN_DEBUG | 482 | printk(KERN_DEBUG |
471 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", | 483 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", |
472 | (int)cb->rt_flags, devname, skb->len, | 484 | (int)cb->rt_flags, devname, skb->len, |
@@ -573,7 +585,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type | |||
573 | struct dn_skb_cb *cb; | 585 | struct dn_skb_cb *cb; |
574 | unsigned char flags = 0; | 586 | unsigned char flags = 0; |
575 | __u16 len = le16_to_cpu(*(__le16 *)skb->data); | 587 | __u16 len = le16_to_cpu(*(__le16 *)skb->data); |
576 | struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; | 588 | struct dn_dev *dn = rcu_dereference(dev->dn_ptr); |
577 | unsigned char padlen = 0; | 589 | unsigned char padlen = 0; |
578 | 590 | ||
579 | if (!net_eq(dev_net(dev), &init_net)) | 591 | if (!net_eq(dev_net(dev), &init_net)) |
@@ -728,7 +740,7 @@ static int dn_forward(struct sk_buff *skb) | |||
728 | { | 740 | { |
729 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 741 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
730 | struct dst_entry *dst = skb_dst(skb); | 742 | struct dst_entry *dst = skb_dst(skb); |
731 | struct dn_dev *dn_db = dst->dev->dn_ptr; | 743 | struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr); |
732 | struct dn_route *rt; | 744 | struct dn_route *rt; |
733 | struct neighbour *neigh = dst->neighbour; | 745 | struct neighbour *neigh = dst->neighbour; |
734 | int header_len; | 746 | int header_len; |
@@ -788,19 +800,28 @@ static int dn_rt_bug(struct sk_buff *skb) | |||
788 | return NET_RX_DROP; | 800 | return NET_RX_DROP; |
789 | } | 801 | } |
790 | 802 | ||
803 | static unsigned int dn_dst_default_advmss(const struct dst_entry *dst) | ||
804 | { | ||
805 | return dn_mss_from_pmtu(dst->dev, dst_mtu(dst)); | ||
806 | } | ||
807 | |||
808 | static unsigned int dn_dst_default_mtu(const struct dst_entry *dst) | ||
809 | { | ||
810 | return dst->dev->mtu; | ||
811 | } | ||
812 | |||
791 | static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) | 813 | static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) |
792 | { | 814 | { |
793 | struct dn_fib_info *fi = res->fi; | 815 | struct dn_fib_info *fi = res->fi; |
794 | struct net_device *dev = rt->dst.dev; | 816 | struct net_device *dev = rt->dst.dev; |
795 | struct neighbour *n; | 817 | struct neighbour *n; |
796 | unsigned mss; | 818 | unsigned int metric; |
797 | 819 | ||
798 | if (fi) { | 820 | if (fi) { |
799 | if (DN_FIB_RES_GW(*res) && | 821 | if (DN_FIB_RES_GW(*res) && |
800 | DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) | 822 | DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) |
801 | rt->rt_gateway = DN_FIB_RES_GW(*res); | 823 | rt->rt_gateway = DN_FIB_RES_GW(*res); |
802 | memcpy(rt->dst.metrics, fi->fib_metrics, | 824 | dst_import_metrics(&rt->dst, fi->fib_metrics); |
803 | sizeof(rt->dst.metrics)); | ||
804 | } | 825 | } |
805 | rt->rt_type = res->type; | 826 | rt->rt_type = res->type; |
806 | 827 | ||
@@ -811,13 +832,14 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) | |||
811 | rt->dst.neighbour = n; | 832 | rt->dst.neighbour = n; |
812 | } | 833 | } |
813 | 834 | ||
814 | if (dst_metric(&rt->dst, RTAX_MTU) == 0 || | 835 | if (dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu) |
815 | dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu) | 836 | dst_metric_set(&rt->dst, RTAX_MTU, rt->dst.dev->mtu); |
816 | rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu; | 837 | metric = dst_metric_raw(&rt->dst, RTAX_ADVMSS); |
817 | mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst)); | 838 | if (metric) { |
818 | if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0 || | 839 | unsigned int mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst)); |
819 | dst_metric(&rt->dst, RTAX_ADVMSS) > mss) | 840 | if (metric > mss) |
820 | rt->dst.metrics[RTAX_ADVMSS-1] = mss; | 841 | dst_metric_set(&rt->dst, RTAX_ADVMSS, mss); |
842 | } | ||
821 | return 0; | 843 | return 0; |
822 | } | 844 | } |
823 | 845 | ||
@@ -835,13 +857,16 @@ static inline int dn_match_addr(__le16 addr1, __le16 addr2) | |||
835 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) | 857 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) |
836 | { | 858 | { |
837 | __le16 saddr = 0; | 859 | __le16 saddr = 0; |
838 | struct dn_dev *dn_db = dev->dn_ptr; | 860 | struct dn_dev *dn_db; |
839 | struct dn_ifaddr *ifa; | 861 | struct dn_ifaddr *ifa; |
840 | int best_match = 0; | 862 | int best_match = 0; |
841 | int ret; | 863 | int ret; |
842 | 864 | ||
843 | read_lock(&dev_base_lock); | 865 | rcu_read_lock(); |
844 | for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { | 866 | dn_db = rcu_dereference(dev->dn_ptr); |
867 | for (ifa = rcu_dereference(dn_db->ifa_list); | ||
868 | ifa != NULL; | ||
869 | ifa = rcu_dereference(ifa->ifa_next)) { | ||
845 | if (ifa->ifa_scope > scope) | 870 | if (ifa->ifa_scope > scope) |
846 | continue; | 871 | continue; |
847 | if (!daddr) { | 872 | if (!daddr) { |
@@ -854,7 +879,7 @@ static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int | |||
854 | if (best_match == 0) | 879 | if (best_match == 0) |
855 | saddr = ifa->ifa_local; | 880 | saddr = ifa->ifa_local; |
856 | } | 881 | } |
857 | read_unlock(&dev_base_lock); | 882 | rcu_read_unlock(); |
858 | 883 | ||
859 | return saddr; | 884 | return saddr; |
860 | } | 885 | } |
@@ -872,11 +897,9 @@ static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_re | |||
872 | 897 | ||
873 | static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *oldflp, int try_hard) | 898 | static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *oldflp, int try_hard) |
874 | { | 899 | { |
875 | struct flowi fl = { .nl_u = { .dn_u = | 900 | struct flowi fl = { .fld_dst = oldflp->fld_dst, |
876 | { .daddr = oldflp->fld_dst, | 901 | .fld_src = oldflp->fld_src, |
877 | .saddr = oldflp->fld_src, | 902 | .fld_scope = RT_SCOPE_UNIVERSE, |
878 | .scope = RT_SCOPE_UNIVERSE, | ||
879 | } }, | ||
880 | .mark = oldflp->mark, | 903 | .mark = oldflp->mark, |
881 | .iif = init_net.loopback_dev->ifindex, | 904 | .iif = init_net.loopback_dev->ifindex, |
882 | .oif = oldflp->oif }; | 905 | .oif = oldflp->oif }; |
@@ -1020,7 +1043,7 @@ source_ok: | |||
1020 | err = -ENODEV; | 1043 | err = -ENODEV; |
1021 | if (dev_out == NULL) | 1044 | if (dev_out == NULL) |
1022 | goto out; | 1045 | goto out; |
1023 | dn_db = dev_out->dn_ptr; | 1046 | dn_db = rcu_dereference_raw(dev_out->dn_ptr); |
1024 | /* Possible improvement - check all devices for local addr */ | 1047 | /* Possible improvement - check all devices for local addr */ |
1025 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { | 1048 | if (dn_dev_islocal(dev_out, fl.fld_dst)) { |
1026 | dev_put(dev_out); | 1049 | dev_put(dev_out); |
@@ -1171,7 +1194,7 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl | |||
1171 | if ((flp->fld_dst == rt->fl.fld_dst) && | 1194 | if ((flp->fld_dst == rt->fl.fld_dst) && |
1172 | (flp->fld_src == rt->fl.fld_src) && | 1195 | (flp->fld_src == rt->fl.fld_src) && |
1173 | (flp->mark == rt->fl.mark) && | 1196 | (flp->mark == rt->fl.mark) && |
1174 | (rt->fl.iif == 0) && | 1197 | dn_is_output_route(rt) && |
1175 | (rt->fl.oif == flp->oif)) { | 1198 | (rt->fl.oif == flp->oif)) { |
1176 | dst_use(&rt->dst, jiffies); | 1199 | dst_use(&rt->dst, jiffies); |
1177 | rcu_read_unlock_bh(); | 1200 | rcu_read_unlock_bh(); |
@@ -1220,11 +1243,9 @@ static int dn_route_input_slow(struct sk_buff *skb) | |||
1220 | int flags = 0; | 1243 | int flags = 0; |
1221 | __le16 gateway = 0; | 1244 | __le16 gateway = 0; |
1222 | __le16 local_src = 0; | 1245 | __le16 local_src = 0; |
1223 | struct flowi fl = { .nl_u = { .dn_u = | 1246 | struct flowi fl = { .fld_dst = cb->dst, |
1224 | { .daddr = cb->dst, | 1247 | .fld_src = cb->src, |
1225 | .saddr = cb->src, | 1248 | .fld_scope = RT_SCOPE_UNIVERSE, |
1226 | .scope = RT_SCOPE_UNIVERSE, | ||
1227 | } }, | ||
1228 | .mark = skb->mark, | 1249 | .mark = skb->mark, |
1229 | .iif = skb->dev->ifindex }; | 1250 | .iif = skb->dev->ifindex }; |
1230 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE }; | 1251 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE }; |
@@ -1233,7 +1254,7 @@ static int dn_route_input_slow(struct sk_buff *skb) | |||
1233 | 1254 | ||
1234 | dev_hold(in_dev); | 1255 | dev_hold(in_dev); |
1235 | 1256 | ||
1236 | if ((dn_db = in_dev->dn_ptr) == NULL) | 1257 | if ((dn_db = rcu_dereference(in_dev->dn_ptr)) == NULL) |
1237 | goto out; | 1258 | goto out; |
1238 | 1259 | ||
1239 | /* Zero source addresses are not allowed */ | 1260 | /* Zero source addresses are not allowed */ |
@@ -1496,13 +1517,13 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | |||
1496 | RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src); | 1517 | RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src); |
1497 | if (rt->rt_daddr != rt->rt_gateway) | 1518 | if (rt->rt_daddr != rt->rt_gateway) |
1498 | RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); | 1519 | RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); |
1499 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) | 1520 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
1500 | goto rtattr_failure; | 1521 | goto rtattr_failure; |
1501 | expires = rt->dst.expires ? rt->dst.expires - jiffies : 0; | 1522 | expires = rt->dst.expires ? rt->dst.expires - jiffies : 0; |
1502 | if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, expires, | 1523 | if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, expires, |
1503 | rt->dst.error) < 0) | 1524 | rt->dst.error) < 0) |
1504 | goto rtattr_failure; | 1525 | goto rtattr_failure; |
1505 | if (rt->fl.iif) | 1526 | if (dn_is_input_route(rt)) |
1506 | RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); | 1527 | RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); |
1507 | 1528 | ||
1508 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; | 1529 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
@@ -1677,15 +1698,15 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou | |||
1677 | { | 1698 | { |
1678 | struct dn_rt_cache_iter_state *s = seq->private; | 1699 | struct dn_rt_cache_iter_state *s = seq->private; |
1679 | 1700 | ||
1680 | rt = rt->dst.dn_next; | 1701 | rt = rcu_dereference_bh(rt->dst.dn_next); |
1681 | while(!rt) { | 1702 | while (!rt) { |
1682 | rcu_read_unlock_bh(); | 1703 | rcu_read_unlock_bh(); |
1683 | if (--s->bucket < 0) | 1704 | if (--s->bucket < 0) |
1684 | break; | 1705 | break; |
1685 | rcu_read_lock_bh(); | 1706 | rcu_read_lock_bh(); |
1686 | rt = dn_rt_hash_table[s->bucket].chain; | 1707 | rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain); |
1687 | } | 1708 | } |
1688 | return rcu_dereference_bh(rt); | 1709 | return rt; |
1689 | } | 1710 | } |
1690 | 1711 | ||
1691 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) | 1712 | static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) |
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 48fdf10be7a1..6eb91df3c550 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c | |||
@@ -175,7 +175,7 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | |||
175 | 175 | ||
176 | unsigned dnet_addr_type(__le16 addr) | 176 | unsigned dnet_addr_type(__le16 addr) |
177 | { | 177 | { |
178 | struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; | 178 | struct flowi fl = { .fld_dst = addr }; |
179 | struct dn_fib_res res; | 179 | struct dn_fib_res res; |
180 | unsigned ret = RTN_UNICAST; | 180 | unsigned ret = RTN_UNICAST; |
181 | struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0); | 181 | struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0); |
diff --git a/net/dns_resolver/Makefile b/net/dns_resolver/Makefile index c0ef4e71dc49..d5c13c2eb36d 100644 --- a/net/dns_resolver/Makefile +++ b/net/dns_resolver/Makefile | |||
@@ -4,4 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver.o | 5 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver.o |
6 | 6 | ||
7 | dns_resolver-objs := dns_key.o dns_query.o | 7 | dns_resolver-y := dns_key.o dns_query.o |
diff --git a/net/econet/Makefile b/net/econet/Makefile index 39f0a77abdbd..05fae8be2fed 100644 --- a/net/econet/Makefile +++ b/net/econet/Makefile | |||
@@ -4,4 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_ECONET) += econet.o | 5 | obj-$(CONFIG_ECONET) += econet.o |
6 | 6 | ||
7 | econet-objs := af_econet.o | 7 | econet-y := af_econet.o |
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 93c91b633a56..6df6ecf49708 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c | |||
@@ -52,11 +52,11 @@ struct net_device *ieee802154_get_dev(struct net *net, | |||
52 | 52 | ||
53 | switch (addr->addr_type) { | 53 | switch (addr->addr_type) { |
54 | case IEEE802154_ADDR_LONG: | 54 | case IEEE802154_ADDR_LONG: |
55 | rtnl_lock(); | 55 | rcu_read_lock(); |
56 | dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr); | 56 | dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr); |
57 | if (dev) | 57 | if (dev) |
58 | dev_hold(dev); | 58 | dev_hold(dev); |
59 | rtnl_unlock(); | 59 | rcu_read_unlock(); |
60 | break; | 60 | break; |
61 | case IEEE802154_ADDR_SHORT: | 61 | case IEEE802154_ADDR_SHORT: |
62 | if (addr->pan_id == 0xffff || | 62 | if (addr->pan_id == 0xffff || |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index f581f77d1097..f2b61107df6c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1148,21 +1148,13 @@ int inet_sk_rebuild_header(struct sock *sk) | |||
1148 | struct flowi fl = { | 1148 | struct flowi fl = { |
1149 | .oif = sk->sk_bound_dev_if, | 1149 | .oif = sk->sk_bound_dev_if, |
1150 | .mark = sk->sk_mark, | 1150 | .mark = sk->sk_mark, |
1151 | .nl_u = { | 1151 | .fl4_dst = daddr, |
1152 | .ip4_u = { | 1152 | .fl4_src = inet->inet_saddr, |
1153 | .daddr = daddr, | 1153 | .fl4_tos = RT_CONN_FLAGS(sk), |
1154 | .saddr = inet->inet_saddr, | ||
1155 | .tos = RT_CONN_FLAGS(sk), | ||
1156 | }, | ||
1157 | }, | ||
1158 | .proto = sk->sk_protocol, | 1154 | .proto = sk->sk_protocol, |
1159 | .flags = inet_sk_flowi_flags(sk), | 1155 | .flags = inet_sk_flowi_flags(sk), |
1160 | .uli_u = { | 1156 | .fl_ip_sport = inet->inet_sport, |
1161 | .ports = { | 1157 | .fl_ip_dport = inet->inet_dport, |
1162 | .sport = inet->inet_sport, | ||
1163 | .dport = inet->inet_dport, | ||
1164 | }, | ||
1165 | }, | ||
1166 | }; | 1158 | }; |
1167 | 1159 | ||
1168 | security_sk_classify_flow(sk, &fl); | 1160 | security_sk_classify_flow(sk, &fl); |
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index d8e540c5b071..a2fc7b961dbc 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -433,8 +433,8 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) | |||
433 | 433 | ||
434 | static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) | 434 | static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) |
435 | { | 435 | { |
436 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip, | 436 | struct flowi fl = { .fl4_dst = sip, |
437 | .saddr = tip } } }; | 437 | .fl4_src = tip }; |
438 | struct rtable *rt; | 438 | struct rtable *rt; |
439 | int flag = 0; | 439 | int flag = 0; |
440 | /*unsigned long now; */ | 440 | /*unsigned long now; */ |
@@ -883,7 +883,7 @@ static int arp_process(struct sk_buff *skb) | |||
883 | 883 | ||
884 | dont_send = arp_ignore(in_dev, sip, tip); | 884 | dont_send = arp_ignore(in_dev, sip, tip); |
885 | if (!dont_send && IN_DEV_ARPFILTER(in_dev)) | 885 | if (!dont_send && IN_DEV_ARPFILTER(in_dev)) |
886 | dont_send |= arp_filter(sip, tip, dev); | 886 | dont_send = arp_filter(sip, tip, dev); |
887 | if (!dont_send) { | 887 | if (!dont_send) { |
888 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); | 888 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); |
889 | if (n) { | 889 | if (n) { |
@@ -1017,13 +1017,14 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) | |||
1017 | IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; | 1017 | IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; |
1018 | return 0; | 1018 | return 0; |
1019 | } | 1019 | } |
1020 | if (__in_dev_get_rtnl(dev)) { | 1020 | if (__in_dev_get_rcu(dev)) { |
1021 | IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on); | 1021 | IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on); |
1022 | return 0; | 1022 | return 0; |
1023 | } | 1023 | } |
1024 | return -ENXIO; | 1024 | return -ENXIO; |
1025 | } | 1025 | } |
1026 | 1026 | ||
1027 | /* must be called with rcu_read_lock() */ | ||
1027 | static int arp_req_set_public(struct net *net, struct arpreq *r, | 1028 | static int arp_req_set_public(struct net *net, struct arpreq *r, |
1028 | struct net_device *dev) | 1029 | struct net_device *dev) |
1029 | { | 1030 | { |
@@ -1033,7 +1034,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r, | |||
1033 | if (mask && mask != htonl(0xFFFFFFFF)) | 1034 | if (mask && mask != htonl(0xFFFFFFFF)) |
1034 | return -EINVAL; | 1035 | return -EINVAL; |
1035 | if (!dev && (r->arp_flags & ATF_COM)) { | 1036 | if (!dev && (r->arp_flags & ATF_COM)) { |
1036 | dev = dev_getbyhwaddr(net, r->arp_ha.sa_family, | 1037 | dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family, |
1037 | r->arp_ha.sa_data); | 1038 | r->arp_ha.sa_data); |
1038 | if (!dev) | 1039 | if (!dev) |
1039 | return -ENODEV; | 1040 | return -ENODEV; |
@@ -1061,8 +1062,8 @@ static int arp_req_set(struct net *net, struct arpreq *r, | |||
1061 | if (r->arp_flags & ATF_PERM) | 1062 | if (r->arp_flags & ATF_PERM) |
1062 | r->arp_flags |= ATF_COM; | 1063 | r->arp_flags |= ATF_COM; |
1063 | if (dev == NULL) { | 1064 | if (dev == NULL) { |
1064 | struct flowi fl = { .nl_u.ip4_u = { .daddr = ip, | 1065 | struct flowi fl = { .fl4_dst = ip, |
1065 | .tos = RTO_ONLINK } }; | 1066 | .fl4_tos = RTO_ONLINK }; |
1066 | struct rtable *rt; | 1067 | struct rtable *rt; |
1067 | err = ip_route_output_key(net, &rt, &fl); | 1068 | err = ip_route_output_key(net, &rt, &fl); |
1068 | if (err != 0) | 1069 | if (err != 0) |
@@ -1169,8 +1170,8 @@ static int arp_req_delete(struct net *net, struct arpreq *r, | |||
1169 | 1170 | ||
1170 | ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; | 1171 | ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; |
1171 | if (dev == NULL) { | 1172 | if (dev == NULL) { |
1172 | struct flowi fl = { .nl_u.ip4_u = { .daddr = ip, | 1173 | struct flowi fl = { .fl4_dst = ip, |
1173 | .tos = RTO_ONLINK } }; | 1174 | .fl4_tos = RTO_ONLINK }; |
1174 | struct rtable *rt; | 1175 | struct rtable *rt; |
1175 | err = ip_route_output_key(net, &rt, &fl); | 1176 | err = ip_route_output_key(net, &rt, &fl); |
1176 | if (err != 0) | 1177 | if (err != 0) |
@@ -1225,10 +1226,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1225 | if (!(r.arp_flags & ATF_NETMASK)) | 1226 | if (!(r.arp_flags & ATF_NETMASK)) |
1226 | ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = | 1227 | ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = |
1227 | htonl(0xFFFFFFFFUL); | 1228 | htonl(0xFFFFFFFFUL); |
1228 | rtnl_lock(); | 1229 | rcu_read_lock(); |
1229 | if (r.arp_dev[0]) { | 1230 | if (r.arp_dev[0]) { |
1230 | err = -ENODEV; | 1231 | err = -ENODEV; |
1231 | dev = __dev_get_by_name(net, r.arp_dev); | 1232 | dev = dev_get_by_name_rcu(net, r.arp_dev); |
1232 | if (dev == NULL) | 1233 | if (dev == NULL) |
1233 | goto out; | 1234 | goto out; |
1234 | 1235 | ||
@@ -1252,12 +1253,12 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1252 | break; | 1253 | break; |
1253 | case SIOCGARP: | 1254 | case SIOCGARP: |
1254 | err = arp_req_get(&r, dev); | 1255 | err = arp_req_get(&r, dev); |
1255 | if (!err && copy_to_user(arg, &r, sizeof(r))) | ||
1256 | err = -EFAULT; | ||
1257 | break; | 1256 | break; |
1258 | } | 1257 | } |
1259 | out: | 1258 | out: |
1260 | rtnl_unlock(); | 1259 | rcu_read_unlock(); |
1260 | if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r))) | ||
1261 | err = -EFAULT; | ||
1261 | return err; | 1262 | return err; |
1262 | } | 1263 | } |
1263 | 1264 | ||
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index dc94b0316b78..748cb5b337bd 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1256,6 +1256,87 @@ errout: | |||
1256 | rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); | 1256 | rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | static size_t inet_get_link_af_size(const struct net_device *dev) | ||
1260 | { | ||
1261 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
1262 | |||
1263 | if (!in_dev) | ||
1264 | return 0; | ||
1265 | |||
1266 | return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ | ||
1267 | } | ||
1268 | |||
1269 | static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||
1270 | { | ||
1271 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
1272 | struct nlattr *nla; | ||
1273 | int i; | ||
1274 | |||
1275 | if (!in_dev) | ||
1276 | return -ENODATA; | ||
1277 | |||
1278 | nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); | ||
1279 | if (nla == NULL) | ||
1280 | return -EMSGSIZE; | ||
1281 | |||
1282 | for (i = 0; i < IPV4_DEVCONF_MAX; i++) | ||
1283 | ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { | ||
1289 | [IFLA_INET_CONF] = { .type = NLA_NESTED }, | ||
1290 | }; | ||
1291 | |||
1292 | static int inet_validate_link_af(const struct net_device *dev, | ||
1293 | const struct nlattr *nla) | ||
1294 | { | ||
1295 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||
1296 | int err, rem; | ||
1297 | |||
1298 | if (dev && !__in_dev_get_rtnl(dev)) | ||
1299 | return -EAFNOSUPPORT; | ||
1300 | |||
1301 | err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy); | ||
1302 | if (err < 0) | ||
1303 | return err; | ||
1304 | |||
1305 | if (tb[IFLA_INET_CONF]) { | ||
1306 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { | ||
1307 | int cfgid = nla_type(a); | ||
1308 | |||
1309 | if (nla_len(a) < 4) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla) | ||
1321 | { | ||
1322 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
1323 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | ||
1324 | int rem; | ||
1325 | |||
1326 | if (!in_dev) | ||
1327 | return -EAFNOSUPPORT; | ||
1328 | |||
1329 | if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0) | ||
1330 | BUG(); | ||
1331 | |||
1332 | if (tb[IFLA_INET_CONF]) { | ||
1333 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) | ||
1334 | ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); | ||
1335 | } | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1259 | #ifdef CONFIG_SYSCTL | 1340 | #ifdef CONFIG_SYSCTL |
1260 | 1341 | ||
1261 | static void devinet_copy_dflt_conf(struct net *net, int i) | 1342 | static void devinet_copy_dflt_conf(struct net *net, int i) |
@@ -1349,9 +1430,9 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, | |||
1349 | return ret; | 1430 | return ret; |
1350 | } | 1431 | } |
1351 | 1432 | ||
1352 | int ipv4_doint_and_flush(ctl_table *ctl, int write, | 1433 | static int ipv4_doint_and_flush(ctl_table *ctl, int write, |
1353 | void __user *buffer, | 1434 | void __user *buffer, |
1354 | size_t *lenp, loff_t *ppos) | 1435 | size_t *lenp, loff_t *ppos) |
1355 | { | 1436 | { |
1356 | int *valp = ctl->data; | 1437 | int *valp = ctl->data; |
1357 | int val = *valp; | 1438 | int val = *valp; |
@@ -1619,6 +1700,14 @@ static __net_initdata struct pernet_operations devinet_ops = { | |||
1619 | .exit = devinet_exit_net, | 1700 | .exit = devinet_exit_net, |
1620 | }; | 1701 | }; |
1621 | 1702 | ||
1703 | static struct rtnl_af_ops inet_af_ops = { | ||
1704 | .family = AF_INET, | ||
1705 | .fill_link_af = inet_fill_link_af, | ||
1706 | .get_link_af_size = inet_get_link_af_size, | ||
1707 | .validate_link_af = inet_validate_link_af, | ||
1708 | .set_link_af = inet_set_link_af, | ||
1709 | }; | ||
1710 | |||
1622 | void __init devinet_init(void) | 1711 | void __init devinet_init(void) |
1623 | { | 1712 | { |
1624 | register_pernet_subsys(&devinet_ops); | 1713 | register_pernet_subsys(&devinet_ops); |
@@ -1626,6 +1715,8 @@ void __init devinet_init(void) | |||
1626 | register_gifconf(PF_INET, inet_gifconf); | 1715 | register_gifconf(PF_INET, inet_gifconf); |
1627 | register_netdevice_notifier(&ip_netdev_notifier); | 1716 | register_netdevice_notifier(&ip_netdev_notifier); |
1628 | 1717 | ||
1718 | rtnl_af_register(&inet_af_ops); | ||
1719 | |||
1629 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); | 1720 | rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL); |
1630 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); | 1721 | rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); |
1631 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); | 1722 | rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); |
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 14ca1f1c3fb0..e42a905180f0 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -23,6 +23,8 @@ struct esp_skb_cb { | |||
23 | 23 | ||
24 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) | 24 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) |
25 | 25 | ||
26 | static u32 esp4_get_mtu(struct xfrm_state *x, int mtu); | ||
27 | |||
26 | /* | 28 | /* |
27 | * Allocate an AEAD request structure with extra space for SG and IV. | 29 | * Allocate an AEAD request structure with extra space for SG and IV. |
28 | * | 30 | * |
@@ -117,25 +119,35 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
117 | int blksize; | 119 | int blksize; |
118 | int clen; | 120 | int clen; |
119 | int alen; | 121 | int alen; |
122 | int plen; | ||
123 | int tfclen; | ||
120 | int nfrags; | 124 | int nfrags; |
121 | 125 | ||
122 | /* skb is pure payload to encrypt */ | 126 | /* skb is pure payload to encrypt */ |
123 | 127 | ||
124 | err = -ENOMEM; | 128 | err = -ENOMEM; |
125 | 129 | ||
126 | /* Round to block size */ | ||
127 | clen = skb->len; | ||
128 | |||
129 | esp = x->data; | 130 | esp = x->data; |
130 | aead = esp->aead; | 131 | aead = esp->aead; |
131 | alen = crypto_aead_authsize(aead); | 132 | alen = crypto_aead_authsize(aead); |
132 | 133 | ||
134 | tfclen = 0; | ||
135 | if (x->tfcpad) { | ||
136 | struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); | ||
137 | u32 padto; | ||
138 | |||
139 | padto = min(x->tfcpad, esp4_get_mtu(x, dst->child_mtu_cached)); | ||
140 | if (skb->len < padto) | ||
141 | tfclen = padto - skb->len; | ||
142 | } | ||
133 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); | 143 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); |
134 | clen = ALIGN(clen + 2, blksize); | 144 | clen = ALIGN(skb->len + 2 + tfclen, blksize); |
135 | if (esp->padlen) | 145 | if (esp->padlen) |
136 | clen = ALIGN(clen, esp->padlen); | 146 | clen = ALIGN(clen, esp->padlen); |
147 | plen = clen - skb->len - tfclen; | ||
137 | 148 | ||
138 | if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0) | 149 | err = skb_cow_data(skb, tfclen + plen + alen, &trailer); |
150 | if (err < 0) | ||
139 | goto error; | 151 | goto error; |
140 | nfrags = err; | 152 | nfrags = err; |
141 | 153 | ||
@@ -150,13 +162,17 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
150 | 162 | ||
151 | /* Fill padding... */ | 163 | /* Fill padding... */ |
152 | tail = skb_tail_pointer(trailer); | 164 | tail = skb_tail_pointer(trailer); |
165 | if (tfclen) { | ||
166 | memset(tail, 0, tfclen); | ||
167 | tail += tfclen; | ||
168 | } | ||
153 | do { | 169 | do { |
154 | int i; | 170 | int i; |
155 | for (i=0; i<clen-skb->len - 2; i++) | 171 | for (i = 0; i < plen - 2; i++) |
156 | tail[i] = i + 1; | 172 | tail[i] = i + 1; |
157 | } while (0); | 173 | } while (0); |
158 | tail[clen - skb->len - 2] = (clen - skb->len) - 2; | 174 | tail[plen - 2] = plen - 2; |
159 | tail[clen - skb->len - 1] = *skb_mac_header(skb); | 175 | tail[plen - 1] = *skb_mac_header(skb); |
160 | pskb_put(skb, trailer, clen - skb->len + alen); | 176 | pskb_put(skb, trailer, clen - skb->len + alen); |
161 | 177 | ||
162 | skb_push(skb, -skb_network_offset(skb)); | 178 | skb_push(skb, -skb_network_offset(skb)); |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index c19c1f739fba..1d2cdd43a878 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -158,11 +158,7 @@ static void fib_flush(struct net *net) | |||
158 | struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) | 158 | struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) |
159 | { | 159 | { |
160 | struct flowi fl = { | 160 | struct flowi fl = { |
161 | .nl_u = { | 161 | .fl4_dst = addr, |
162 | .ip4_u = { | ||
163 | .daddr = addr | ||
164 | } | ||
165 | }, | ||
166 | }; | 162 | }; |
167 | struct fib_result res = { 0 }; | 163 | struct fib_result res = { 0 }; |
168 | struct net_device *dev = NULL; | 164 | struct net_device *dev = NULL; |
@@ -199,7 +195,7 @@ static inline unsigned __inet_dev_addr_type(struct net *net, | |||
199 | const struct net_device *dev, | 195 | const struct net_device *dev, |
200 | __be32 addr) | 196 | __be32 addr) |
201 | { | 197 | { |
202 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; | 198 | struct flowi fl = { .fl4_dst = addr }; |
203 | struct fib_result res; | 199 | struct fib_result res; |
204 | unsigned ret = RTN_BROADCAST; | 200 | unsigned ret = RTN_BROADCAST; |
205 | struct fib_table *local_table; | 201 | struct fib_table *local_table; |
@@ -253,13 +249,9 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
253 | { | 249 | { |
254 | struct in_device *in_dev; | 250 | struct in_device *in_dev; |
255 | struct flowi fl = { | 251 | struct flowi fl = { |
256 | .nl_u = { | 252 | .fl4_dst = src, |
257 | .ip4_u = { | 253 | .fl4_src = dst, |
258 | .daddr = src, | 254 | .fl4_tos = tos, |
259 | .saddr = dst, | ||
260 | .tos = tos | ||
261 | } | ||
262 | }, | ||
263 | .mark = mark, | 255 | .mark = mark, |
264 | .iif = oif | 256 | .iif = oif |
265 | }; | 257 | }; |
@@ -859,13 +851,9 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) | |||
859 | struct fib_result res; | 851 | struct fib_result res; |
860 | struct flowi fl = { | 852 | struct flowi fl = { |
861 | .mark = frn->fl_mark, | 853 | .mark = frn->fl_mark, |
862 | .nl_u = { | 854 | .fl4_dst = frn->fl_addr, |
863 | .ip4_u = { | 855 | .fl4_tos = frn->fl_tos, |
864 | .daddr = frn->fl_addr, | 856 | .fl4_scope = frn->fl_scope, |
865 | .tos = frn->fl_tos, | ||
866 | .scope = frn->fl_scope | ||
867 | } | ||
868 | } | ||
869 | }; | 857 | }; |
870 | 858 | ||
871 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 859 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
@@ -1005,7 +993,11 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
1005 | rt_cache_flush(dev_net(dev), 0); | 993 | rt_cache_flush(dev_net(dev), 0); |
1006 | break; | 994 | break; |
1007 | case NETDEV_UNREGISTER_BATCH: | 995 | case NETDEV_UNREGISTER_BATCH: |
1008 | rt_cache_flush_batch(); | 996 | /* The batch unregister is only called on the first |
997 | * device in the list of devices being unregistered. | ||
998 | * Therefore we should not pass dev_net(dev) in here. | ||
999 | */ | ||
1000 | rt_cache_flush_batch(NULL); | ||
1009 | break; | 1001 | break; |
1010 | } | 1002 | } |
1011 | return NOTIFY_DONE; | 1003 | return NOTIFY_DONE; |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 3e0da3ef6116..12d3dc3df1b7 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -563,12 +563,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, | |||
563 | rcu_read_lock(); | 563 | rcu_read_lock(); |
564 | { | 564 | { |
565 | struct flowi fl = { | 565 | struct flowi fl = { |
566 | .nl_u = { | 566 | .fl4_dst = nh->nh_gw, |
567 | .ip4_u = { | 567 | .fl4_scope = cfg->fc_scope + 1, |
568 | .daddr = nh->nh_gw, | ||
569 | .scope = cfg->fc_scope + 1, | ||
570 | }, | ||
571 | }, | ||
572 | .oif = nh->nh_oif, | 568 | .oif = nh->nh_oif, |
573 | }; | 569 | }; |
574 | 570 | ||
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index e5d1a44bcbdf..4aa1b7f01ea0 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -386,10 +386,9 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | |||
386 | daddr = icmp_param->replyopts.faddr; | 386 | daddr = icmp_param->replyopts.faddr; |
387 | } | 387 | } |
388 | { | 388 | { |
389 | struct flowi fl = { .nl_u = { .ip4_u = | 389 | struct flowi fl = { .fl4_dst= daddr, |
390 | { .daddr = daddr, | 390 | .fl4_src = rt->rt_spec_dst, |
391 | .saddr = rt->rt_spec_dst, | 391 | .fl4_tos = RT_TOS(ip_hdr(skb)->tos), |
392 | .tos = RT_TOS(ip_hdr(skb)->tos) } }, | ||
393 | .proto = IPPROTO_ICMP }; | 392 | .proto = IPPROTO_ICMP }; |
394 | security_skb_classify_flow(skb, &fl); | 393 | security_skb_classify_flow(skb, &fl); |
395 | if (ip_route_output_key(net, &rt, &fl)) | 394 | if (ip_route_output_key(net, &rt, &fl)) |
@@ -506,8 +505,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
506 | struct net_device *dev = NULL; | 505 | struct net_device *dev = NULL; |
507 | 506 | ||
508 | rcu_read_lock(); | 507 | rcu_read_lock(); |
509 | if (rt->fl.iif && | 508 | if (rt_is_input_route(rt) && |
510 | net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) | 509 | net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) |
511 | dev = dev_get_by_index_rcu(net, rt->fl.iif); | 510 | dev = dev_get_by_index_rcu(net, rt->fl.iif); |
512 | 511 | ||
513 | if (dev) | 512 | if (dev) |
@@ -542,22 +541,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
542 | 541 | ||
543 | { | 542 | { |
544 | struct flowi fl = { | 543 | struct flowi fl = { |
545 | .nl_u = { | 544 | .fl4_dst = icmp_param.replyopts.srr ? |
546 | .ip4_u = { | 545 | icmp_param.replyopts.faddr : iph->saddr, |
547 | .daddr = icmp_param.replyopts.srr ? | 546 | .fl4_src = saddr, |
548 | icmp_param.replyopts.faddr : | 547 | .fl4_tos = RT_TOS(tos), |
549 | iph->saddr, | ||
550 | .saddr = saddr, | ||
551 | .tos = RT_TOS(tos) | ||
552 | } | ||
553 | }, | ||
554 | .proto = IPPROTO_ICMP, | 548 | .proto = IPPROTO_ICMP, |
555 | .uli_u = { | 549 | .fl_icmp_type = type, |
556 | .icmpt = { | 550 | .fl_icmp_code = code, |
557 | .type = type, | ||
558 | .code = code | ||
559 | } | ||
560 | } | ||
561 | }; | 551 | }; |
562 | int err; | 552 | int err; |
563 | struct rtable *rt2; | 553 | struct rtable *rt2; |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 3c53c2d89e3b..e0e77e297de3 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -149,21 +149,37 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc); | |||
149 | static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | 149 | static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, |
150 | int sfcount, __be32 *psfsrc, int delta); | 150 | int sfcount, __be32 *psfsrc, int delta); |
151 | 151 | ||
152 | |||
153 | static void ip_mc_list_reclaim(struct rcu_head *head) | ||
154 | { | ||
155 | kfree(container_of(head, struct ip_mc_list, rcu)); | ||
156 | } | ||
157 | |||
152 | static void ip_ma_put(struct ip_mc_list *im) | 158 | static void ip_ma_put(struct ip_mc_list *im) |
153 | { | 159 | { |
154 | if (atomic_dec_and_test(&im->refcnt)) { | 160 | if (atomic_dec_and_test(&im->refcnt)) { |
155 | in_dev_put(im->interface); | 161 | in_dev_put(im->interface); |
156 | kfree(im); | 162 | call_rcu(&im->rcu, ip_mc_list_reclaim); |
157 | } | 163 | } |
158 | } | 164 | } |
159 | 165 | ||
166 | #define for_each_pmc_rcu(in_dev, pmc) \ | ||
167 | for (pmc = rcu_dereference(in_dev->mc_list); \ | ||
168 | pmc != NULL; \ | ||
169 | pmc = rcu_dereference(pmc->next_rcu)) | ||
170 | |||
171 | #define for_each_pmc_rtnl(in_dev, pmc) \ | ||
172 | for (pmc = rtnl_dereference(in_dev->mc_list); \ | ||
173 | pmc != NULL; \ | ||
174 | pmc = rtnl_dereference(pmc->next_rcu)) | ||
175 | |||
160 | #ifdef CONFIG_IP_MULTICAST | 176 | #ifdef CONFIG_IP_MULTICAST |
161 | 177 | ||
162 | /* | 178 | /* |
163 | * Timer management | 179 | * Timer management |
164 | */ | 180 | */ |
165 | 181 | ||
166 | static __inline__ void igmp_stop_timer(struct ip_mc_list *im) | 182 | static void igmp_stop_timer(struct ip_mc_list *im) |
167 | { | 183 | { |
168 | spin_lock_bh(&im->lock); | 184 | spin_lock_bh(&im->lock); |
169 | if (del_timer(&im->timer)) | 185 | if (del_timer(&im->timer)) |
@@ -284,6 +300,8 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted) | |||
284 | return scount; | 300 | return scount; |
285 | } | 301 | } |
286 | 302 | ||
303 | #define igmp_skb_size(skb) (*(unsigned int *)((skb)->cb)) | ||
304 | |||
287 | static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) | 305 | static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) |
288 | { | 306 | { |
289 | struct sk_buff *skb; | 307 | struct sk_buff *skb; |
@@ -292,14 +310,20 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) | |||
292 | struct igmpv3_report *pig; | 310 | struct igmpv3_report *pig; |
293 | struct net *net = dev_net(dev); | 311 | struct net *net = dev_net(dev); |
294 | 312 | ||
295 | skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC); | 313 | while (1) { |
296 | if (skb == NULL) | 314 | skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), |
297 | return NULL; | 315 | GFP_ATOMIC | __GFP_NOWARN); |
316 | if (skb) | ||
317 | break; | ||
318 | size >>= 1; | ||
319 | if (size < 256) | ||
320 | return NULL; | ||
321 | } | ||
322 | igmp_skb_size(skb) = size; | ||
298 | 323 | ||
299 | { | 324 | { |
300 | struct flowi fl = { .oif = dev->ifindex, | 325 | struct flowi fl = { .oif = dev->ifindex, |
301 | .nl_u = { .ip4_u = { | 326 | .fl4_dst = IGMPV3_ALL_MCR, |
302 | .daddr = IGMPV3_ALL_MCR } }, | ||
303 | .proto = IPPROTO_IGMP }; | 327 | .proto = IPPROTO_IGMP }; |
304 | if (ip_route_output_key(net, &rt, &fl)) { | 328 | if (ip_route_output_key(net, &rt, &fl)) { |
305 | kfree_skb(skb); | 329 | kfree_skb(skb); |
@@ -384,7 +408,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, | |||
384 | return skb; | 408 | return skb; |
385 | } | 409 | } |
386 | 410 | ||
387 | #define AVAILABLE(skb) ((skb) ? ((skb)->dev ? (skb)->dev->mtu - (skb)->len : \ | 411 | #define AVAILABLE(skb) ((skb) ? ((skb)->dev ? igmp_skb_size(skb) - (skb)->len : \ |
388 | skb_tailroom(skb)) : 0) | 412 | skb_tailroom(skb)) : 0) |
389 | 413 | ||
390 | static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, | 414 | static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, |
@@ -502,8 +526,8 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) | |||
502 | int type; | 526 | int type; |
503 | 527 | ||
504 | if (!pmc) { | 528 | if (!pmc) { |
505 | read_lock(&in_dev->mc_list_lock); | 529 | rcu_read_lock(); |
506 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 530 | for_each_pmc_rcu(in_dev, pmc) { |
507 | if (pmc->multiaddr == IGMP_ALL_HOSTS) | 531 | if (pmc->multiaddr == IGMP_ALL_HOSTS) |
508 | continue; | 532 | continue; |
509 | spin_lock_bh(&pmc->lock); | 533 | spin_lock_bh(&pmc->lock); |
@@ -514,7 +538,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) | |||
514 | skb = add_grec(skb, pmc, type, 0, 0); | 538 | skb = add_grec(skb, pmc, type, 0, 0); |
515 | spin_unlock_bh(&pmc->lock); | 539 | spin_unlock_bh(&pmc->lock); |
516 | } | 540 | } |
517 | read_unlock(&in_dev->mc_list_lock); | 541 | rcu_read_unlock(); |
518 | } else { | 542 | } else { |
519 | spin_lock_bh(&pmc->lock); | 543 | spin_lock_bh(&pmc->lock); |
520 | if (pmc->sfcount[MCAST_EXCLUDE]) | 544 | if (pmc->sfcount[MCAST_EXCLUDE]) |
@@ -556,7 +580,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
556 | struct sk_buff *skb = NULL; | 580 | struct sk_buff *skb = NULL; |
557 | int type, dtype; | 581 | int type, dtype; |
558 | 582 | ||
559 | read_lock(&in_dev->mc_list_lock); | 583 | rcu_read_lock(); |
560 | spin_lock_bh(&in_dev->mc_tomb_lock); | 584 | spin_lock_bh(&in_dev->mc_tomb_lock); |
561 | 585 | ||
562 | /* deleted MCA's */ | 586 | /* deleted MCA's */ |
@@ -593,7 +617,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
593 | spin_unlock_bh(&in_dev->mc_tomb_lock); | 617 | spin_unlock_bh(&in_dev->mc_tomb_lock); |
594 | 618 | ||
595 | /* change recs */ | 619 | /* change recs */ |
596 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 620 | for_each_pmc_rcu(in_dev, pmc) { |
597 | spin_lock_bh(&pmc->lock); | 621 | spin_lock_bh(&pmc->lock); |
598 | if (pmc->sfcount[MCAST_EXCLUDE]) { | 622 | if (pmc->sfcount[MCAST_EXCLUDE]) { |
599 | type = IGMPV3_BLOCK_OLD_SOURCES; | 623 | type = IGMPV3_BLOCK_OLD_SOURCES; |
@@ -616,7 +640,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) | |||
616 | } | 640 | } |
617 | spin_unlock_bh(&pmc->lock); | 641 | spin_unlock_bh(&pmc->lock); |
618 | } | 642 | } |
619 | read_unlock(&in_dev->mc_list_lock); | 643 | rcu_read_unlock(); |
620 | 644 | ||
621 | if (!skb) | 645 | if (!skb) |
622 | return; | 646 | return; |
@@ -644,7 +668,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | |||
644 | 668 | ||
645 | { | 669 | { |
646 | struct flowi fl = { .oif = dev->ifindex, | 670 | struct flowi fl = { .oif = dev->ifindex, |
647 | .nl_u = { .ip4_u = { .daddr = dst } }, | 671 | .fl4_dst = dst, |
648 | .proto = IPPROTO_IGMP }; | 672 | .proto = IPPROTO_IGMP }; |
649 | if (ip_route_output_key(net, &rt, &fl)) | 673 | if (ip_route_output_key(net, &rt, &fl)) |
650 | return -1; | 674 | return -1; |
@@ -813,14 +837,14 @@ static void igmp_heard_report(struct in_device *in_dev, __be32 group) | |||
813 | if (group == IGMP_ALL_HOSTS) | 837 | if (group == IGMP_ALL_HOSTS) |
814 | return; | 838 | return; |
815 | 839 | ||
816 | read_lock(&in_dev->mc_list_lock); | 840 | rcu_read_lock(); |
817 | for (im=in_dev->mc_list; im!=NULL; im=im->next) { | 841 | for_each_pmc_rcu(in_dev, im) { |
818 | if (im->multiaddr == group) { | 842 | if (im->multiaddr == group) { |
819 | igmp_stop_timer(im); | 843 | igmp_stop_timer(im); |
820 | break; | 844 | break; |
821 | } | 845 | } |
822 | } | 846 | } |
823 | read_unlock(&in_dev->mc_list_lock); | 847 | rcu_read_unlock(); |
824 | } | 848 | } |
825 | 849 | ||
826 | static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | 850 | static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, |
@@ -906,8 +930,8 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
906 | * - Use the igmp->igmp_code field as the maximum | 930 | * - Use the igmp->igmp_code field as the maximum |
907 | * delay possible | 931 | * delay possible |
908 | */ | 932 | */ |
909 | read_lock(&in_dev->mc_list_lock); | 933 | rcu_read_lock(); |
910 | for (im=in_dev->mc_list; im!=NULL; im=im->next) { | 934 | for_each_pmc_rcu(in_dev, im) { |
911 | int changed; | 935 | int changed; |
912 | 936 | ||
913 | if (group && group != im->multiaddr) | 937 | if (group && group != im->multiaddr) |
@@ -925,7 +949,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
925 | if (changed) | 949 | if (changed) |
926 | igmp_mod_timer(im, max_delay); | 950 | igmp_mod_timer(im, max_delay); |
927 | } | 951 | } |
928 | read_unlock(&in_dev->mc_list_lock); | 952 | rcu_read_unlock(); |
929 | } | 953 | } |
930 | 954 | ||
931 | /* called in rcu_read_lock() section */ | 955 | /* called in rcu_read_lock() section */ |
@@ -961,7 +985,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
961 | case IGMP_HOST_MEMBERSHIP_REPORT: | 985 | case IGMP_HOST_MEMBERSHIP_REPORT: |
962 | case IGMPV2_HOST_MEMBERSHIP_REPORT: | 986 | case IGMPV2_HOST_MEMBERSHIP_REPORT: |
963 | /* Is it our report looped back? */ | 987 | /* Is it our report looped back? */ |
964 | if (skb_rtable(skb)->fl.iif == 0) | 988 | if (rt_is_output_route(skb_rtable(skb))) |
965 | break; | 989 | break; |
966 | /* don't rely on MC router hearing unicast reports */ | 990 | /* don't rely on MC router hearing unicast reports */ |
967 | if (skb->pkt_type == PACKET_MULTICAST || | 991 | if (skb->pkt_type == PACKET_MULTICAST || |
@@ -1110,8 +1134,8 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) | |||
1110 | kfree(pmc); | 1134 | kfree(pmc); |
1111 | } | 1135 | } |
1112 | /* clear dead sources, too */ | 1136 | /* clear dead sources, too */ |
1113 | read_lock(&in_dev->mc_list_lock); | 1137 | rcu_read_lock(); |
1114 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 1138 | for_each_pmc_rcu(in_dev, pmc) { |
1115 | struct ip_sf_list *psf, *psf_next; | 1139 | struct ip_sf_list *psf, *psf_next; |
1116 | 1140 | ||
1117 | spin_lock_bh(&pmc->lock); | 1141 | spin_lock_bh(&pmc->lock); |
@@ -1123,7 +1147,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) | |||
1123 | kfree(psf); | 1147 | kfree(psf); |
1124 | } | 1148 | } |
1125 | } | 1149 | } |
1126 | read_unlock(&in_dev->mc_list_lock); | 1150 | rcu_read_unlock(); |
1127 | } | 1151 | } |
1128 | #endif | 1152 | #endif |
1129 | 1153 | ||
@@ -1209,7 +1233,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
1209 | 1233 | ||
1210 | ASSERT_RTNL(); | 1234 | ASSERT_RTNL(); |
1211 | 1235 | ||
1212 | for (im=in_dev->mc_list; im; im=im->next) { | 1236 | for_each_pmc_rtnl(in_dev, im) { |
1213 | if (im->multiaddr == addr) { | 1237 | if (im->multiaddr == addr) { |
1214 | im->users++; | 1238 | im->users++; |
1215 | ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0); | 1239 | ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0); |
@@ -1217,7 +1241,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
1217 | } | 1241 | } |
1218 | } | 1242 | } |
1219 | 1243 | ||
1220 | im = kmalloc(sizeof(*im), GFP_KERNEL); | 1244 | im = kzalloc(sizeof(*im), GFP_KERNEL); |
1221 | if (!im) | 1245 | if (!im) |
1222 | goto out; | 1246 | goto out; |
1223 | 1247 | ||
@@ -1227,26 +1251,18 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
1227 | im->multiaddr = addr; | 1251 | im->multiaddr = addr; |
1228 | /* initial mode is (EX, empty) */ | 1252 | /* initial mode is (EX, empty) */ |
1229 | im->sfmode = MCAST_EXCLUDE; | 1253 | im->sfmode = MCAST_EXCLUDE; |
1230 | im->sfcount[MCAST_INCLUDE] = 0; | ||
1231 | im->sfcount[MCAST_EXCLUDE] = 1; | 1254 | im->sfcount[MCAST_EXCLUDE] = 1; |
1232 | im->sources = NULL; | ||
1233 | im->tomb = NULL; | ||
1234 | im->crcount = 0; | ||
1235 | atomic_set(&im->refcnt, 1); | 1255 | atomic_set(&im->refcnt, 1); |
1236 | spin_lock_init(&im->lock); | 1256 | spin_lock_init(&im->lock); |
1237 | #ifdef CONFIG_IP_MULTICAST | 1257 | #ifdef CONFIG_IP_MULTICAST |
1238 | im->tm_running = 0; | ||
1239 | setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); | 1258 | setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); |
1240 | im->unsolicit_count = IGMP_Unsolicited_Report_Count; | 1259 | im->unsolicit_count = IGMP_Unsolicited_Report_Count; |
1241 | im->reporter = 0; | ||
1242 | im->gsquery = 0; | ||
1243 | #endif | 1260 | #endif |
1244 | im->loaded = 0; | 1261 | |
1245 | write_lock_bh(&in_dev->mc_list_lock); | 1262 | im->next_rcu = in_dev->mc_list; |
1246 | im->next = in_dev->mc_list; | ||
1247 | in_dev->mc_list = im; | ||
1248 | in_dev->mc_count++; | 1263 | in_dev->mc_count++; |
1249 | write_unlock_bh(&in_dev->mc_list_lock); | 1264 | rcu_assign_pointer(in_dev->mc_list, im); |
1265 | |||
1250 | #ifdef CONFIG_IP_MULTICAST | 1266 | #ifdef CONFIG_IP_MULTICAST |
1251 | igmpv3_del_delrec(in_dev, im->multiaddr); | 1267 | igmpv3_del_delrec(in_dev, im->multiaddr); |
1252 | #endif | 1268 | #endif |
@@ -1260,26 +1276,32 @@ EXPORT_SYMBOL(ip_mc_inc_group); | |||
1260 | 1276 | ||
1261 | /* | 1277 | /* |
1262 | * Resend IGMP JOIN report; used for bonding. | 1278 | * Resend IGMP JOIN report; used for bonding. |
1279 | * Called with rcu_read_lock() | ||
1263 | */ | 1280 | */ |
1264 | void ip_mc_rejoin_group(struct ip_mc_list *im) | 1281 | void ip_mc_rejoin_groups(struct in_device *in_dev) |
1265 | { | 1282 | { |
1266 | #ifdef CONFIG_IP_MULTICAST | 1283 | #ifdef CONFIG_IP_MULTICAST |
1267 | struct in_device *in_dev = im->interface; | 1284 | struct ip_mc_list *im; |
1285 | int type; | ||
1268 | 1286 | ||
1269 | if (im->multiaddr == IGMP_ALL_HOSTS) | 1287 | for_each_pmc_rcu(in_dev, im) { |
1270 | return; | 1288 | if (im->multiaddr == IGMP_ALL_HOSTS) |
1289 | continue; | ||
1271 | 1290 | ||
1272 | /* a failover is happening and switches | 1291 | /* a failover is happening and switches |
1273 | * must be notified immediately */ | 1292 | * must be notified immediately |
1274 | if (IGMP_V1_SEEN(in_dev)) | 1293 | */ |
1275 | igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT); | 1294 | if (IGMP_V1_SEEN(in_dev)) |
1276 | else if (IGMP_V2_SEEN(in_dev)) | 1295 | type = IGMP_HOST_MEMBERSHIP_REPORT; |
1277 | igmp_send_report(in_dev, im, IGMPV2_HOST_MEMBERSHIP_REPORT); | 1296 | else if (IGMP_V2_SEEN(in_dev)) |
1278 | else | 1297 | type = IGMPV2_HOST_MEMBERSHIP_REPORT; |
1279 | igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT); | 1298 | else |
1299 | type = IGMPV3_HOST_MEMBERSHIP_REPORT; | ||
1300 | igmp_send_report(in_dev, im, type); | ||
1301 | } | ||
1280 | #endif | 1302 | #endif |
1281 | } | 1303 | } |
1282 | EXPORT_SYMBOL(ip_mc_rejoin_group); | 1304 | EXPORT_SYMBOL(ip_mc_rejoin_groups); |
1283 | 1305 | ||
1284 | /* | 1306 | /* |
1285 | * A socket has left a multicast group on device dev | 1307 | * A socket has left a multicast group on device dev |
@@ -1287,17 +1309,18 @@ EXPORT_SYMBOL(ip_mc_rejoin_group); | |||
1287 | 1309 | ||
1288 | void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) | 1310 | void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) |
1289 | { | 1311 | { |
1290 | struct ip_mc_list *i, **ip; | 1312 | struct ip_mc_list *i; |
1313 | struct ip_mc_list __rcu **ip; | ||
1291 | 1314 | ||
1292 | ASSERT_RTNL(); | 1315 | ASSERT_RTNL(); |
1293 | 1316 | ||
1294 | for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { | 1317 | for (ip = &in_dev->mc_list; |
1318 | (i = rtnl_dereference(*ip)) != NULL; | ||
1319 | ip = &i->next_rcu) { | ||
1295 | if (i->multiaddr == addr) { | 1320 | if (i->multiaddr == addr) { |
1296 | if (--i->users == 0) { | 1321 | if (--i->users == 0) { |
1297 | write_lock_bh(&in_dev->mc_list_lock); | 1322 | *ip = i->next_rcu; |
1298 | *ip = i->next; | ||
1299 | in_dev->mc_count--; | 1323 | in_dev->mc_count--; |
1300 | write_unlock_bh(&in_dev->mc_list_lock); | ||
1301 | igmp_group_dropped(i); | 1324 | igmp_group_dropped(i); |
1302 | 1325 | ||
1303 | if (!in_dev->dead) | 1326 | if (!in_dev->dead) |
@@ -1316,34 +1339,34 @@ EXPORT_SYMBOL(ip_mc_dec_group); | |||
1316 | 1339 | ||
1317 | void ip_mc_unmap(struct in_device *in_dev) | 1340 | void ip_mc_unmap(struct in_device *in_dev) |
1318 | { | 1341 | { |
1319 | struct ip_mc_list *i; | 1342 | struct ip_mc_list *pmc; |
1320 | 1343 | ||
1321 | ASSERT_RTNL(); | 1344 | ASSERT_RTNL(); |
1322 | 1345 | ||
1323 | for (i = in_dev->mc_list; i; i = i->next) | 1346 | for_each_pmc_rtnl(in_dev, pmc) |
1324 | igmp_group_dropped(i); | 1347 | igmp_group_dropped(pmc); |
1325 | } | 1348 | } |
1326 | 1349 | ||
1327 | void ip_mc_remap(struct in_device *in_dev) | 1350 | void ip_mc_remap(struct in_device *in_dev) |
1328 | { | 1351 | { |
1329 | struct ip_mc_list *i; | 1352 | struct ip_mc_list *pmc; |
1330 | 1353 | ||
1331 | ASSERT_RTNL(); | 1354 | ASSERT_RTNL(); |
1332 | 1355 | ||
1333 | for (i = in_dev->mc_list; i; i = i->next) | 1356 | for_each_pmc_rtnl(in_dev, pmc) |
1334 | igmp_group_added(i); | 1357 | igmp_group_added(pmc); |
1335 | } | 1358 | } |
1336 | 1359 | ||
1337 | /* Device going down */ | 1360 | /* Device going down */ |
1338 | 1361 | ||
1339 | void ip_mc_down(struct in_device *in_dev) | 1362 | void ip_mc_down(struct in_device *in_dev) |
1340 | { | 1363 | { |
1341 | struct ip_mc_list *i; | 1364 | struct ip_mc_list *pmc; |
1342 | 1365 | ||
1343 | ASSERT_RTNL(); | 1366 | ASSERT_RTNL(); |
1344 | 1367 | ||
1345 | for (i=in_dev->mc_list; i; i=i->next) | 1368 | for_each_pmc_rtnl(in_dev, pmc) |
1346 | igmp_group_dropped(i); | 1369 | igmp_group_dropped(pmc); |
1347 | 1370 | ||
1348 | #ifdef CONFIG_IP_MULTICAST | 1371 | #ifdef CONFIG_IP_MULTICAST |
1349 | in_dev->mr_ifc_count = 0; | 1372 | in_dev->mr_ifc_count = 0; |
@@ -1374,7 +1397,6 @@ void ip_mc_init_dev(struct in_device *in_dev) | |||
1374 | in_dev->mr_qrv = IGMP_Unsolicited_Report_Count; | 1397 | in_dev->mr_qrv = IGMP_Unsolicited_Report_Count; |
1375 | #endif | 1398 | #endif |
1376 | 1399 | ||
1377 | rwlock_init(&in_dev->mc_list_lock); | ||
1378 | spin_lock_init(&in_dev->mc_tomb_lock); | 1400 | spin_lock_init(&in_dev->mc_tomb_lock); |
1379 | } | 1401 | } |
1380 | 1402 | ||
@@ -1382,14 +1404,14 @@ void ip_mc_init_dev(struct in_device *in_dev) | |||
1382 | 1404 | ||
1383 | void ip_mc_up(struct in_device *in_dev) | 1405 | void ip_mc_up(struct in_device *in_dev) |
1384 | { | 1406 | { |
1385 | struct ip_mc_list *i; | 1407 | struct ip_mc_list *pmc; |
1386 | 1408 | ||
1387 | ASSERT_RTNL(); | 1409 | ASSERT_RTNL(); |
1388 | 1410 | ||
1389 | ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); | 1411 | ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); |
1390 | 1412 | ||
1391 | for (i=in_dev->mc_list; i; i=i->next) | 1413 | for_each_pmc_rtnl(in_dev, pmc) |
1392 | igmp_group_added(i); | 1414 | igmp_group_added(pmc); |
1393 | } | 1415 | } |
1394 | 1416 | ||
1395 | /* | 1417 | /* |
@@ -1405,24 +1427,19 @@ void ip_mc_destroy_dev(struct in_device *in_dev) | |||
1405 | /* Deactivate timers */ | 1427 | /* Deactivate timers */ |
1406 | ip_mc_down(in_dev); | 1428 | ip_mc_down(in_dev); |
1407 | 1429 | ||
1408 | write_lock_bh(&in_dev->mc_list_lock); | 1430 | while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) { |
1409 | while ((i = in_dev->mc_list) != NULL) { | 1431 | in_dev->mc_list = i->next_rcu; |
1410 | in_dev->mc_list = i->next; | ||
1411 | in_dev->mc_count--; | 1432 | in_dev->mc_count--; |
1412 | write_unlock_bh(&in_dev->mc_list_lock); | 1433 | |
1413 | igmp_group_dropped(i); | 1434 | igmp_group_dropped(i); |
1414 | ip_ma_put(i); | 1435 | ip_ma_put(i); |
1415 | |||
1416 | write_lock_bh(&in_dev->mc_list_lock); | ||
1417 | } | 1436 | } |
1418 | write_unlock_bh(&in_dev->mc_list_lock); | ||
1419 | } | 1437 | } |
1420 | 1438 | ||
1421 | /* RTNL is locked */ | 1439 | /* RTNL is locked */ |
1422 | static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) | 1440 | static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) |
1423 | { | 1441 | { |
1424 | struct flowi fl = { .nl_u = { .ip4_u = | 1442 | struct flowi fl = { .fl4_dst = imr->imr_multiaddr.s_addr }; |
1425 | { .daddr = imr->imr_multiaddr.s_addr } } }; | ||
1426 | struct rtable *rt; | 1443 | struct rtable *rt; |
1427 | struct net_device *dev = NULL; | 1444 | struct net_device *dev = NULL; |
1428 | struct in_device *idev = NULL; | 1445 | struct in_device *idev = NULL; |
@@ -1513,18 +1530,18 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
1513 | 1530 | ||
1514 | if (!in_dev) | 1531 | if (!in_dev) |
1515 | return -ENODEV; | 1532 | return -ENODEV; |
1516 | read_lock(&in_dev->mc_list_lock); | 1533 | rcu_read_lock(); |
1517 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 1534 | for_each_pmc_rcu(in_dev, pmc) { |
1518 | if (*pmca == pmc->multiaddr) | 1535 | if (*pmca == pmc->multiaddr) |
1519 | break; | 1536 | break; |
1520 | } | 1537 | } |
1521 | if (!pmc) { | 1538 | if (!pmc) { |
1522 | /* MCA not found?? bug */ | 1539 | /* MCA not found?? bug */ |
1523 | read_unlock(&in_dev->mc_list_lock); | 1540 | rcu_read_unlock(); |
1524 | return -ESRCH; | 1541 | return -ESRCH; |
1525 | } | 1542 | } |
1526 | spin_lock_bh(&pmc->lock); | 1543 | spin_lock_bh(&pmc->lock); |
1527 | read_unlock(&in_dev->mc_list_lock); | 1544 | rcu_read_unlock(); |
1528 | #ifdef CONFIG_IP_MULTICAST | 1545 | #ifdef CONFIG_IP_MULTICAST |
1529 | sf_markstate(pmc); | 1546 | sf_markstate(pmc); |
1530 | #endif | 1547 | #endif |
@@ -1685,18 +1702,18 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
1685 | 1702 | ||
1686 | if (!in_dev) | 1703 | if (!in_dev) |
1687 | return -ENODEV; | 1704 | return -ENODEV; |
1688 | read_lock(&in_dev->mc_list_lock); | 1705 | rcu_read_lock(); |
1689 | for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { | 1706 | for_each_pmc_rcu(in_dev, pmc) { |
1690 | if (*pmca == pmc->multiaddr) | 1707 | if (*pmca == pmc->multiaddr) |
1691 | break; | 1708 | break; |
1692 | } | 1709 | } |
1693 | if (!pmc) { | 1710 | if (!pmc) { |
1694 | /* MCA not found?? bug */ | 1711 | /* MCA not found?? bug */ |
1695 | read_unlock(&in_dev->mc_list_lock); | 1712 | rcu_read_unlock(); |
1696 | return -ESRCH; | 1713 | return -ESRCH; |
1697 | } | 1714 | } |
1698 | spin_lock_bh(&pmc->lock); | 1715 | spin_lock_bh(&pmc->lock); |
1699 | read_unlock(&in_dev->mc_list_lock); | 1716 | rcu_read_unlock(); |
1700 | 1717 | ||
1701 | #ifdef CONFIG_IP_MULTICAST | 1718 | #ifdef CONFIG_IP_MULTICAST |
1702 | sf_markstate(pmc); | 1719 | sf_markstate(pmc); |
@@ -1793,7 +1810,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
1793 | 1810 | ||
1794 | err = -EADDRINUSE; | 1811 | err = -EADDRINUSE; |
1795 | ifindex = imr->imr_ifindex; | 1812 | ifindex = imr->imr_ifindex; |
1796 | for (i = inet->mc_list; i; i = i->next) { | 1813 | for_each_pmc_rtnl(inet, i) { |
1797 | if (i->multi.imr_multiaddr.s_addr == addr && | 1814 | if (i->multi.imr_multiaddr.s_addr == addr && |
1798 | i->multi.imr_ifindex == ifindex) | 1815 | i->multi.imr_ifindex == ifindex) |
1799 | goto done; | 1816 | goto done; |
@@ -1807,7 +1824,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
1807 | goto done; | 1824 | goto done; |
1808 | 1825 | ||
1809 | memcpy(&iml->multi, imr, sizeof(*imr)); | 1826 | memcpy(&iml->multi, imr, sizeof(*imr)); |
1810 | iml->next = inet->mc_list; | 1827 | iml->next_rcu = inet->mc_list; |
1811 | iml->sflist = NULL; | 1828 | iml->sflist = NULL; |
1812 | iml->sfmode = MCAST_EXCLUDE; | 1829 | iml->sfmode = MCAST_EXCLUDE; |
1813 | rcu_assign_pointer(inet->mc_list, iml); | 1830 | rcu_assign_pointer(inet->mc_list, iml); |
@@ -1821,17 +1838,14 @@ EXPORT_SYMBOL(ip_mc_join_group); | |||
1821 | 1838 | ||
1822 | static void ip_sf_socklist_reclaim(struct rcu_head *rp) | 1839 | static void ip_sf_socklist_reclaim(struct rcu_head *rp) |
1823 | { | 1840 | { |
1824 | struct ip_sf_socklist *psf; | 1841 | kfree(container_of(rp, struct ip_sf_socklist, rcu)); |
1825 | |||
1826 | psf = container_of(rp, struct ip_sf_socklist, rcu); | ||
1827 | /* sk_omem_alloc should have been decreased by the caller*/ | 1842 | /* sk_omem_alloc should have been decreased by the caller*/ |
1828 | kfree(psf); | ||
1829 | } | 1843 | } |
1830 | 1844 | ||
1831 | static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | 1845 | static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, |
1832 | struct in_device *in_dev) | 1846 | struct in_device *in_dev) |
1833 | { | 1847 | { |
1834 | struct ip_sf_socklist *psf = iml->sflist; | 1848 | struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist); |
1835 | int err; | 1849 | int err; |
1836 | 1850 | ||
1837 | if (psf == NULL) { | 1851 | if (psf == NULL) { |
@@ -1851,11 +1865,8 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | |||
1851 | 1865 | ||
1852 | static void ip_mc_socklist_reclaim(struct rcu_head *rp) | 1866 | static void ip_mc_socklist_reclaim(struct rcu_head *rp) |
1853 | { | 1867 | { |
1854 | struct ip_mc_socklist *iml; | 1868 | kfree(container_of(rp, struct ip_mc_socklist, rcu)); |
1855 | |||
1856 | iml = container_of(rp, struct ip_mc_socklist, rcu); | ||
1857 | /* sk_omem_alloc should have been decreased by the caller*/ | 1869 | /* sk_omem_alloc should have been decreased by the caller*/ |
1858 | kfree(iml); | ||
1859 | } | 1870 | } |
1860 | 1871 | ||
1861 | 1872 | ||
@@ -1866,7 +1877,8 @@ static void ip_mc_socklist_reclaim(struct rcu_head *rp) | |||
1866 | int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | 1877 | int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) |
1867 | { | 1878 | { |
1868 | struct inet_sock *inet = inet_sk(sk); | 1879 | struct inet_sock *inet = inet_sk(sk); |
1869 | struct ip_mc_socklist *iml, **imlp; | 1880 | struct ip_mc_socklist *iml; |
1881 | struct ip_mc_socklist __rcu **imlp; | ||
1870 | struct in_device *in_dev; | 1882 | struct in_device *in_dev; |
1871 | struct net *net = sock_net(sk); | 1883 | struct net *net = sock_net(sk); |
1872 | __be32 group = imr->imr_multiaddr.s_addr; | 1884 | __be32 group = imr->imr_multiaddr.s_addr; |
@@ -1876,7 +1888,9 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
1876 | rtnl_lock(); | 1888 | rtnl_lock(); |
1877 | in_dev = ip_mc_find_dev(net, imr); | 1889 | in_dev = ip_mc_find_dev(net, imr); |
1878 | ifindex = imr->imr_ifindex; | 1890 | ifindex = imr->imr_ifindex; |
1879 | for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) { | 1891 | for (imlp = &inet->mc_list; |
1892 | (iml = rtnl_dereference(*imlp)) != NULL; | ||
1893 | imlp = &iml->next_rcu) { | ||
1880 | if (iml->multi.imr_multiaddr.s_addr != group) | 1894 | if (iml->multi.imr_multiaddr.s_addr != group) |
1881 | continue; | 1895 | continue; |
1882 | if (ifindex) { | 1896 | if (ifindex) { |
@@ -1888,7 +1902,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
1888 | 1902 | ||
1889 | (void) ip_mc_leave_src(sk, iml, in_dev); | 1903 | (void) ip_mc_leave_src(sk, iml, in_dev); |
1890 | 1904 | ||
1891 | rcu_assign_pointer(*imlp, iml->next); | 1905 | *imlp = iml->next_rcu; |
1892 | 1906 | ||
1893 | if (in_dev) | 1907 | if (in_dev) |
1894 | ip_mc_dec_group(in_dev, group); | 1908 | ip_mc_dec_group(in_dev, group); |
@@ -1934,7 +1948,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
1934 | } | 1948 | } |
1935 | err = -EADDRNOTAVAIL; | 1949 | err = -EADDRNOTAVAIL; |
1936 | 1950 | ||
1937 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 1951 | for_each_pmc_rtnl(inet, pmc) { |
1938 | if ((pmc->multi.imr_multiaddr.s_addr == | 1952 | if ((pmc->multi.imr_multiaddr.s_addr == |
1939 | imr.imr_multiaddr.s_addr) && | 1953 | imr.imr_multiaddr.s_addr) && |
1940 | (pmc->multi.imr_ifindex == imr.imr_ifindex)) | 1954 | (pmc->multi.imr_ifindex == imr.imr_ifindex)) |
@@ -1958,7 +1972,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
1958 | pmc->sfmode = omode; | 1972 | pmc->sfmode = omode; |
1959 | } | 1973 | } |
1960 | 1974 | ||
1961 | psl = pmc->sflist; | 1975 | psl = rtnl_dereference(pmc->sflist); |
1962 | if (!add) { | 1976 | if (!add) { |
1963 | if (!psl) | 1977 | if (!psl) |
1964 | goto done; /* err = -EADDRNOTAVAIL */ | 1978 | goto done; /* err = -EADDRNOTAVAIL */ |
@@ -2077,7 +2091,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
2077 | goto done; | 2091 | goto done; |
2078 | } | 2092 | } |
2079 | 2093 | ||
2080 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2094 | for_each_pmc_rtnl(inet, pmc) { |
2081 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && | 2095 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && |
2082 | pmc->multi.imr_ifindex == imr.imr_ifindex) | 2096 | pmc->multi.imr_ifindex == imr.imr_ifindex) |
2083 | break; | 2097 | break; |
@@ -2107,7 +2121,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
2107 | (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr, | 2121 | (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr, |
2108 | msf->imsf_fmode, 0, NULL, 0); | 2122 | msf->imsf_fmode, 0, NULL, 0); |
2109 | } | 2123 | } |
2110 | psl = pmc->sflist; | 2124 | psl = rtnl_dereference(pmc->sflist); |
2111 | if (psl) { | 2125 | if (psl) { |
2112 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, | 2126 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, |
2113 | psl->sl_count, psl->sl_addr, 0); | 2127 | psl->sl_count, psl->sl_addr, 0); |
@@ -2155,7 +2169,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2155 | } | 2169 | } |
2156 | err = -EADDRNOTAVAIL; | 2170 | err = -EADDRNOTAVAIL; |
2157 | 2171 | ||
2158 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2172 | for_each_pmc_rtnl(inet, pmc) { |
2159 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && | 2173 | if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && |
2160 | pmc->multi.imr_ifindex == imr.imr_ifindex) | 2174 | pmc->multi.imr_ifindex == imr.imr_ifindex) |
2161 | break; | 2175 | break; |
@@ -2163,7 +2177,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2163 | if (!pmc) /* must have a prior join */ | 2177 | if (!pmc) /* must have a prior join */ |
2164 | goto done; | 2178 | goto done; |
2165 | msf->imsf_fmode = pmc->sfmode; | 2179 | msf->imsf_fmode = pmc->sfmode; |
2166 | psl = pmc->sflist; | 2180 | psl = rtnl_dereference(pmc->sflist); |
2167 | rtnl_unlock(); | 2181 | rtnl_unlock(); |
2168 | if (!psl) { | 2182 | if (!psl) { |
2169 | len = 0; | 2183 | len = 0; |
@@ -2208,7 +2222,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2208 | 2222 | ||
2209 | err = -EADDRNOTAVAIL; | 2223 | err = -EADDRNOTAVAIL; |
2210 | 2224 | ||
2211 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2225 | for_each_pmc_rtnl(inet, pmc) { |
2212 | if (pmc->multi.imr_multiaddr.s_addr == addr && | 2226 | if (pmc->multi.imr_multiaddr.s_addr == addr && |
2213 | pmc->multi.imr_ifindex == gsf->gf_interface) | 2227 | pmc->multi.imr_ifindex == gsf->gf_interface) |
2214 | break; | 2228 | break; |
@@ -2216,7 +2230,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2216 | if (!pmc) /* must have a prior join */ | 2230 | if (!pmc) /* must have a prior join */ |
2217 | goto done; | 2231 | goto done; |
2218 | gsf->gf_fmode = pmc->sfmode; | 2232 | gsf->gf_fmode = pmc->sfmode; |
2219 | psl = pmc->sflist; | 2233 | psl = rtnl_dereference(pmc->sflist); |
2220 | rtnl_unlock(); | 2234 | rtnl_unlock(); |
2221 | count = psl ? psl->sl_count : 0; | 2235 | count = psl ? psl->sl_count : 0; |
2222 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; | 2236 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; |
@@ -2257,7 +2271,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
2257 | goto out; | 2271 | goto out; |
2258 | 2272 | ||
2259 | rcu_read_lock(); | 2273 | rcu_read_lock(); |
2260 | for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) { | 2274 | for_each_pmc_rcu(inet, pmc) { |
2261 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && | 2275 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && |
2262 | pmc->multi.imr_ifindex == dif) | 2276 | pmc->multi.imr_ifindex == dif) |
2263 | break; | 2277 | break; |
@@ -2265,7 +2279,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
2265 | ret = inet->mc_all; | 2279 | ret = inet->mc_all; |
2266 | if (!pmc) | 2280 | if (!pmc) |
2267 | goto unlock; | 2281 | goto unlock; |
2268 | psl = pmc->sflist; | 2282 | psl = rcu_dereference(pmc->sflist); |
2269 | ret = (pmc->sfmode == MCAST_EXCLUDE); | 2283 | ret = (pmc->sfmode == MCAST_EXCLUDE); |
2270 | if (!psl) | 2284 | if (!psl) |
2271 | goto unlock; | 2285 | goto unlock; |
@@ -2300,10 +2314,10 @@ void ip_mc_drop_socket(struct sock *sk) | |||
2300 | return; | 2314 | return; |
2301 | 2315 | ||
2302 | rtnl_lock(); | 2316 | rtnl_lock(); |
2303 | while ((iml = inet->mc_list) != NULL) { | 2317 | while ((iml = rtnl_dereference(inet->mc_list)) != NULL) { |
2304 | struct in_device *in_dev; | 2318 | struct in_device *in_dev; |
2305 | rcu_assign_pointer(inet->mc_list, iml->next); | ||
2306 | 2319 | ||
2320 | inet->mc_list = iml->next_rcu; | ||
2307 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); | 2321 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); |
2308 | (void) ip_mc_leave_src(sk, iml, in_dev); | 2322 | (void) ip_mc_leave_src(sk, iml, in_dev); |
2309 | if (in_dev != NULL) | 2323 | if (in_dev != NULL) |
@@ -2321,8 +2335,8 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p | |||
2321 | struct ip_sf_list *psf; | 2335 | struct ip_sf_list *psf; |
2322 | int rv = 0; | 2336 | int rv = 0; |
2323 | 2337 | ||
2324 | read_lock(&in_dev->mc_list_lock); | 2338 | rcu_read_lock(); |
2325 | for (im=in_dev->mc_list; im; im=im->next) { | 2339 | for_each_pmc_rcu(in_dev, im) { |
2326 | if (im->multiaddr == mc_addr) | 2340 | if (im->multiaddr == mc_addr) |
2327 | break; | 2341 | break; |
2328 | } | 2342 | } |
@@ -2343,7 +2357,7 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p | |||
2343 | } else | 2357 | } else |
2344 | rv = 1; /* unspecified source; tentatively allow */ | 2358 | rv = 1; /* unspecified source; tentatively allow */ |
2345 | } | 2359 | } |
2346 | read_unlock(&in_dev->mc_list_lock); | 2360 | rcu_read_unlock(); |
2347 | return rv; | 2361 | return rv; |
2348 | } | 2362 | } |
2349 | 2363 | ||
@@ -2369,13 +2383,11 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) | |||
2369 | in_dev = __in_dev_get_rcu(state->dev); | 2383 | in_dev = __in_dev_get_rcu(state->dev); |
2370 | if (!in_dev) | 2384 | if (!in_dev) |
2371 | continue; | 2385 | continue; |
2372 | read_lock(&in_dev->mc_list_lock); | 2386 | im = rcu_dereference(in_dev->mc_list); |
2373 | im = in_dev->mc_list; | ||
2374 | if (im) { | 2387 | if (im) { |
2375 | state->in_dev = in_dev; | 2388 | state->in_dev = in_dev; |
2376 | break; | 2389 | break; |
2377 | } | 2390 | } |
2378 | read_unlock(&in_dev->mc_list_lock); | ||
2379 | } | 2391 | } |
2380 | return im; | 2392 | return im; |
2381 | } | 2393 | } |
@@ -2383,11 +2395,9 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) | |||
2383 | static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im) | 2395 | static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im) |
2384 | { | 2396 | { |
2385 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); | 2397 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); |
2386 | im = im->next; | ||
2387 | while (!im) { | ||
2388 | if (likely(state->in_dev != NULL)) | ||
2389 | read_unlock(&state->in_dev->mc_list_lock); | ||
2390 | 2398 | ||
2399 | im = rcu_dereference(im->next_rcu); | ||
2400 | while (!im) { | ||
2391 | state->dev = next_net_device_rcu(state->dev); | 2401 | state->dev = next_net_device_rcu(state->dev); |
2392 | if (!state->dev) { | 2402 | if (!state->dev) { |
2393 | state->in_dev = NULL; | 2403 | state->in_dev = NULL; |
@@ -2396,8 +2406,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li | |||
2396 | state->in_dev = __in_dev_get_rcu(state->dev); | 2406 | state->in_dev = __in_dev_get_rcu(state->dev); |
2397 | if (!state->in_dev) | 2407 | if (!state->in_dev) |
2398 | continue; | 2408 | continue; |
2399 | read_lock(&state->in_dev->mc_list_lock); | 2409 | im = rcu_dereference(state->in_dev->mc_list); |
2400 | im = state->in_dev->mc_list; | ||
2401 | } | 2410 | } |
2402 | return im; | 2411 | return im; |
2403 | } | 2412 | } |
@@ -2433,10 +2442,8 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v) | |||
2433 | __releases(rcu) | 2442 | __releases(rcu) |
2434 | { | 2443 | { |
2435 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); | 2444 | struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); |
2436 | if (likely(state->in_dev != NULL)) { | 2445 | |
2437 | read_unlock(&state->in_dev->mc_list_lock); | 2446 | state->in_dev = NULL; |
2438 | state->in_dev = NULL; | ||
2439 | } | ||
2440 | state->dev = NULL; | 2447 | state->dev = NULL; |
2441 | rcu_read_unlock(); | 2448 | rcu_read_unlock(); |
2442 | } | 2449 | } |
@@ -2458,7 +2465,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v) | |||
2458 | querier = "NONE"; | 2465 | querier = "NONE"; |
2459 | #endif | 2466 | #endif |
2460 | 2467 | ||
2461 | if (state->in_dev->mc_list == im) { | 2468 | if (rcu_dereference(state->in_dev->mc_list) == im) { |
2462 | seq_printf(seq, "%d\t%-10s: %5d %7s\n", | 2469 | seq_printf(seq, "%d\t%-10s: %5d %7s\n", |
2463 | state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); | 2470 | state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); |
2464 | } | 2471 | } |
@@ -2517,8 +2524,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) | |||
2517 | idev = __in_dev_get_rcu(state->dev); | 2524 | idev = __in_dev_get_rcu(state->dev); |
2518 | if (unlikely(idev == NULL)) | 2525 | if (unlikely(idev == NULL)) |
2519 | continue; | 2526 | continue; |
2520 | read_lock(&idev->mc_list_lock); | 2527 | im = rcu_dereference(idev->mc_list); |
2521 | im = idev->mc_list; | ||
2522 | if (likely(im != NULL)) { | 2528 | if (likely(im != NULL)) { |
2523 | spin_lock_bh(&im->lock); | 2529 | spin_lock_bh(&im->lock); |
2524 | psf = im->sources; | 2530 | psf = im->sources; |
@@ -2529,7 +2535,6 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) | |||
2529 | } | 2535 | } |
2530 | spin_unlock_bh(&im->lock); | 2536 | spin_unlock_bh(&im->lock); |
2531 | } | 2537 | } |
2532 | read_unlock(&idev->mc_list_lock); | ||
2533 | } | 2538 | } |
2534 | return psf; | 2539 | return psf; |
2535 | } | 2540 | } |
@@ -2543,9 +2548,6 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l | |||
2543 | spin_unlock_bh(&state->im->lock); | 2548 | spin_unlock_bh(&state->im->lock); |
2544 | state->im = state->im->next; | 2549 | state->im = state->im->next; |
2545 | while (!state->im) { | 2550 | while (!state->im) { |
2546 | if (likely(state->idev != NULL)) | ||
2547 | read_unlock(&state->idev->mc_list_lock); | ||
2548 | |||
2549 | state->dev = next_net_device_rcu(state->dev); | 2551 | state->dev = next_net_device_rcu(state->dev); |
2550 | if (!state->dev) { | 2552 | if (!state->dev) { |
2551 | state->idev = NULL; | 2553 | state->idev = NULL; |
@@ -2554,8 +2556,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l | |||
2554 | state->idev = __in_dev_get_rcu(state->dev); | 2556 | state->idev = __in_dev_get_rcu(state->dev); |
2555 | if (!state->idev) | 2557 | if (!state->idev) |
2556 | continue; | 2558 | continue; |
2557 | read_lock(&state->idev->mc_list_lock); | 2559 | state->im = rcu_dereference(state->idev->mc_list); |
2558 | state->im = state->idev->mc_list; | ||
2559 | } | 2560 | } |
2560 | if (!state->im) | 2561 | if (!state->im) |
2561 | break; | 2562 | break; |
@@ -2601,10 +2602,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) | |||
2601 | spin_unlock_bh(&state->im->lock); | 2602 | spin_unlock_bh(&state->im->lock); |
2602 | state->im = NULL; | 2603 | state->im = NULL; |
2603 | } | 2604 | } |
2604 | if (likely(state->idev != NULL)) { | 2605 | state->idev = NULL; |
2605 | read_unlock(&state->idev->mc_list_lock); | ||
2606 | state->idev = NULL; | ||
2607 | } | ||
2608 | state->dev = NULL; | 2606 | state->dev = NULL; |
2609 | rcu_read_unlock(); | 2607 | rcu_read_unlock(); |
2610 | } | 2608 | } |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 7174370b1195..25e318153f14 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -55,7 +55,6 @@ EXPORT_SYMBOL(inet_get_local_port_range); | |||
55 | int inet_csk_bind_conflict(const struct sock *sk, | 55 | int inet_csk_bind_conflict(const struct sock *sk, |
56 | const struct inet_bind_bucket *tb) | 56 | const struct inet_bind_bucket *tb) |
57 | { | 57 | { |
58 | const __be32 sk_rcv_saddr = inet_rcv_saddr(sk); | ||
59 | struct sock *sk2; | 58 | struct sock *sk2; |
60 | struct hlist_node *node; | 59 | struct hlist_node *node; |
61 | int reuse = sk->sk_reuse; | 60 | int reuse = sk->sk_reuse; |
@@ -75,9 +74,9 @@ int inet_csk_bind_conflict(const struct sock *sk, | |||
75 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { | 74 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
76 | if (!reuse || !sk2->sk_reuse || | 75 | if (!reuse || !sk2->sk_reuse || |
77 | sk2->sk_state == TCP_LISTEN) { | 76 | sk2->sk_state == TCP_LISTEN) { |
78 | const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 77 | const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); |
79 | if (!sk2_rcv_saddr || !sk_rcv_saddr || | 78 | if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) || |
80 | sk2_rcv_saddr == sk_rcv_saddr) | 79 | sk2_rcv_saddr == sk_rcv_saddr(sk)) |
81 | break; | 80 | break; |
82 | } | 81 | } |
83 | } | 82 | } |
@@ -358,17 +357,14 @@ struct dst_entry *inet_csk_route_req(struct sock *sk, | |||
358 | struct ip_options *opt = inet_rsk(req)->opt; | 357 | struct ip_options *opt = inet_rsk(req)->opt; |
359 | struct flowi fl = { .oif = sk->sk_bound_dev_if, | 358 | struct flowi fl = { .oif = sk->sk_bound_dev_if, |
360 | .mark = sk->sk_mark, | 359 | .mark = sk->sk_mark, |
361 | .nl_u = { .ip4_u = | 360 | .fl4_dst = ((opt && opt->srr) ? |
362 | { .daddr = ((opt && opt->srr) ? | 361 | opt->faddr : ireq->rmt_addr), |
363 | opt->faddr : | 362 | .fl4_src = ireq->loc_addr, |
364 | ireq->rmt_addr), | 363 | .fl4_tos = RT_CONN_FLAGS(sk), |
365 | .saddr = ireq->loc_addr, | ||
366 | .tos = RT_CONN_FLAGS(sk) } }, | ||
367 | .proto = sk->sk_protocol, | 364 | .proto = sk->sk_protocol, |
368 | .flags = inet_sk_flowi_flags(sk), | 365 | .flags = inet_sk_flowi_flags(sk), |
369 | .uli_u = { .ports = | 366 | .fl_ip_sport = inet_sk(sk)->inet_sport, |
370 | { .sport = inet_sk(sk)->inet_sport, | 367 | .fl_ip_dport = ireq->rmt_port }; |
371 | .dport = ireq->rmt_port } } }; | ||
372 | struct net *net = sock_net(sk); | 368 | struct net *net = sock_net(sk); |
373 | 369 | ||
374 | security_req_classify_flow(req, &fl); | 370 | security_req_classify_flow(req, &fl); |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 9e94d7cf4f8a..d9bc85751c74 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
@@ -63,7 +63,7 @@ | |||
63 | * refcnt: atomically against modifications on other CPU; | 63 | * refcnt: atomically against modifications on other CPU; |
64 | * usually under some other lock to prevent node disappearing | 64 | * usually under some other lock to prevent node disappearing |
65 | * dtime: unused node list lock | 65 | * dtime: unused node list lock |
66 | * v4daddr: unchangeable | 66 | * daddr: unchangeable |
67 | * ip_id_count: atomic value (no lock needed) | 67 | * ip_id_count: atomic value (no lock needed) |
68 | */ | 68 | */ |
69 | 69 | ||
@@ -79,15 +79,24 @@ static const struct inet_peer peer_fake_node = { | |||
79 | .avl_height = 0 | 79 | .avl_height = 0 |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static struct { | 82 | struct inet_peer_base { |
83 | struct inet_peer __rcu *root; | 83 | struct inet_peer __rcu *root; |
84 | spinlock_t lock; | 84 | spinlock_t lock; |
85 | int total; | 85 | int total; |
86 | } peers = { | 86 | }; |
87 | |||
88 | static struct inet_peer_base v4_peers = { | ||
89 | .root = peer_avl_empty_rcu, | ||
90 | .lock = __SPIN_LOCK_UNLOCKED(v4_peers.lock), | ||
91 | .total = 0, | ||
92 | }; | ||
93 | |||
94 | static struct inet_peer_base v6_peers = { | ||
87 | .root = peer_avl_empty_rcu, | 95 | .root = peer_avl_empty_rcu, |
88 | .lock = __SPIN_LOCK_UNLOCKED(peers.lock), | 96 | .lock = __SPIN_LOCK_UNLOCKED(v6_peers.lock), |
89 | .total = 0, | 97 | .total = 0, |
90 | }; | 98 | }; |
99 | |||
91 | #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ | 100 | #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ |
92 | 101 | ||
93 | /* Exported for sysctl_net_ipv4. */ | 102 | /* Exported for sysctl_net_ipv4. */ |
@@ -152,28 +161,45 @@ static void unlink_from_unused(struct inet_peer *p) | |||
152 | } | 161 | } |
153 | } | 162 | } |
154 | 163 | ||
164 | static int addr_compare(const struct inetpeer_addr *a, | ||
165 | const struct inetpeer_addr *b) | ||
166 | { | ||
167 | int i, n = (a->family == AF_INET ? 1 : 4); | ||
168 | |||
169 | for (i = 0; i < n; i++) { | ||
170 | if (a->a6[i] == b->a6[i]) | ||
171 | continue; | ||
172 | if (a->a6[i] < b->a6[i]) | ||
173 | return -1; | ||
174 | return 1; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
155 | /* | 180 | /* |
156 | * Called with local BH disabled and the pool lock held. | 181 | * Called with local BH disabled and the pool lock held. |
157 | */ | 182 | */ |
158 | #define lookup(_daddr, _stack) \ | 183 | #define lookup(_daddr, _stack, _base) \ |
159 | ({ \ | 184 | ({ \ |
160 | struct inet_peer *u; \ | 185 | struct inet_peer *u; \ |
161 | struct inet_peer __rcu **v; \ | 186 | struct inet_peer __rcu **v; \ |
162 | \ | 187 | \ |
163 | stackptr = _stack; \ | 188 | stackptr = _stack; \ |
164 | *stackptr++ = &peers.root; \ | 189 | *stackptr++ = &_base->root; \ |
165 | for (u = rcu_dereference_protected(peers.root, \ | 190 | for (u = rcu_dereference_protected(_base->root, \ |
166 | lockdep_is_held(&peers.lock)); \ | 191 | lockdep_is_held(&_base->lock)); \ |
167 | u != peer_avl_empty; ) { \ | 192 | u != peer_avl_empty; ) { \ |
168 | if (_daddr == u->v4daddr) \ | 193 | int cmp = addr_compare(_daddr, &u->daddr); \ |
194 | if (cmp == 0) \ | ||
169 | break; \ | 195 | break; \ |
170 | if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \ | 196 | if (cmp == -1) \ |
171 | v = &u->avl_left; \ | 197 | v = &u->avl_left; \ |
172 | else \ | 198 | else \ |
173 | v = &u->avl_right; \ | 199 | v = &u->avl_right; \ |
174 | *stackptr++ = v; \ | 200 | *stackptr++ = v; \ |
175 | u = rcu_dereference_protected(*v, \ | 201 | u = rcu_dereference_protected(*v, \ |
176 | lockdep_is_held(&peers.lock)); \ | 202 | lockdep_is_held(&_base->lock)); \ |
177 | } \ | 203 | } \ |
178 | u; \ | 204 | u; \ |
179 | }) | 205 | }) |
@@ -185,13 +211,15 @@ static void unlink_from_unused(struct inet_peer *p) | |||
185 | * But every pointer we follow is guaranteed to be valid thanks to RCU. | 211 | * But every pointer we follow is guaranteed to be valid thanks to RCU. |
186 | * We exit from this function if number of links exceeds PEER_MAXDEPTH | 212 | * We exit from this function if number of links exceeds PEER_MAXDEPTH |
187 | */ | 213 | */ |
188 | static struct inet_peer *lookup_rcu_bh(__be32 daddr) | 214 | static struct inet_peer *lookup_rcu_bh(const struct inetpeer_addr *daddr, |
215 | struct inet_peer_base *base) | ||
189 | { | 216 | { |
190 | struct inet_peer *u = rcu_dereference_bh(peers.root); | 217 | struct inet_peer *u = rcu_dereference_bh(base->root); |
191 | int count = 0; | 218 | int count = 0; |
192 | 219 | ||
193 | while (u != peer_avl_empty) { | 220 | while (u != peer_avl_empty) { |
194 | if (daddr == u->v4daddr) { | 221 | int cmp = addr_compare(daddr, &u->daddr); |
222 | if (cmp == 0) { | ||
195 | /* Before taking a reference, check if this entry was | 223 | /* Before taking a reference, check if this entry was |
196 | * deleted, unlink_from_pool() sets refcnt=-1 to make | 224 | * deleted, unlink_from_pool() sets refcnt=-1 to make |
197 | * distinction between an unused entry (refcnt=0) and | 225 | * distinction between an unused entry (refcnt=0) and |
@@ -201,7 +229,7 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr) | |||
201 | u = NULL; | 229 | u = NULL; |
202 | return u; | 230 | return u; |
203 | } | 231 | } |
204 | if ((__force __u32)daddr < (__force __u32)u->v4daddr) | 232 | if (cmp == -1) |
205 | u = rcu_dereference_bh(u->avl_left); | 233 | u = rcu_dereference_bh(u->avl_left); |
206 | else | 234 | else |
207 | u = rcu_dereference_bh(u->avl_right); | 235 | u = rcu_dereference_bh(u->avl_right); |
@@ -212,19 +240,19 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr) | |||
212 | } | 240 | } |
213 | 241 | ||
214 | /* Called with local BH disabled and the pool lock held. */ | 242 | /* Called with local BH disabled and the pool lock held. */ |
215 | #define lookup_rightempty(start) \ | 243 | #define lookup_rightempty(start, base) \ |
216 | ({ \ | 244 | ({ \ |
217 | struct inet_peer *u; \ | 245 | struct inet_peer *u; \ |
218 | struct inet_peer __rcu **v; \ | 246 | struct inet_peer __rcu **v; \ |
219 | *stackptr++ = &start->avl_left; \ | 247 | *stackptr++ = &start->avl_left; \ |
220 | v = &start->avl_left; \ | 248 | v = &start->avl_left; \ |
221 | for (u = rcu_dereference_protected(*v, \ | 249 | for (u = rcu_dereference_protected(*v, \ |
222 | lockdep_is_held(&peers.lock)); \ | 250 | lockdep_is_held(&base->lock)); \ |
223 | u->avl_right != peer_avl_empty_rcu; ) { \ | 251 | u->avl_right != peer_avl_empty_rcu; ) { \ |
224 | v = &u->avl_right; \ | 252 | v = &u->avl_right; \ |
225 | *stackptr++ = v; \ | 253 | *stackptr++ = v; \ |
226 | u = rcu_dereference_protected(*v, \ | 254 | u = rcu_dereference_protected(*v, \ |
227 | lockdep_is_held(&peers.lock)); \ | 255 | lockdep_is_held(&base->lock)); \ |
228 | } \ | 256 | } \ |
229 | u; \ | 257 | u; \ |
230 | }) | 258 | }) |
@@ -234,7 +262,8 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr) | |||
234 | * Look into mm/map_avl.c for more detail description of the ideas. | 262 | * Look into mm/map_avl.c for more detail description of the ideas. |
235 | */ | 263 | */ |
236 | static void peer_avl_rebalance(struct inet_peer __rcu **stack[], | 264 | static void peer_avl_rebalance(struct inet_peer __rcu **stack[], |
237 | struct inet_peer __rcu ***stackend) | 265 | struct inet_peer __rcu ***stackend, |
266 | struct inet_peer_base *base) | ||
238 | { | 267 | { |
239 | struct inet_peer __rcu **nodep; | 268 | struct inet_peer __rcu **nodep; |
240 | struct inet_peer *node, *l, *r; | 269 | struct inet_peer *node, *l, *r; |
@@ -243,20 +272,20 @@ static void peer_avl_rebalance(struct inet_peer __rcu **stack[], | |||
243 | while (stackend > stack) { | 272 | while (stackend > stack) { |
244 | nodep = *--stackend; | 273 | nodep = *--stackend; |
245 | node = rcu_dereference_protected(*nodep, | 274 | node = rcu_dereference_protected(*nodep, |
246 | lockdep_is_held(&peers.lock)); | 275 | lockdep_is_held(&base->lock)); |
247 | l = rcu_dereference_protected(node->avl_left, | 276 | l = rcu_dereference_protected(node->avl_left, |
248 | lockdep_is_held(&peers.lock)); | 277 | lockdep_is_held(&base->lock)); |
249 | r = rcu_dereference_protected(node->avl_right, | 278 | r = rcu_dereference_protected(node->avl_right, |
250 | lockdep_is_held(&peers.lock)); | 279 | lockdep_is_held(&base->lock)); |
251 | lh = node_height(l); | 280 | lh = node_height(l); |
252 | rh = node_height(r); | 281 | rh = node_height(r); |
253 | if (lh > rh + 1) { /* l: RH+2 */ | 282 | if (lh > rh + 1) { /* l: RH+2 */ |
254 | struct inet_peer *ll, *lr, *lrl, *lrr; | 283 | struct inet_peer *ll, *lr, *lrl, *lrr; |
255 | int lrh; | 284 | int lrh; |
256 | ll = rcu_dereference_protected(l->avl_left, | 285 | ll = rcu_dereference_protected(l->avl_left, |
257 | lockdep_is_held(&peers.lock)); | 286 | lockdep_is_held(&base->lock)); |
258 | lr = rcu_dereference_protected(l->avl_right, | 287 | lr = rcu_dereference_protected(l->avl_right, |
259 | lockdep_is_held(&peers.lock)); | 288 | lockdep_is_held(&base->lock)); |
260 | lrh = node_height(lr); | 289 | lrh = node_height(lr); |
261 | if (lrh <= node_height(ll)) { /* ll: RH+1 */ | 290 | if (lrh <= node_height(ll)) { /* ll: RH+1 */ |
262 | RCU_INIT_POINTER(node->avl_left, lr); /* lr: RH or RH+1 */ | 291 | RCU_INIT_POINTER(node->avl_left, lr); /* lr: RH or RH+1 */ |
@@ -268,9 +297,9 @@ static void peer_avl_rebalance(struct inet_peer __rcu **stack[], | |||
268 | RCU_INIT_POINTER(*nodep, l); | 297 | RCU_INIT_POINTER(*nodep, l); |
269 | } else { /* ll: RH, lr: RH+1 */ | 298 | } else { /* ll: RH, lr: RH+1 */ |
270 | lrl = rcu_dereference_protected(lr->avl_left, | 299 | lrl = rcu_dereference_protected(lr->avl_left, |
271 | lockdep_is_held(&peers.lock)); /* lrl: RH or RH-1 */ | 300 | lockdep_is_held(&base->lock)); /* lrl: RH or RH-1 */ |
272 | lrr = rcu_dereference_protected(lr->avl_right, | 301 | lrr = rcu_dereference_protected(lr->avl_right, |
273 | lockdep_is_held(&peers.lock)); /* lrr: RH or RH-1 */ | 302 | lockdep_is_held(&base->lock)); /* lrr: RH or RH-1 */ |
274 | RCU_INIT_POINTER(node->avl_left, lrr); /* lrr: RH or RH-1 */ | 303 | RCU_INIT_POINTER(node->avl_left, lrr); /* lrr: RH or RH-1 */ |
275 | RCU_INIT_POINTER(node->avl_right, r); /* r: RH */ | 304 | RCU_INIT_POINTER(node->avl_right, r); /* r: RH */ |
276 | node->avl_height = rh + 1; /* node: RH+1 */ | 305 | node->avl_height = rh + 1; /* node: RH+1 */ |
@@ -286,9 +315,9 @@ static void peer_avl_rebalance(struct inet_peer __rcu **stack[], | |||
286 | struct inet_peer *rr, *rl, *rlr, *rll; | 315 | struct inet_peer *rr, *rl, *rlr, *rll; |
287 | int rlh; | 316 | int rlh; |
288 | rr = rcu_dereference_protected(r->avl_right, | 317 | rr = rcu_dereference_protected(r->avl_right, |
289 | lockdep_is_held(&peers.lock)); | 318 | lockdep_is_held(&base->lock)); |
290 | rl = rcu_dereference_protected(r->avl_left, | 319 | rl = rcu_dereference_protected(r->avl_left, |
291 | lockdep_is_held(&peers.lock)); | 320 | lockdep_is_held(&base->lock)); |
292 | rlh = node_height(rl); | 321 | rlh = node_height(rl); |
293 | if (rlh <= node_height(rr)) { /* rr: LH+1 */ | 322 | if (rlh <= node_height(rr)) { /* rr: LH+1 */ |
294 | RCU_INIT_POINTER(node->avl_right, rl); /* rl: LH or LH+1 */ | 323 | RCU_INIT_POINTER(node->avl_right, rl); /* rl: LH or LH+1 */ |
@@ -300,9 +329,9 @@ static void peer_avl_rebalance(struct inet_peer __rcu **stack[], | |||
300 | RCU_INIT_POINTER(*nodep, r); | 329 | RCU_INIT_POINTER(*nodep, r); |
301 | } else { /* rr: RH, rl: RH+1 */ | 330 | } else { /* rr: RH, rl: RH+1 */ |
302 | rlr = rcu_dereference_protected(rl->avl_right, | 331 | rlr = rcu_dereference_protected(rl->avl_right, |
303 | lockdep_is_held(&peers.lock)); /* rlr: LH or LH-1 */ | 332 | lockdep_is_held(&base->lock)); /* rlr: LH or LH-1 */ |
304 | rll = rcu_dereference_protected(rl->avl_left, | 333 | rll = rcu_dereference_protected(rl->avl_left, |
305 | lockdep_is_held(&peers.lock)); /* rll: LH or LH-1 */ | 334 | lockdep_is_held(&base->lock)); /* rll: LH or LH-1 */ |
306 | RCU_INIT_POINTER(node->avl_right, rll); /* rll: LH or LH-1 */ | 335 | RCU_INIT_POINTER(node->avl_right, rll); /* rll: LH or LH-1 */ |
307 | RCU_INIT_POINTER(node->avl_left, l); /* l: LH */ | 336 | RCU_INIT_POINTER(node->avl_left, l); /* l: LH */ |
308 | node->avl_height = lh + 1; /* node: LH+1 */ | 337 | node->avl_height = lh + 1; /* node: LH+1 */ |
@@ -321,14 +350,14 @@ static void peer_avl_rebalance(struct inet_peer __rcu **stack[], | |||
321 | } | 350 | } |
322 | 351 | ||
323 | /* Called with local BH disabled and the pool lock held. */ | 352 | /* Called with local BH disabled and the pool lock held. */ |
324 | #define link_to_pool(n) \ | 353 | #define link_to_pool(n, base) \ |
325 | do { \ | 354 | do { \ |
326 | n->avl_height = 1; \ | 355 | n->avl_height = 1; \ |
327 | n->avl_left = peer_avl_empty_rcu; \ | 356 | n->avl_left = peer_avl_empty_rcu; \ |
328 | n->avl_right = peer_avl_empty_rcu; \ | 357 | n->avl_right = peer_avl_empty_rcu; \ |
329 | /* lockless readers can catch us now */ \ | 358 | /* lockless readers can catch us now */ \ |
330 | rcu_assign_pointer(**--stackptr, n); \ | 359 | rcu_assign_pointer(**--stackptr, n); \ |
331 | peer_avl_rebalance(stack, stackptr); \ | 360 | peer_avl_rebalance(stack, stackptr, base); \ |
332 | } while (0) | 361 | } while (0) |
333 | 362 | ||
334 | static void inetpeer_free_rcu(struct rcu_head *head) | 363 | static void inetpeer_free_rcu(struct rcu_head *head) |
@@ -337,13 +366,13 @@ static void inetpeer_free_rcu(struct rcu_head *head) | |||
337 | } | 366 | } |
338 | 367 | ||
339 | /* May be called with local BH enabled. */ | 368 | /* May be called with local BH enabled. */ |
340 | static void unlink_from_pool(struct inet_peer *p) | 369 | static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base) |
341 | { | 370 | { |
342 | int do_free; | 371 | int do_free; |
343 | 372 | ||
344 | do_free = 0; | 373 | do_free = 0; |
345 | 374 | ||
346 | spin_lock_bh(&peers.lock); | 375 | spin_lock_bh(&base->lock); |
347 | /* Check the reference counter. It was artificially incremented by 1 | 376 | /* Check the reference counter. It was artificially incremented by 1 |
348 | * in cleanup() function to prevent sudden disappearing. If we can | 377 | * in cleanup() function to prevent sudden disappearing. If we can |
349 | * atomically (because of lockless readers) take this last reference, | 378 | * atomically (because of lockless readers) take this last reference, |
@@ -353,7 +382,7 @@ static void unlink_from_pool(struct inet_peer *p) | |||
353 | if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) { | 382 | if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) { |
354 | struct inet_peer __rcu **stack[PEER_MAXDEPTH]; | 383 | struct inet_peer __rcu **stack[PEER_MAXDEPTH]; |
355 | struct inet_peer __rcu ***stackptr, ***delp; | 384 | struct inet_peer __rcu ***stackptr, ***delp; |
356 | if (lookup(p->v4daddr, stack) != p) | 385 | if (lookup(&p->daddr, stack, base) != p) |
357 | BUG(); | 386 | BUG(); |
358 | delp = stackptr - 1; /* *delp[0] == p */ | 387 | delp = stackptr - 1; /* *delp[0] == p */ |
359 | if (p->avl_left == peer_avl_empty_rcu) { | 388 | if (p->avl_left == peer_avl_empty_rcu) { |
@@ -362,11 +391,11 @@ static void unlink_from_pool(struct inet_peer *p) | |||
362 | } else { | 391 | } else { |
363 | /* look for a node to insert instead of p */ | 392 | /* look for a node to insert instead of p */ |
364 | struct inet_peer *t; | 393 | struct inet_peer *t; |
365 | t = lookup_rightempty(p); | 394 | t = lookup_rightempty(p, base); |
366 | BUG_ON(rcu_dereference_protected(*stackptr[-1], | 395 | BUG_ON(rcu_dereference_protected(*stackptr[-1], |
367 | lockdep_is_held(&peers.lock)) != t); | 396 | lockdep_is_held(&base->lock)) != t); |
368 | **--stackptr = t->avl_left; | 397 | **--stackptr = t->avl_left; |
369 | /* t is removed, t->v4daddr > x->v4daddr for any | 398 | /* t is removed, t->daddr > x->daddr for any |
370 | * x in p->avl_left subtree. | 399 | * x in p->avl_left subtree. |
371 | * Put t in the old place of p. */ | 400 | * Put t in the old place of p. */ |
372 | RCU_INIT_POINTER(*delp[0], t); | 401 | RCU_INIT_POINTER(*delp[0], t); |
@@ -376,11 +405,11 @@ static void unlink_from_pool(struct inet_peer *p) | |||
376 | BUG_ON(delp[1] != &p->avl_left); | 405 | BUG_ON(delp[1] != &p->avl_left); |
377 | delp[1] = &t->avl_left; /* was &p->avl_left */ | 406 | delp[1] = &t->avl_left; /* was &p->avl_left */ |
378 | } | 407 | } |
379 | peer_avl_rebalance(stack, stackptr); | 408 | peer_avl_rebalance(stack, stackptr, base); |
380 | peers.total--; | 409 | base->total--; |
381 | do_free = 1; | 410 | do_free = 1; |
382 | } | 411 | } |
383 | spin_unlock_bh(&peers.lock); | 412 | spin_unlock_bh(&base->lock); |
384 | 413 | ||
385 | if (do_free) | 414 | if (do_free) |
386 | call_rcu_bh(&p->rcu, inetpeer_free_rcu); | 415 | call_rcu_bh(&p->rcu, inetpeer_free_rcu); |
@@ -395,6 +424,16 @@ static void unlink_from_pool(struct inet_peer *p) | |||
395 | inet_putpeer(p); | 424 | inet_putpeer(p); |
396 | } | 425 | } |
397 | 426 | ||
427 | static struct inet_peer_base *family_to_base(int family) | ||
428 | { | ||
429 | return (family == AF_INET ? &v4_peers : &v6_peers); | ||
430 | } | ||
431 | |||
432 | static struct inet_peer_base *peer_to_base(struct inet_peer *p) | ||
433 | { | ||
434 | return family_to_base(p->daddr.family); | ||
435 | } | ||
436 | |||
398 | /* May be called with local BH enabled. */ | 437 | /* May be called with local BH enabled. */ |
399 | static int cleanup_once(unsigned long ttl) | 438 | static int cleanup_once(unsigned long ttl) |
400 | { | 439 | { |
@@ -428,21 +467,22 @@ static int cleanup_once(unsigned long ttl) | |||
428 | * happen because of entry limits in route cache. */ | 467 | * happen because of entry limits in route cache. */ |
429 | return -1; | 468 | return -1; |
430 | 469 | ||
431 | unlink_from_pool(p); | 470 | unlink_from_pool(p, peer_to_base(p)); |
432 | return 0; | 471 | return 0; |
433 | } | 472 | } |
434 | 473 | ||
435 | /* Called with or without local BH being disabled. */ | 474 | /* Called with or without local BH being disabled. */ |
436 | struct inet_peer *inet_getpeer(__be32 daddr, int create) | 475 | struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create) |
437 | { | 476 | { |
438 | struct inet_peer *p; | ||
439 | struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr; | 477 | struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr; |
478 | struct inet_peer_base *base = family_to_base(AF_INET); | ||
479 | struct inet_peer *p; | ||
440 | 480 | ||
441 | /* Look up for the address quickly, lockless. | 481 | /* Look up for the address quickly, lockless. |
442 | * Because of a concurrent writer, we might not find an existing entry. | 482 | * Because of a concurrent writer, we might not find an existing entry. |
443 | */ | 483 | */ |
444 | rcu_read_lock_bh(); | 484 | rcu_read_lock_bh(); |
445 | p = lookup_rcu_bh(daddr); | 485 | p = lookup_rcu_bh(daddr, base); |
446 | rcu_read_unlock_bh(); | 486 | rcu_read_unlock_bh(); |
447 | 487 | ||
448 | if (p) { | 488 | if (p) { |
@@ -456,50 +496,57 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create) | |||
456 | /* retry an exact lookup, taking the lock before. | 496 | /* retry an exact lookup, taking the lock before. |
457 | * At least, nodes should be hot in our cache. | 497 | * At least, nodes should be hot in our cache. |
458 | */ | 498 | */ |
459 | spin_lock_bh(&peers.lock); | 499 | spin_lock_bh(&base->lock); |
460 | p = lookup(daddr, stack); | 500 | p = lookup(daddr, stack, base); |
461 | if (p != peer_avl_empty) { | 501 | if (p != peer_avl_empty) { |
462 | atomic_inc(&p->refcnt); | 502 | atomic_inc(&p->refcnt); |
463 | spin_unlock_bh(&peers.lock); | 503 | spin_unlock_bh(&base->lock); |
464 | /* Remove the entry from unused list if it was there. */ | 504 | /* Remove the entry from unused list if it was there. */ |
465 | unlink_from_unused(p); | 505 | unlink_from_unused(p); |
466 | return p; | 506 | return p; |
467 | } | 507 | } |
468 | p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL; | 508 | p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL; |
469 | if (p) { | 509 | if (p) { |
470 | p->v4daddr = daddr; | 510 | p->daddr = *daddr; |
471 | atomic_set(&p->refcnt, 1); | 511 | atomic_set(&p->refcnt, 1); |
472 | atomic_set(&p->rid, 0); | 512 | atomic_set(&p->rid, 0); |
473 | atomic_set(&p->ip_id_count, secure_ip_id(daddr)); | 513 | atomic_set(&p->ip_id_count, secure_ip_id(daddr->a4)); |
474 | p->tcp_ts_stamp = 0; | 514 | p->tcp_ts_stamp = 0; |
475 | INIT_LIST_HEAD(&p->unused); | 515 | INIT_LIST_HEAD(&p->unused); |
476 | 516 | ||
477 | 517 | ||
478 | /* Link the node. */ | 518 | /* Link the node. */ |
479 | link_to_pool(p); | 519 | link_to_pool(p, base); |
480 | peers.total++; | 520 | base->total++; |
481 | } | 521 | } |
482 | spin_unlock_bh(&peers.lock); | 522 | spin_unlock_bh(&base->lock); |
483 | 523 | ||
484 | if (peers.total >= inet_peer_threshold) | 524 | if (base->total >= inet_peer_threshold) |
485 | /* Remove one less-recently-used entry. */ | 525 | /* Remove one less-recently-used entry. */ |
486 | cleanup_once(0); | 526 | cleanup_once(0); |
487 | 527 | ||
488 | return p; | 528 | return p; |
489 | } | 529 | } |
490 | 530 | ||
531 | static int compute_total(void) | ||
532 | { | ||
533 | return v4_peers.total + v6_peers.total; | ||
534 | } | ||
535 | EXPORT_SYMBOL_GPL(inet_getpeer); | ||
536 | |||
491 | /* Called with local BH disabled. */ | 537 | /* Called with local BH disabled. */ |
492 | static void peer_check_expire(unsigned long dummy) | 538 | static void peer_check_expire(unsigned long dummy) |
493 | { | 539 | { |
494 | unsigned long now = jiffies; | 540 | unsigned long now = jiffies; |
495 | int ttl; | 541 | int ttl, total; |
496 | 542 | ||
497 | if (peers.total >= inet_peer_threshold) | 543 | total = compute_total(); |
544 | if (total >= inet_peer_threshold) | ||
498 | ttl = inet_peer_minttl; | 545 | ttl = inet_peer_minttl; |
499 | else | 546 | else |
500 | ttl = inet_peer_maxttl | 547 | ttl = inet_peer_maxttl |
501 | - (inet_peer_maxttl - inet_peer_minttl) / HZ * | 548 | - (inet_peer_maxttl - inet_peer_minttl) / HZ * |
502 | peers.total / inet_peer_threshold * HZ; | 549 | total / inet_peer_threshold * HZ; |
503 | while (!cleanup_once(ttl)) { | 550 | while (!cleanup_once(ttl)) { |
504 | if (jiffies != now) | 551 | if (jiffies != now) |
505 | break; | 552 | break; |
@@ -508,13 +555,14 @@ static void peer_check_expire(unsigned long dummy) | |||
508 | /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime | 555 | /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime |
509 | * interval depending on the total number of entries (more entries, | 556 | * interval depending on the total number of entries (more entries, |
510 | * less interval). */ | 557 | * less interval). */ |
511 | if (peers.total >= inet_peer_threshold) | 558 | total = compute_total(); |
559 | if (total >= inet_peer_threshold) | ||
512 | peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime; | 560 | peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime; |
513 | else | 561 | else |
514 | peer_periodic_timer.expires = jiffies | 562 | peer_periodic_timer.expires = jiffies |
515 | + inet_peer_gc_maxtime | 563 | + inet_peer_gc_maxtime |
516 | - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ * | 564 | - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ * |
517 | peers.total / inet_peer_threshold * HZ; | 565 | total / inet_peer_threshold * HZ; |
518 | add_timer(&peer_periodic_timer); | 566 | add_timer(&peer_periodic_timer); |
519 | } | 567 | } |
520 | 568 | ||
@@ -530,3 +578,4 @@ void inet_putpeer(struct inet_peer *p) | |||
530 | 578 | ||
531 | local_bh_enable(); | 579 | local_bh_enable(); |
532 | } | 580 | } |
581 | EXPORT_SYMBOL_GPL(inet_putpeer); | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 168440834ade..e6215bdd96c0 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -141,7 +141,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, void *a) | |||
141 | qp->daddr = arg->iph->daddr; | 141 | qp->daddr = arg->iph->daddr; |
142 | qp->user = arg->user; | 142 | qp->user = arg->user; |
143 | qp->peer = sysctl_ipfrag_max_dist ? | 143 | qp->peer = sysctl_ipfrag_max_dist ? |
144 | inet_getpeer(arg->iph->saddr, 1) : NULL; | 144 | inet_getpeer_v4(arg->iph->saddr, 1) : NULL; |
145 | } | 145 | } |
146 | 146 | ||
147 | static __inline__ void ip4_frag_free(struct inet_frag_queue *q) | 147 | static __inline__ void ip4_frag_free(struct inet_frag_queue *q) |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 70ff77f02eee..eb68a0e34e49 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -405,11 +405,11 @@ static struct ip_tunnel *ipgre_tunnel_locate(struct net *net, | |||
405 | if (parms->name[0]) | 405 | if (parms->name[0]) |
406 | strlcpy(name, parms->name, IFNAMSIZ); | 406 | strlcpy(name, parms->name, IFNAMSIZ); |
407 | else | 407 | else |
408 | sprintf(name, "gre%%d"); | 408 | strcpy(name, "gre%d"); |
409 | 409 | ||
410 | dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup); | 410 | dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup); |
411 | if (!dev) | 411 | if (!dev) |
412 | return NULL; | 412 | return NULL; |
413 | 413 | ||
414 | dev_net_set(dev, net); | 414 | dev_net_set(dev, net); |
415 | 415 | ||
@@ -634,7 +634,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
634 | #ifdef CONFIG_NET_IPGRE_BROADCAST | 634 | #ifdef CONFIG_NET_IPGRE_BROADCAST |
635 | if (ipv4_is_multicast(iph->daddr)) { | 635 | if (ipv4_is_multicast(iph->daddr)) { |
636 | /* Looped back packet, drop it! */ | 636 | /* Looped back packet, drop it! */ |
637 | if (skb_rtable(skb)->fl.iif == 0) | 637 | if (rt_is_output_route(skb_rtable(skb))) |
638 | goto drop; | 638 | goto drop; |
639 | tunnel->dev->stats.multicast++; | 639 | tunnel->dev->stats.multicast++; |
640 | skb->pkt_type = PACKET_BROADCAST; | 640 | skb->pkt_type = PACKET_BROADCAST; |
@@ -772,16 +772,11 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev | |||
772 | { | 772 | { |
773 | struct flowi fl = { | 773 | struct flowi fl = { |
774 | .oif = tunnel->parms.link, | 774 | .oif = tunnel->parms.link, |
775 | .nl_u = { | 775 | .fl4_dst = dst, |
776 | .ip4_u = { | 776 | .fl4_src = tiph->saddr, |
777 | .daddr = dst, | 777 | .fl4_tos = RT_TOS(tos), |
778 | .saddr = tiph->saddr, | 778 | .fl_gre_key = tunnel->parms.o_key |
779 | .tos = RT_TOS(tos) | 779 | }; |
780 | } | ||
781 | }, | ||
782 | .proto = IPPROTO_GRE | ||
783 | } | ||
784 | ; | ||
785 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 780 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { |
786 | dev->stats.tx_carrier_errors++; | 781 | dev->stats.tx_carrier_errors++; |
787 | goto tx_error; | 782 | goto tx_error; |
@@ -823,7 +818,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev | |||
823 | !ipv4_is_multicast(tunnel->parms.iph.daddr)) || | 818 | !ipv4_is_multicast(tunnel->parms.iph.daddr)) || |
824 | rt6->rt6i_dst.plen == 128) { | 819 | rt6->rt6i_dst.plen == 128) { |
825 | rt6->rt6i_flags |= RTF_MODIFIED; | 820 | rt6->rt6i_flags |= RTF_MODIFIED; |
826 | skb_dst(skb)->metrics[RTAX_MTU-1] = mtu; | 821 | dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); |
827 | } | 822 | } |
828 | } | 823 | } |
829 | 824 | ||
@@ -895,7 +890,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev | |||
895 | iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit; | 890 | iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit; |
896 | #endif | 891 | #endif |
897 | else | 892 | else |
898 | iph->ttl = dst_metric(&rt->dst, RTAX_HOPLIMIT); | 893 | iph->ttl = ip4_dst_hoplimit(&rt->dst); |
899 | } | 894 | } |
900 | 895 | ||
901 | ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags; | 896 | ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags; |
@@ -951,14 +946,11 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev) | |||
951 | if (iph->daddr) { | 946 | if (iph->daddr) { |
952 | struct flowi fl = { | 947 | struct flowi fl = { |
953 | .oif = tunnel->parms.link, | 948 | .oif = tunnel->parms.link, |
954 | .nl_u = { | 949 | .fl4_dst = iph->daddr, |
955 | .ip4_u = { | 950 | .fl4_src = iph->saddr, |
956 | .daddr = iph->daddr, | 951 | .fl4_tos = RT_TOS(iph->tos), |
957 | .saddr = iph->saddr, | 952 | .proto = IPPROTO_GRE, |
958 | .tos = RT_TOS(iph->tos) | 953 | .fl_gre_key = tunnel->parms.o_key |
959 | } | ||
960 | }, | ||
961 | .proto = IPPROTO_GRE | ||
962 | }; | 954 | }; |
963 | struct rtable *rt; | 955 | struct rtable *rt; |
964 | 956 | ||
@@ -1216,14 +1208,11 @@ static int ipgre_open(struct net_device *dev) | |||
1216 | if (ipv4_is_multicast(t->parms.iph.daddr)) { | 1208 | if (ipv4_is_multicast(t->parms.iph.daddr)) { |
1217 | struct flowi fl = { | 1209 | struct flowi fl = { |
1218 | .oif = t->parms.link, | 1210 | .oif = t->parms.link, |
1219 | .nl_u = { | 1211 | .fl4_dst = t->parms.iph.daddr, |
1220 | .ip4_u = { | 1212 | .fl4_src = t->parms.iph.saddr, |
1221 | .daddr = t->parms.iph.daddr, | 1213 | .fl4_tos = RT_TOS(t->parms.iph.tos), |
1222 | .saddr = t->parms.iph.saddr, | 1214 | .proto = IPPROTO_GRE, |
1223 | .tos = RT_TOS(t->parms.iph.tos) | 1215 | .fl_gre_key = t->parms.o_key |
1224 | } | ||
1225 | }, | ||
1226 | .proto = IPPROTO_GRE | ||
1227 | }; | 1216 | }; |
1228 | struct rtable *rt; | 1217 | struct rtable *rt; |
1229 | 1218 | ||
@@ -1775,3 +1764,4 @@ module_exit(ipgre_fini); | |||
1775 | MODULE_LICENSE("GPL"); | 1764 | MODULE_LICENSE("GPL"); |
1776 | MODULE_ALIAS_RTNL_LINK("gre"); | 1765 | MODULE_ALIAS_RTNL_LINK("gre"); |
1777 | MODULE_ALIAS_RTNL_LINK("gretap"); | 1766 | MODULE_ALIAS_RTNL_LINK("gretap"); |
1767 | MODULE_ALIAS("gre0"); | ||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 439d2a34ee44..04c7b3ba6b39 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -82,6 +82,7 @@ | |||
82 | #include <linux/tcp.h> | 82 | #include <linux/tcp.h> |
83 | 83 | ||
84 | int sysctl_ip_default_ttl __read_mostly = IPDEFTTL; | 84 | int sysctl_ip_default_ttl __read_mostly = IPDEFTTL; |
85 | EXPORT_SYMBOL(sysctl_ip_default_ttl); | ||
85 | 86 | ||
86 | /* Generate a checksum for an outgoing IP datagram. */ | 87 | /* Generate a checksum for an outgoing IP datagram. */ |
87 | __inline__ void ip_send_check(struct iphdr *iph) | 88 | __inline__ void ip_send_check(struct iphdr *iph) |
@@ -130,7 +131,7 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) | |||
130 | int ttl = inet->uc_ttl; | 131 | int ttl = inet->uc_ttl; |
131 | 132 | ||
132 | if (ttl < 0) | 133 | if (ttl < 0) |
133 | ttl = dst_metric(dst, RTAX_HOPLIMIT); | 134 | ttl = ip4_dst_hoplimit(dst); |
134 | return ttl; | 135 | return ttl; |
135 | } | 136 | } |
136 | 137 | ||
@@ -341,15 +342,13 @@ int ip_queue_xmit(struct sk_buff *skb) | |||
341 | { | 342 | { |
342 | struct flowi fl = { .oif = sk->sk_bound_dev_if, | 343 | struct flowi fl = { .oif = sk->sk_bound_dev_if, |
343 | .mark = sk->sk_mark, | 344 | .mark = sk->sk_mark, |
344 | .nl_u = { .ip4_u = | 345 | .fl4_dst = daddr, |
345 | { .daddr = daddr, | 346 | .fl4_src = inet->inet_saddr, |
346 | .saddr = inet->inet_saddr, | 347 | .fl4_tos = RT_CONN_FLAGS(sk), |
347 | .tos = RT_CONN_FLAGS(sk) } }, | ||
348 | .proto = sk->sk_protocol, | 348 | .proto = sk->sk_protocol, |
349 | .flags = inet_sk_flowi_flags(sk), | 349 | .flags = inet_sk_flowi_flags(sk), |
350 | .uli_u = { .ports = | 350 | .fl_ip_sport = inet->inet_sport, |
351 | { .sport = inet->inet_sport, | 351 | .fl_ip_dport = inet->inet_dport }; |
352 | .dport = inet->inet_dport } } }; | ||
353 | 352 | ||
354 | /* If this fails, retransmit mechanism of transport layer will | 353 | /* If this fails, retransmit mechanism of transport layer will |
355 | * keep trying until route appears or the connection times | 354 | * keep trying until route appears or the connection times |
@@ -1404,14 +1403,11 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
1404 | 1403 | ||
1405 | { | 1404 | { |
1406 | struct flowi fl = { .oif = arg->bound_dev_if, | 1405 | struct flowi fl = { .oif = arg->bound_dev_if, |
1407 | .nl_u = { .ip4_u = | 1406 | .fl4_dst = daddr, |
1408 | { .daddr = daddr, | 1407 | .fl4_src = rt->rt_spec_dst, |
1409 | .saddr = rt->rt_spec_dst, | 1408 | .fl4_tos = RT_TOS(ip_hdr(skb)->tos), |
1410 | .tos = RT_TOS(ip_hdr(skb)->tos) } }, | 1409 | .fl_ip_sport = tcp_hdr(skb)->dest, |
1411 | /* Not quite clean, but right. */ | 1410 | .fl_ip_dport = tcp_hdr(skb)->source, |
1412 | .uli_u = { .ports = | ||
1413 | { .sport = tcp_hdr(skb)->dest, | ||
1414 | .dport = tcp_hdr(skb)->source } }, | ||
1415 | .proto = sk->sk_protocol, | 1411 | .proto = sk->sk_protocol, |
1416 | .flags = ip_reply_arg_flowi_flags(arg) }; | 1412 | .flags = ip_reply_arg_flowi_flags(arg) }; |
1417 | security_skb_classify_flow(skb, &fl); | 1413 | security_skb_classify_flow(skb, &fl); |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 3a6e1ec5e9ae..2b097752426b 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -1191,13 +1191,13 @@ static int __init ic_dynamic(void) | |||
1191 | (ic_proto_enabled & IC_USE_DHCP) && | 1191 | (ic_proto_enabled & IC_USE_DHCP) && |
1192 | ic_dhcp_msgtype != DHCPACK) { | 1192 | ic_dhcp_msgtype != DHCPACK) { |
1193 | ic_got_reply = 0; | 1193 | ic_got_reply = 0; |
1194 | printk(","); | 1194 | printk(KERN_CONT ","); |
1195 | continue; | 1195 | continue; |
1196 | } | 1196 | } |
1197 | #endif /* IPCONFIG_DHCP */ | 1197 | #endif /* IPCONFIG_DHCP */ |
1198 | 1198 | ||
1199 | if (ic_got_reply) { | 1199 | if (ic_got_reply) { |
1200 | printk(" OK\n"); | 1200 | printk(KERN_CONT " OK\n"); |
1201 | break; | 1201 | break; |
1202 | } | 1202 | } |
1203 | 1203 | ||
@@ -1205,7 +1205,7 @@ static int __init ic_dynamic(void) | |||
1205 | continue; | 1205 | continue; |
1206 | 1206 | ||
1207 | if (! --retries) { | 1207 | if (! --retries) { |
1208 | printk(" timed out!\n"); | 1208 | printk(KERN_CONT " timed out!\n"); |
1209 | break; | 1209 | break; |
1210 | } | 1210 | } |
1211 | 1211 | ||
@@ -1215,7 +1215,7 @@ static int __init ic_dynamic(void) | |||
1215 | if (timeout > CONF_TIMEOUT_MAX) | 1215 | if (timeout > CONF_TIMEOUT_MAX) |
1216 | timeout = CONF_TIMEOUT_MAX; | 1216 | timeout = CONF_TIMEOUT_MAX; |
1217 | 1217 | ||
1218 | printk("."); | 1218 | printk(KERN_CONT "."); |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | #ifdef IPCONFIG_BOOTP | 1221 | #ifdef IPCONFIG_BOOTP |
@@ -1236,7 +1236,7 @@ static int __init ic_dynamic(void) | |||
1236 | ((ic_got_reply & IC_RARP) ? "RARP" | 1236 | ((ic_got_reply & IC_RARP) ? "RARP" |
1237 | : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), | 1237 | : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), |
1238 | &ic_servaddr); | 1238 | &ic_servaddr); |
1239 | printk("my address is %pI4\n", &ic_myaddr); | 1239 | printk(KERN_CONT "my address is %pI4\n", &ic_myaddr); |
1240 | 1240 | ||
1241 | return 0; | 1241 | return 0; |
1242 | } | 1242 | } |
@@ -1468,19 +1468,19 @@ static int __init ip_auto_config(void) | |||
1468 | /* | 1468 | /* |
1469 | * Clue in the operator. | 1469 | * Clue in the operator. |
1470 | */ | 1470 | */ |
1471 | printk("IP-Config: Complete:"); | 1471 | printk("IP-Config: Complete:\n"); |
1472 | printk("\n device=%s", ic_dev->name); | 1472 | printk(" device=%s", ic_dev->name); |
1473 | printk(", addr=%pI4", &ic_myaddr); | 1473 | printk(KERN_CONT ", addr=%pI4", &ic_myaddr); |
1474 | printk(", mask=%pI4", &ic_netmask); | 1474 | printk(KERN_CONT ", mask=%pI4", &ic_netmask); |
1475 | printk(", gw=%pI4", &ic_gateway); | 1475 | printk(KERN_CONT ", gw=%pI4", &ic_gateway); |
1476 | printk(",\n host=%s, domain=%s, nis-domain=%s", | 1476 | printk(KERN_CONT ",\n host=%s, domain=%s, nis-domain=%s", |
1477 | utsname()->nodename, ic_domain, utsname()->domainname); | 1477 | utsname()->nodename, ic_domain, utsname()->domainname); |
1478 | printk(",\n bootserver=%pI4", &ic_servaddr); | 1478 | printk(KERN_CONT ",\n bootserver=%pI4", &ic_servaddr); |
1479 | printk(", rootserver=%pI4", &root_server_addr); | 1479 | printk(KERN_CONT ", rootserver=%pI4", &root_server_addr); |
1480 | printk(", rootpath=%s", root_server_path); | 1480 | printk(KERN_CONT ", rootpath=%s", root_server_path); |
1481 | if (ic_dev_mtu) | 1481 | if (ic_dev_mtu) |
1482 | printk(", mtu=%d", ic_dev_mtu); | 1482 | printk(KERN_CONT ", mtu=%d", ic_dev_mtu); |
1483 | printk("\n"); | 1483 | printk(KERN_CONT "\n"); |
1484 | #endif /* !SILENT */ | 1484 | #endif /* !SILENT */ |
1485 | 1485 | ||
1486 | return 0; | 1486 | return 0; |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index cd300aaee78f..988f52fba54a 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -463,13 +463,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
463 | { | 463 | { |
464 | struct flowi fl = { | 464 | struct flowi fl = { |
465 | .oif = tunnel->parms.link, | 465 | .oif = tunnel->parms.link, |
466 | .nl_u = { | 466 | .fl4_dst = dst, |
467 | .ip4_u = { | 467 | .fl4_src= tiph->saddr, |
468 | .daddr = dst, | 468 | .fl4_tos = RT_TOS(tos), |
469 | .saddr = tiph->saddr, | ||
470 | .tos = RT_TOS(tos) | ||
471 | } | ||
472 | }, | ||
473 | .proto = IPPROTO_IPIP | 469 | .proto = IPPROTO_IPIP |
474 | }; | 470 | }; |
475 | 471 | ||
@@ -589,13 +585,9 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) | |||
589 | if (iph->daddr) { | 585 | if (iph->daddr) { |
590 | struct flowi fl = { | 586 | struct flowi fl = { |
591 | .oif = tunnel->parms.link, | 587 | .oif = tunnel->parms.link, |
592 | .nl_u = { | 588 | .fl4_dst = iph->daddr, |
593 | .ip4_u = { | 589 | .fl4_src = iph->saddr, |
594 | .daddr = iph->daddr, | 590 | .fl4_tos = RT_TOS(iph->tos), |
595 | .saddr = iph->saddr, | ||
596 | .tos = RT_TOS(iph->tos) | ||
597 | } | ||
598 | }, | ||
599 | .proto = IPPROTO_IPIP | 591 | .proto = IPPROTO_IPIP |
600 | }; | 592 | }; |
601 | struct rtable *rt; | 593 | struct rtable *rt; |
@@ -921,3 +913,4 @@ static void __exit ipip_fini(void) | |||
921 | module_init(ipip_init); | 913 | module_init(ipip_init); |
922 | module_exit(ipip_fini); | 914 | module_exit(ipip_fini); |
923 | MODULE_LICENSE("GPL"); | 915 | MODULE_LICENSE("GPL"); |
916 | MODULE_ALIAS("tunl0"); | ||
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 86dd5691af46..3f3a9afd73e0 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -1537,13 +1537,9 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, | |||
1537 | if (vif->flags & VIFF_TUNNEL) { | 1537 | if (vif->flags & VIFF_TUNNEL) { |
1538 | struct flowi fl = { | 1538 | struct flowi fl = { |
1539 | .oif = vif->link, | 1539 | .oif = vif->link, |
1540 | .nl_u = { | 1540 | .fl4_dst = vif->remote, |
1541 | .ip4_u = { | 1541 | .fl4_src = vif->local, |
1542 | .daddr = vif->remote, | 1542 | .fl4_tos = RT_TOS(iph->tos), |
1543 | .saddr = vif->local, | ||
1544 | .tos = RT_TOS(iph->tos) | ||
1545 | } | ||
1546 | }, | ||
1547 | .proto = IPPROTO_IPIP | 1543 | .proto = IPPROTO_IPIP |
1548 | }; | 1544 | }; |
1549 | 1545 | ||
@@ -1553,12 +1549,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, | |||
1553 | } else { | 1549 | } else { |
1554 | struct flowi fl = { | 1550 | struct flowi fl = { |
1555 | .oif = vif->link, | 1551 | .oif = vif->link, |
1556 | .nl_u = { | 1552 | .fl4_dst = iph->daddr, |
1557 | .ip4_u = { | 1553 | .fl4_tos = RT_TOS(iph->tos), |
1558 | .daddr = iph->daddr, | ||
1559 | .tos = RT_TOS(iph->tos) | ||
1560 | } | ||
1561 | }, | ||
1562 | .proto = IPPROTO_IPIP | 1554 | .proto = IPPROTO_IPIP |
1563 | }; | 1555 | }; |
1564 | 1556 | ||
@@ -1654,7 +1646,7 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt, | |||
1654 | if (mrt->vif_table[vif].dev != skb->dev) { | 1646 | if (mrt->vif_table[vif].dev != skb->dev) { |
1655 | int true_vifi; | 1647 | int true_vifi; |
1656 | 1648 | ||
1657 | if (skb_rtable(skb)->fl.iif == 0) { | 1649 | if (rt_is_output_route(skb_rtable(skb))) { |
1658 | /* It is our own packet, looped back. | 1650 | /* It is our own packet, looped back. |
1659 | * Very complicated situation... | 1651 | * Very complicated situation... |
1660 | * | 1652 | * |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index d88a46c54fd1..994a1f29ebbc 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -31,10 +31,10 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) | |||
31 | * packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook. | 31 | * packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook. |
32 | */ | 32 | */ |
33 | if (addr_type == RTN_LOCAL) { | 33 | if (addr_type == RTN_LOCAL) { |
34 | fl.nl_u.ip4_u.daddr = iph->daddr; | 34 | fl.fl4_dst = iph->daddr; |
35 | if (type == RTN_LOCAL) | 35 | if (type == RTN_LOCAL) |
36 | fl.nl_u.ip4_u.saddr = iph->saddr; | 36 | fl.fl4_src = iph->saddr; |
37 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | 37 | fl.fl4_tos = RT_TOS(iph->tos); |
38 | fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0; | 38 | fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0; |
39 | fl.mark = skb->mark; | 39 | fl.mark = skb->mark; |
40 | fl.flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0; | 40 | fl.flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0; |
@@ -47,7 +47,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) | |||
47 | } else { | 47 | } else { |
48 | /* non-local src, find valid iif to satisfy | 48 | /* non-local src, find valid iif to satisfy |
49 | * rp-filter when calling ip_route_input. */ | 49 | * rp-filter when calling ip_route_input. */ |
50 | fl.nl_u.ip4_u.daddr = iph->saddr; | 50 | fl.fl4_dst = iph->saddr; |
51 | if (ip_route_output_key(net, &rt, &fl) != 0) | 51 | if (ip_route_output_key(net, &rt, &fl) != 0) |
52 | return -1; | 52 | return -1; |
53 | 53 | ||
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 48111594ee9b..19eb59d01037 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -3,15 +3,15 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # objects for l3 independent conntrack | 5 | # objects for l3 independent conntrack |
6 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o | 6 | nf_conntrack_ipv4-y := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o |
7 | ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y) | 7 | ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y) |
8 | ifeq ($(CONFIG_PROC_FS),y) | 8 | ifeq ($(CONFIG_PROC_FS),y) |
9 | nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o | 9 | nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o |
10 | endif | 10 | endif |
11 | endif | 11 | endif |
12 | 12 | ||
13 | nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_common.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o | 13 | nf_nat-y := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_common.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o |
14 | iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o | 14 | iptable_nat-y := nf_nat_rule.o nf_nat_standalone.o |
15 | 15 | ||
16 | # connection tracking | 16 | # connection tracking |
17 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 43eec80c0e7c..1ff79e557f96 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -116,7 +116,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
116 | if (ip_route_me_harder(nskb, addr_type)) | 116 | if (ip_route_me_harder(nskb, addr_type)) |
117 | goto free_nskb; | 117 | goto free_nskb; |
118 | 118 | ||
119 | niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); | 119 | niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); |
120 | 120 | ||
121 | /* "Never happens" */ | 121 | /* "Never happens" */ |
122 | if (nskb->len > dst_mtu(skb_dst(nskb))) | 122 | if (nskb->len > dst_mtu(skb_dst(nskb))) |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 1f85ef289895..a3d5ab786e81 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -549,10 +549,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
549 | { | 549 | { |
550 | struct flowi fl = { .oif = ipc.oif, | 550 | struct flowi fl = { .oif = ipc.oif, |
551 | .mark = sk->sk_mark, | 551 | .mark = sk->sk_mark, |
552 | .nl_u = { .ip4_u = | 552 | .fl4_dst = daddr, |
553 | { .daddr = daddr, | 553 | .fl4_src = saddr, |
554 | .saddr = saddr, | 554 | .fl4_tos = tos, |
555 | .tos = tos } }, | ||
556 | .proto = inet->hdrincl ? IPPROTO_RAW : | 555 | .proto = inet->hdrincl ? IPPROTO_RAW : |
557 | sk->sk_protocol, | 556 | sk->sk_protocol, |
558 | }; | 557 | }; |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 93bfd95584f4..351dc4e85242 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -139,20 +139,26 @@ static unsigned long expires_ljiffies; | |||
139 | */ | 139 | */ |
140 | 140 | ||
141 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); | 141 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); |
142 | static unsigned int ipv4_default_advmss(const struct dst_entry *dst); | ||
143 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst); | ||
142 | static void ipv4_dst_destroy(struct dst_entry *dst); | 144 | static void ipv4_dst_destroy(struct dst_entry *dst); |
143 | static void ipv4_dst_ifdown(struct dst_entry *dst, | ||
144 | struct net_device *dev, int how); | ||
145 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); | 145 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); |
146 | static void ipv4_link_failure(struct sk_buff *skb); | 146 | static void ipv4_link_failure(struct sk_buff *skb); |
147 | static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | 147 | static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); |
148 | static int rt_garbage_collect(struct dst_ops *ops); | 148 | static int rt_garbage_collect(struct dst_ops *ops); |
149 | 149 | ||
150 | static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | ||
151 | int how) | ||
152 | { | ||
153 | } | ||
150 | 154 | ||
151 | static struct dst_ops ipv4_dst_ops = { | 155 | static struct dst_ops ipv4_dst_ops = { |
152 | .family = AF_INET, | 156 | .family = AF_INET, |
153 | .protocol = cpu_to_be16(ETH_P_IP), | 157 | .protocol = cpu_to_be16(ETH_P_IP), |
154 | .gc = rt_garbage_collect, | 158 | .gc = rt_garbage_collect, |
155 | .check = ipv4_dst_check, | 159 | .check = ipv4_dst_check, |
160 | .default_advmss = ipv4_default_advmss, | ||
161 | .default_mtu = ipv4_default_mtu, | ||
156 | .destroy = ipv4_dst_destroy, | 162 | .destroy = ipv4_dst_destroy, |
157 | .ifdown = ipv4_dst_ifdown, | 163 | .ifdown = ipv4_dst_ifdown, |
158 | .negative_advice = ipv4_negative_advice, | 164 | .negative_advice = ipv4_negative_advice, |
@@ -381,8 +387,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
381 | (__force u32)r->rt_gateway, | 387 | (__force u32)r->rt_gateway, |
382 | r->rt_flags, atomic_read(&r->dst.__refcnt), | 388 | r->rt_flags, atomic_read(&r->dst.__refcnt), |
383 | r->dst.__use, 0, (__force u32)r->rt_src, | 389 | r->dst.__use, 0, (__force u32)r->rt_src, |
384 | (dst_metric(&r->dst, RTAX_ADVMSS) ? | 390 | dst_metric_advmss(&r->dst) + 40, |
385 | (int)dst_metric(&r->dst, RTAX_ADVMSS) + 40 : 0), | ||
386 | dst_metric(&r->dst, RTAX_WINDOW), | 391 | dst_metric(&r->dst, RTAX_WINDOW), |
387 | (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) + | 392 | (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) + |
388 | dst_metric(&r->dst, RTAX_RTTVAR)), | 393 | dst_metric(&r->dst, RTAX_RTTVAR)), |
@@ -621,7 +626,7 @@ static inline int rt_fast_clean(struct rtable *rth) | |||
621 | /* Kill broadcast/multicast entries very aggresively, if they | 626 | /* Kill broadcast/multicast entries very aggresively, if they |
622 | collide in hash table with more useful entries */ | 627 | collide in hash table with more useful entries */ |
623 | return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && | 628 | return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && |
624 | rth->fl.iif && rth->dst.rt_next; | 629 | rt_is_input_route(rth) && rth->dst.rt_next; |
625 | } | 630 | } |
626 | 631 | ||
627 | static inline int rt_valuable(struct rtable *rth) | 632 | static inline int rt_valuable(struct rtable *rth) |
@@ -666,7 +671,7 @@ static inline u32 rt_score(struct rtable *rt) | |||
666 | if (rt_valuable(rt)) | 671 | if (rt_valuable(rt)) |
667 | score |= (1<<31); | 672 | score |= (1<<31); |
668 | 673 | ||
669 | if (!rt->fl.iif || | 674 | if (rt_is_output_route(rt) || |
670 | !(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL))) | 675 | !(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL))) |
671 | score |= (1<<30); | 676 | score |= (1<<30); |
672 | 677 | ||
@@ -682,17 +687,17 @@ static inline bool rt_caching(const struct net *net) | |||
682 | static inline bool compare_hash_inputs(const struct flowi *fl1, | 687 | static inline bool compare_hash_inputs(const struct flowi *fl1, |
683 | const struct flowi *fl2) | 688 | const struct flowi *fl2) |
684 | { | 689 | { |
685 | return ((((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) | | 690 | return ((((__force u32)fl1->fl4_dst ^ (__force u32)fl2->fl4_dst) | |
686 | ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) | | 691 | ((__force u32)fl1->fl4_src ^ (__force u32)fl2->fl4_src) | |
687 | (fl1->iif ^ fl2->iif)) == 0); | 692 | (fl1->iif ^ fl2->iif)) == 0); |
688 | } | 693 | } |
689 | 694 | ||
690 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | 695 | static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) |
691 | { | 696 | { |
692 | return (((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) | | 697 | return (((__force u32)fl1->fl4_dst ^ (__force u32)fl2->fl4_dst) | |
693 | ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) | | 698 | ((__force u32)fl1->fl4_src ^ (__force u32)fl2->fl4_src) | |
694 | (fl1->mark ^ fl2->mark) | | 699 | (fl1->mark ^ fl2->mark) | |
695 | (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) | | 700 | (*(u16 *)&fl1->fl4_tos ^ *(u16 *)&fl2->fl4_tos) | |
696 | (fl1->oif ^ fl2->oif) | | 701 | (fl1->oif ^ fl2->oif) | |
697 | (fl1->iif ^ fl2->iif)) == 0; | 702 | (fl1->iif ^ fl2->iif)) == 0; |
698 | } | 703 | } |
@@ -712,13 +717,15 @@ static inline int rt_is_expired(struct rtable *rth) | |||
712 | * Can be called by a softirq or a process. | 717 | * Can be called by a softirq or a process. |
713 | * In the later case, we want to be reschedule if necessary | 718 | * In the later case, we want to be reschedule if necessary |
714 | */ | 719 | */ |
715 | static void rt_do_flush(int process_context) | 720 | static void rt_do_flush(struct net *net, int process_context) |
716 | { | 721 | { |
717 | unsigned int i; | 722 | unsigned int i; |
718 | struct rtable *rth, *next; | 723 | struct rtable *rth, *next; |
719 | struct rtable * tail; | ||
720 | 724 | ||
721 | for (i = 0; i <= rt_hash_mask; i++) { | 725 | for (i = 0; i <= rt_hash_mask; i++) { |
726 | struct rtable __rcu **pprev; | ||
727 | struct rtable *list; | ||
728 | |||
722 | if (process_context && need_resched()) | 729 | if (process_context && need_resched()) |
723 | cond_resched(); | 730 | cond_resched(); |
724 | rth = rcu_dereference_raw(rt_hash_table[i].chain); | 731 | rth = rcu_dereference_raw(rt_hash_table[i].chain); |
@@ -726,50 +733,32 @@ static void rt_do_flush(int process_context) | |||
726 | continue; | 733 | continue; |
727 | 734 | ||
728 | spin_lock_bh(rt_hash_lock_addr(i)); | 735 | spin_lock_bh(rt_hash_lock_addr(i)); |
729 | #ifdef CONFIG_NET_NS | ||
730 | { | ||
731 | struct rtable __rcu **prev; | ||
732 | struct rtable *p; | ||
733 | 736 | ||
734 | rth = rcu_dereference_protected(rt_hash_table[i].chain, | 737 | list = NULL; |
738 | pprev = &rt_hash_table[i].chain; | ||
739 | rth = rcu_dereference_protected(*pprev, | ||
735 | lockdep_is_held(rt_hash_lock_addr(i))); | 740 | lockdep_is_held(rt_hash_lock_addr(i))); |
736 | 741 | ||
737 | /* defer releasing the head of the list after spin_unlock */ | 742 | while (rth) { |
738 | for (tail = rth; tail; | 743 | next = rcu_dereference_protected(rth->dst.rt_next, |
739 | tail = rcu_dereference_protected(tail->dst.rt_next, | ||
740 | lockdep_is_held(rt_hash_lock_addr(i)))) | ||
741 | if (!rt_is_expired(tail)) | ||
742 | break; | ||
743 | if (rth != tail) | ||
744 | rt_hash_table[i].chain = tail; | ||
745 | |||
746 | /* call rt_free on entries after the tail requiring flush */ | ||
747 | prev = &rt_hash_table[i].chain; | ||
748 | for (p = rcu_dereference_protected(*prev, | ||
749 | lockdep_is_held(rt_hash_lock_addr(i))); | ||
750 | p != NULL; | ||
751 | p = next) { | ||
752 | next = rcu_dereference_protected(p->dst.rt_next, | ||
753 | lockdep_is_held(rt_hash_lock_addr(i))); | 744 | lockdep_is_held(rt_hash_lock_addr(i))); |
754 | if (!rt_is_expired(p)) { | 745 | |
755 | prev = &p->dst.rt_next; | 746 | if (!net || |
747 | net_eq(dev_net(rth->dst.dev), net)) { | ||
748 | rcu_assign_pointer(*pprev, next); | ||
749 | rcu_assign_pointer(rth->dst.rt_next, list); | ||
750 | list = rth; | ||
756 | } else { | 751 | } else { |
757 | *prev = next; | 752 | pprev = &rth->dst.rt_next; |
758 | rt_free(p); | ||
759 | } | 753 | } |
754 | rth = next; | ||
760 | } | 755 | } |
761 | } | 756 | |
762 | #else | ||
763 | rth = rcu_dereference_protected(rt_hash_table[i].chain, | ||
764 | lockdep_is_held(rt_hash_lock_addr(i))); | ||
765 | rcu_assign_pointer(rt_hash_table[i].chain, NULL); | ||
766 | tail = NULL; | ||
767 | #endif | ||
768 | spin_unlock_bh(rt_hash_lock_addr(i)); | 757 | spin_unlock_bh(rt_hash_lock_addr(i)); |
769 | 758 | ||
770 | for (; rth != tail; rth = next) { | 759 | for (; list; list = next) { |
771 | next = rcu_dereference_protected(rth->dst.rt_next, 1); | 760 | next = rcu_dereference_protected(list->dst.rt_next, 1); |
772 | rt_free(rth); | 761 | rt_free(list); |
773 | } | 762 | } |
774 | } | 763 | } |
775 | } | 764 | } |
@@ -917,13 +906,13 @@ void rt_cache_flush(struct net *net, int delay) | |||
917 | { | 906 | { |
918 | rt_cache_invalidate(net); | 907 | rt_cache_invalidate(net); |
919 | if (delay >= 0) | 908 | if (delay >= 0) |
920 | rt_do_flush(!in_softirq()); | 909 | rt_do_flush(net, !in_softirq()); |
921 | } | 910 | } |
922 | 911 | ||
923 | /* Flush previous cache invalidated entries from the cache */ | 912 | /* Flush previous cache invalidated entries from the cache */ |
924 | void rt_cache_flush_batch(void) | 913 | void rt_cache_flush_batch(struct net *net) |
925 | { | 914 | { |
926 | rt_do_flush(!in_softirq()); | 915 | rt_do_flush(net, !in_softirq()); |
927 | } | 916 | } |
928 | 917 | ||
929 | static void rt_emergency_hash_rebuild(struct net *net) | 918 | static void rt_emergency_hash_rebuild(struct net *net) |
@@ -1124,7 +1113,7 @@ restart: | |||
1124 | */ | 1113 | */ |
1125 | 1114 | ||
1126 | rt->dst.flags |= DST_NOCACHE; | 1115 | rt->dst.flags |= DST_NOCACHE; |
1127 | if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) { | 1116 | if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { |
1128 | int err = arp_bind_neighbour(&rt->dst); | 1117 | int err = arp_bind_neighbour(&rt->dst); |
1129 | if (err) { | 1118 | if (err) { |
1130 | if (net_ratelimit()) | 1119 | if (net_ratelimit()) |
@@ -1222,7 +1211,7 @@ restart: | |||
1222 | /* Try to bind route to arp only if it is output | 1211 | /* Try to bind route to arp only if it is output |
1223 | route or unicast forwarding path. | 1212 | route or unicast forwarding path. |
1224 | */ | 1213 | */ |
1225 | if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) { | 1214 | if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { |
1226 | int err = arp_bind_neighbour(&rt->dst); | 1215 | int err = arp_bind_neighbour(&rt->dst); |
1227 | if (err) { | 1216 | if (err) { |
1228 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1217 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
@@ -1287,7 +1276,7 @@ void rt_bind_peer(struct rtable *rt, int create) | |||
1287 | { | 1276 | { |
1288 | struct inet_peer *peer; | 1277 | struct inet_peer *peer; |
1289 | 1278 | ||
1290 | peer = inet_getpeer(rt->rt_dst, create); | 1279 | peer = inet_getpeer_v4(rt->rt_dst, create); |
1291 | 1280 | ||
1292 | if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) | 1281 | if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) |
1293 | inet_putpeer(peer); | 1282 | inet_putpeer(peer); |
@@ -1404,7 +1393,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1404 | if (rth->fl.fl4_dst != daddr || | 1393 | if (rth->fl.fl4_dst != daddr || |
1405 | rth->fl.fl4_src != skeys[i] || | 1394 | rth->fl.fl4_src != skeys[i] || |
1406 | rth->fl.oif != ikeys[k] || | 1395 | rth->fl.oif != ikeys[k] || |
1407 | rth->fl.iif != 0 || | 1396 | rt_is_input_route(rth) || |
1408 | rt_is_expired(rth) || | 1397 | rt_is_expired(rth) || |
1409 | !net_eq(dev_net(rth->dst.dev), net)) { | 1398 | !net_eq(dev_net(rth->dst.dev), net)) { |
1410 | rthp = &rth->dst.rt_next; | 1399 | rthp = &rth->dst.rt_next; |
@@ -1433,8 +1422,6 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1433 | rt->dst.child = NULL; | 1422 | rt->dst.child = NULL; |
1434 | if (rt->dst.dev) | 1423 | if (rt->dst.dev) |
1435 | dev_hold(rt->dst.dev); | 1424 | dev_hold(rt->dst.dev); |
1436 | if (rt->idev) | ||
1437 | in_dev_hold(rt->idev); | ||
1438 | rt->dst.obsolete = -1; | 1425 | rt->dst.obsolete = -1; |
1439 | rt->dst.lastuse = jiffies; | 1426 | rt->dst.lastuse = jiffies; |
1440 | rt->dst.path = &rt->dst; | 1427 | rt->dst.path = &rt->dst; |
@@ -1666,7 +1653,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, | |||
1666 | rth->rt_dst != daddr || | 1653 | rth->rt_dst != daddr || |
1667 | rth->rt_src != iph->saddr || | 1654 | rth->rt_src != iph->saddr || |
1668 | rth->fl.oif != ikeys[k] || | 1655 | rth->fl.oif != ikeys[k] || |
1669 | rth->fl.iif != 0 || | 1656 | rt_is_input_route(rth) || |
1670 | dst_metric_locked(&rth->dst, RTAX_MTU) || | 1657 | dst_metric_locked(&rth->dst, RTAX_MTU) || |
1671 | !net_eq(dev_net(rth->dst.dev), net) || | 1658 | !net_eq(dev_net(rth->dst.dev), net) || |
1672 | rt_is_expired(rth)) | 1659 | rt_is_expired(rth)) |
@@ -1686,11 +1673,14 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, | |||
1686 | if (mtu < dst_mtu(&rth->dst)) { | 1673 | if (mtu < dst_mtu(&rth->dst)) { |
1687 | dst_confirm(&rth->dst); | 1674 | dst_confirm(&rth->dst); |
1688 | if (mtu < ip_rt_min_pmtu) { | 1675 | if (mtu < ip_rt_min_pmtu) { |
1676 | u32 lock = dst_metric(&rth->dst, | ||
1677 | RTAX_LOCK); | ||
1689 | mtu = ip_rt_min_pmtu; | 1678 | mtu = ip_rt_min_pmtu; |
1690 | rth->dst.metrics[RTAX_LOCK-1] |= | 1679 | lock |= (1 << RTAX_MTU); |
1691 | (1 << RTAX_MTU); | 1680 | dst_metric_set(&rth->dst, RTAX_LOCK, |
1681 | lock); | ||
1692 | } | 1682 | } |
1693 | rth->dst.metrics[RTAX_MTU-1] = mtu; | 1683 | dst_metric_set(&rth->dst, RTAX_MTU, mtu); |
1694 | dst_set_expires(&rth->dst, | 1684 | dst_set_expires(&rth->dst, |
1695 | ip_rt_mtu_expires); | 1685 | ip_rt_mtu_expires); |
1696 | } | 1686 | } |
@@ -1708,10 +1698,11 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1708 | if (dst_mtu(dst) > mtu && mtu >= 68 && | 1698 | if (dst_mtu(dst) > mtu && mtu >= 68 && |
1709 | !(dst_metric_locked(dst, RTAX_MTU))) { | 1699 | !(dst_metric_locked(dst, RTAX_MTU))) { |
1710 | if (mtu < ip_rt_min_pmtu) { | 1700 | if (mtu < ip_rt_min_pmtu) { |
1701 | u32 lock = dst_metric(dst, RTAX_LOCK); | ||
1711 | mtu = ip_rt_min_pmtu; | 1702 | mtu = ip_rt_min_pmtu; |
1712 | dst->metrics[RTAX_LOCK-1] |= (1 << RTAX_MTU); | 1703 | dst_metric_set(dst, RTAX_LOCK, lock | (1 << RTAX_MTU)); |
1713 | } | 1704 | } |
1714 | dst->metrics[RTAX_MTU-1] = mtu; | 1705 | dst_metric_set(dst, RTAX_MTU, mtu); |
1715 | dst_set_expires(dst, ip_rt_mtu_expires); | 1706 | dst_set_expires(dst, ip_rt_mtu_expires); |
1716 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | 1707 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); |
1717 | } | 1708 | } |
@@ -1728,33 +1719,13 @@ static void ipv4_dst_destroy(struct dst_entry *dst) | |||
1728 | { | 1719 | { |
1729 | struct rtable *rt = (struct rtable *) dst; | 1720 | struct rtable *rt = (struct rtable *) dst; |
1730 | struct inet_peer *peer = rt->peer; | 1721 | struct inet_peer *peer = rt->peer; |
1731 | struct in_device *idev = rt->idev; | ||
1732 | 1722 | ||
1733 | if (peer) { | 1723 | if (peer) { |
1734 | rt->peer = NULL; | 1724 | rt->peer = NULL; |
1735 | inet_putpeer(peer); | 1725 | inet_putpeer(peer); |
1736 | } | 1726 | } |
1737 | |||
1738 | if (idev) { | ||
1739 | rt->idev = NULL; | ||
1740 | in_dev_put(idev); | ||
1741 | } | ||
1742 | } | 1727 | } |
1743 | 1728 | ||
1744 | static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | ||
1745 | int how) | ||
1746 | { | ||
1747 | struct rtable *rt = (struct rtable *) dst; | ||
1748 | struct in_device *idev = rt->idev; | ||
1749 | if (dev != dev_net(dev)->loopback_dev && idev && idev->dev == dev) { | ||
1750 | struct in_device *loopback_idev = | ||
1751 | in_dev_get(dev_net(dev)->loopback_dev); | ||
1752 | if (loopback_idev) { | ||
1753 | rt->idev = loopback_idev; | ||
1754 | in_dev_put(idev); | ||
1755 | } | ||
1756 | } | ||
1757 | } | ||
1758 | 1729 | ||
1759 | static void ipv4_link_failure(struct sk_buff *skb) | 1730 | static void ipv4_link_failure(struct sk_buff *skb) |
1760 | { | 1731 | { |
@@ -1790,7 +1761,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) | |||
1790 | __be32 src; | 1761 | __be32 src; |
1791 | struct fib_result res; | 1762 | struct fib_result res; |
1792 | 1763 | ||
1793 | if (rt->fl.iif == 0) | 1764 | if (rt_is_output_route(rt)) |
1794 | src = rt->rt_src; | 1765 | src = rt->rt_src; |
1795 | else { | 1766 | else { |
1796 | rcu_read_lock(); | 1767 | rcu_read_lock(); |
@@ -1814,38 +1785,55 @@ static void set_class_tag(struct rtable *rt, u32 tag) | |||
1814 | } | 1785 | } |
1815 | #endif | 1786 | #endif |
1816 | 1787 | ||
1788 | static unsigned int ipv4_default_advmss(const struct dst_entry *dst) | ||
1789 | { | ||
1790 | unsigned int advmss = dst_metric_raw(dst, RTAX_ADVMSS); | ||
1791 | |||
1792 | if (advmss == 0) { | ||
1793 | advmss = max_t(unsigned int, dst->dev->mtu - 40, | ||
1794 | ip_rt_min_advmss); | ||
1795 | if (advmss > 65535 - 40) | ||
1796 | advmss = 65535 - 40; | ||
1797 | } | ||
1798 | return advmss; | ||
1799 | } | ||
1800 | |||
1801 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst) | ||
1802 | { | ||
1803 | unsigned int mtu = dst->dev->mtu; | ||
1804 | |||
1805 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { | ||
1806 | const struct rtable *rt = (const struct rtable *) dst; | ||
1807 | |||
1808 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) | ||
1809 | mtu = 576; | ||
1810 | } | ||
1811 | |||
1812 | if (mtu > IP_MAX_MTU) | ||
1813 | mtu = IP_MAX_MTU; | ||
1814 | |||
1815 | return mtu; | ||
1816 | } | ||
1817 | |||
1817 | static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) | 1818 | static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) |
1818 | { | 1819 | { |
1820 | struct dst_entry *dst = &rt->dst; | ||
1819 | struct fib_info *fi = res->fi; | 1821 | struct fib_info *fi = res->fi; |
1820 | 1822 | ||
1821 | if (fi) { | 1823 | if (fi) { |
1822 | if (FIB_RES_GW(*res) && | 1824 | if (FIB_RES_GW(*res) && |
1823 | FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) | 1825 | FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) |
1824 | rt->rt_gateway = FIB_RES_GW(*res); | 1826 | rt->rt_gateway = FIB_RES_GW(*res); |
1825 | memcpy(rt->dst.metrics, fi->fib_metrics, | 1827 | dst_import_metrics(dst, fi->fib_metrics); |
1826 | sizeof(rt->dst.metrics)); | ||
1827 | if (fi->fib_mtu == 0) { | ||
1828 | rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu; | ||
1829 | if (dst_metric_locked(&rt->dst, RTAX_MTU) && | ||
1830 | rt->rt_gateway != rt->rt_dst && | ||
1831 | rt->dst.dev->mtu > 576) | ||
1832 | rt->dst.metrics[RTAX_MTU-1] = 576; | ||
1833 | } | ||
1834 | #ifdef CONFIG_NET_CLS_ROUTE | 1828 | #ifdef CONFIG_NET_CLS_ROUTE |
1835 | rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid; | 1829 | dst->tclassid = FIB_RES_NH(*res).nh_tclassid; |
1836 | #endif | 1830 | #endif |
1837 | } else | 1831 | } |
1838 | rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu; | 1832 | |
1839 | 1833 | if (dst_mtu(dst) > IP_MAX_MTU) | |
1840 | if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0) | 1834 | dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU); |
1841 | rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl; | 1835 | if (dst_metric_raw(dst, RTAX_ADVMSS) > 65535 - 40) |
1842 | if (dst_mtu(&rt->dst) > IP_MAX_MTU) | 1836 | dst_metric_set(dst, RTAX_ADVMSS, 65535 - 40); |
1843 | rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU; | ||
1844 | if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0) | ||
1845 | rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40, | ||
1846 | ip_rt_min_advmss); | ||
1847 | if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40) | ||
1848 | rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40; | ||
1849 | 1837 | ||
1850 | #ifdef CONFIG_NET_CLS_ROUTE | 1838 | #ifdef CONFIG_NET_CLS_ROUTE |
1851 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 1839 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
@@ -1910,7 +1898,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1910 | rth->fl.iif = dev->ifindex; | 1898 | rth->fl.iif = dev->ifindex; |
1911 | rth->dst.dev = init_net.loopback_dev; | 1899 | rth->dst.dev = init_net.loopback_dev; |
1912 | dev_hold(rth->dst.dev); | 1900 | dev_hold(rth->dst.dev); |
1913 | rth->idev = in_dev_get(rth->dst.dev); | ||
1914 | rth->fl.oif = 0; | 1901 | rth->fl.oif = 0; |
1915 | rth->rt_gateway = daddr; | 1902 | rth->rt_gateway = daddr; |
1916 | rth->rt_spec_dst= spec_dst; | 1903 | rth->rt_spec_dst= spec_dst; |
@@ -2050,7 +2037,6 @@ static int __mkroute_input(struct sk_buff *skb, | |||
2050 | rth->fl.iif = in_dev->dev->ifindex; | 2037 | rth->fl.iif = in_dev->dev->ifindex; |
2051 | rth->dst.dev = (out_dev)->dev; | 2038 | rth->dst.dev = (out_dev)->dev; |
2052 | dev_hold(rth->dst.dev); | 2039 | dev_hold(rth->dst.dev); |
2053 | rth->idev = in_dev_get(rth->dst.dev); | ||
2054 | rth->fl.oif = 0; | 2040 | rth->fl.oif = 0; |
2055 | rth->rt_spec_dst= spec_dst; | 2041 | rth->rt_spec_dst= spec_dst; |
2056 | 2042 | ||
@@ -2111,12 +2097,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2111 | { | 2097 | { |
2112 | struct fib_result res; | 2098 | struct fib_result res; |
2113 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 2099 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
2114 | struct flowi fl = { .nl_u = { .ip4_u = | 2100 | struct flowi fl = { .fl4_dst = daddr, |
2115 | { .daddr = daddr, | 2101 | .fl4_src = saddr, |
2116 | .saddr = saddr, | 2102 | .fl4_tos = tos, |
2117 | .tos = tos, | 2103 | .fl4_scope = RT_SCOPE_UNIVERSE, |
2118 | .scope = RT_SCOPE_UNIVERSE, | ||
2119 | } }, | ||
2120 | .mark = skb->mark, | 2104 | .mark = skb->mark, |
2121 | .iif = dev->ifindex }; | 2105 | .iif = dev->ifindex }; |
2122 | unsigned flags = 0; | 2106 | unsigned flags = 0; |
@@ -2231,7 +2215,6 @@ local_input: | |||
2231 | rth->fl.iif = dev->ifindex; | 2215 | rth->fl.iif = dev->ifindex; |
2232 | rth->dst.dev = net->loopback_dev; | 2216 | rth->dst.dev = net->loopback_dev; |
2233 | dev_hold(rth->dst.dev); | 2217 | dev_hold(rth->dst.dev); |
2234 | rth->idev = in_dev_get(rth->dst.dev); | ||
2235 | rth->rt_gateway = daddr; | 2218 | rth->rt_gateway = daddr; |
2236 | rth->rt_spec_dst= spec_dst; | 2219 | rth->rt_spec_dst= spec_dst; |
2237 | rth->dst.input= ip_local_deliver; | 2220 | rth->dst.input= ip_local_deliver; |
@@ -2417,9 +2400,6 @@ static int __mkroute_output(struct rtable **result, | |||
2417 | if (!rth) | 2400 | if (!rth) |
2418 | return -ENOBUFS; | 2401 | return -ENOBUFS; |
2419 | 2402 | ||
2420 | in_dev_hold(in_dev); | ||
2421 | rth->idev = in_dev; | ||
2422 | |||
2423 | atomic_set(&rth->dst.__refcnt, 1); | 2403 | atomic_set(&rth->dst.__refcnt, 1); |
2424 | rth->dst.flags= DST_HOST; | 2404 | rth->dst.flags= DST_HOST; |
2425 | if (IN_DEV_CONF_GET(in_dev, NOXFRM)) | 2405 | if (IN_DEV_CONF_GET(in_dev, NOXFRM)) |
@@ -2506,14 +2486,11 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2506 | const struct flowi *oldflp) | 2486 | const struct flowi *oldflp) |
2507 | { | 2487 | { |
2508 | u32 tos = RT_FL_TOS(oldflp); | 2488 | u32 tos = RT_FL_TOS(oldflp); |
2509 | struct flowi fl = { .nl_u = { .ip4_u = | 2489 | struct flowi fl = { .fl4_dst = oldflp->fl4_dst, |
2510 | { .daddr = oldflp->fl4_dst, | 2490 | .fl4_src = oldflp->fl4_src, |
2511 | .saddr = oldflp->fl4_src, | 2491 | .fl4_tos = tos & IPTOS_RT_MASK, |
2512 | .tos = tos & IPTOS_RT_MASK, | 2492 | .fl4_scope = ((tos & RTO_ONLINK) ? |
2513 | .scope = ((tos & RTO_ONLINK) ? | 2493 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE), |
2514 | RT_SCOPE_LINK : | ||
2515 | RT_SCOPE_UNIVERSE), | ||
2516 | } }, | ||
2517 | .mark = oldflp->mark, | 2494 | .mark = oldflp->mark, |
2518 | .iif = net->loopback_dev->ifindex, | 2495 | .iif = net->loopback_dev->ifindex, |
2519 | .oif = oldflp->oif }; | 2496 | .oif = oldflp->oif }; |
@@ -2700,7 +2677,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, | |||
2700 | rth = rcu_dereference_bh(rth->dst.rt_next)) { | 2677 | rth = rcu_dereference_bh(rth->dst.rt_next)) { |
2701 | if (rth->fl.fl4_dst == flp->fl4_dst && | 2678 | if (rth->fl.fl4_dst == flp->fl4_dst && |
2702 | rth->fl.fl4_src == flp->fl4_src && | 2679 | rth->fl.fl4_src == flp->fl4_src && |
2703 | rth->fl.iif == 0 && | 2680 | rt_is_output_route(rth) && |
2704 | rth->fl.oif == flp->oif && | 2681 | rth->fl.oif == flp->oif && |
2705 | rth->fl.mark == flp->mark && | 2682 | rth->fl.mark == flp->mark && |
2706 | !((rth->fl.fl4_tos ^ flp->fl4_tos) & | 2683 | !((rth->fl.fl4_tos ^ flp->fl4_tos) & |
@@ -2756,7 +2733,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi | |||
2756 | new->__use = 1; | 2733 | new->__use = 1; |
2757 | new->input = dst_discard; | 2734 | new->input = dst_discard; |
2758 | new->output = dst_discard; | 2735 | new->output = dst_discard; |
2759 | memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); | 2736 | dst_copy_metrics(new, &ort->dst); |
2760 | 2737 | ||
2761 | new->dev = ort->dst.dev; | 2738 | new->dev = ort->dst.dev; |
2762 | if (new->dev) | 2739 | if (new->dev) |
@@ -2764,9 +2741,6 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi | |||
2764 | 2741 | ||
2765 | rt->fl = ort->fl; | 2742 | rt->fl = ort->fl; |
2766 | 2743 | ||
2767 | rt->idev = ort->idev; | ||
2768 | if (rt->idev) | ||
2769 | in_dev_hold(rt->idev); | ||
2770 | rt->rt_genid = rt_genid(net); | 2744 | rt->rt_genid = rt_genid(net); |
2771 | rt->rt_flags = ort->rt_flags; | 2745 | rt->rt_flags = ort->rt_flags; |
2772 | rt->rt_type = ort->rt_type; | 2746 | rt->rt_type = ort->rt_type; |
@@ -2858,7 +2832,7 @@ static int rt_fill_info(struct net *net, | |||
2858 | if (rt->dst.tclassid) | 2832 | if (rt->dst.tclassid) |
2859 | NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid); | 2833 | NLA_PUT_U32(skb, RTA_FLOW, rt->dst.tclassid); |
2860 | #endif | 2834 | #endif |
2861 | if (rt->fl.iif) | 2835 | if (rt_is_input_route(rt)) |
2862 | NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst); | 2836 | NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst); |
2863 | else if (rt->rt_src != rt->fl.fl4_src) | 2837 | else if (rt->rt_src != rt->fl.fl4_src) |
2864 | NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_src); | 2838 | NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_src); |
@@ -2866,7 +2840,7 @@ static int rt_fill_info(struct net *net, | |||
2866 | if (rt->rt_dst != rt->rt_gateway) | 2840 | if (rt->rt_dst != rt->rt_gateway) |
2867 | NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway); | 2841 | NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway); |
2868 | 2842 | ||
2869 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) | 2843 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2870 | goto nla_put_failure; | 2844 | goto nla_put_failure; |
2871 | 2845 | ||
2872 | if (rt->fl.mark) | 2846 | if (rt->fl.mark) |
@@ -2883,7 +2857,7 @@ static int rt_fill_info(struct net *net, | |||
2883 | } | 2857 | } |
2884 | } | 2858 | } |
2885 | 2859 | ||
2886 | if (rt->fl.iif) { | 2860 | if (rt_is_input_route(rt)) { |
2887 | #ifdef CONFIG_IP_MROUTE | 2861 | #ifdef CONFIG_IP_MROUTE |
2888 | __be32 dst = rt->rt_dst; | 2862 | __be32 dst = rt->rt_dst; |
2889 | 2863 | ||
@@ -2978,13 +2952,9 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2978 | err = -rt->dst.error; | 2952 | err = -rt->dst.error; |
2979 | } else { | 2953 | } else { |
2980 | struct flowi fl = { | 2954 | struct flowi fl = { |
2981 | .nl_u = { | 2955 | .fl4_dst = dst, |
2982 | .ip4_u = { | 2956 | .fl4_src = src, |
2983 | .daddr = dst, | 2957 | .fl4_tos = rtm->rtm_tos, |
2984 | .saddr = src, | ||
2985 | .tos = rtm->rtm_tos, | ||
2986 | }, | ||
2987 | }, | ||
2988 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | 2958 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, |
2989 | .mark = mark, | 2959 | .mark = mark, |
2990 | }; | 2960 | }; |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 650cace2180d..47519205a014 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -346,17 +346,14 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
346 | */ | 346 | */ |
347 | { | 347 | { |
348 | struct flowi fl = { .mark = sk->sk_mark, | 348 | struct flowi fl = { .mark = sk->sk_mark, |
349 | .nl_u = { .ip4_u = | 349 | .fl4_dst = ((opt && opt->srr) ? |
350 | { .daddr = ((opt && opt->srr) ? | 350 | opt->faddr : ireq->rmt_addr), |
351 | opt->faddr : | 351 | .fl4_src = ireq->loc_addr, |
352 | ireq->rmt_addr), | 352 | .fl4_tos = RT_CONN_FLAGS(sk), |
353 | .saddr = ireq->loc_addr, | ||
354 | .tos = RT_CONN_FLAGS(sk) } }, | ||
355 | .proto = IPPROTO_TCP, | 353 | .proto = IPPROTO_TCP, |
356 | .flags = inet_sk_flowi_flags(sk), | 354 | .flags = inet_sk_flowi_flags(sk), |
357 | .uli_u = { .ports = | 355 | .fl_ip_sport = th->dest, |
358 | { .sport = th->dest, | 356 | .fl_ip_dport = th->source }; |
359 | .dport = th->source } } }; | ||
360 | security_req_classify_flow(req, &fl); | 357 | security_req_classify_flow(req, &fl); |
361 | if (ip_route_output_key(sock_net(sk), &rt, &fl)) { | 358 | if (ip_route_output_key(sock_net(sk), &rt, &fl)) { |
362 | reqsk_free(req); | 359 | reqsk_free(req); |
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1b4ec21497a4..1a456652086b 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -28,6 +28,8 @@ static int ip_local_port_range_min[] = { 1, 1 }; | |||
28 | static int ip_local_port_range_max[] = { 65535, 65535 }; | 28 | static int ip_local_port_range_max[] = { 65535, 65535 }; |
29 | static int tcp_adv_win_scale_min = -31; | 29 | static int tcp_adv_win_scale_min = -31; |
30 | static int tcp_adv_win_scale_max = 31; | 30 | static int tcp_adv_win_scale_max = 31; |
31 | static int ip_ttl_min = 1; | ||
32 | static int ip_ttl_max = 255; | ||
31 | 33 | ||
32 | /* Update system visible IP port range */ | 34 | /* Update system visible IP port range */ |
33 | static void set_local_port_range(int range[2]) | 35 | static void set_local_port_range(int range[2]) |
@@ -155,8 +157,9 @@ static struct ctl_table ipv4_table[] = { | |||
155 | .data = &sysctl_ip_default_ttl, | 157 | .data = &sysctl_ip_default_ttl, |
156 | .maxlen = sizeof(int), | 158 | .maxlen = sizeof(int), |
157 | .mode = 0644, | 159 | .mode = 0644, |
158 | .proc_handler = ipv4_doint_and_flush, | 160 | .proc_handler = proc_dointvec_minmax, |
159 | .extra2 = &init_net, | 161 | .extra1 = &ip_ttl_min, |
162 | .extra2 = &ip_ttl_max, | ||
160 | }, | 163 | }, |
161 | { | 164 | { |
162 | .procname = "ip_no_pmtu_disc", | 165 | .procname = "ip_no_pmtu_disc", |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f15c36a706ec..6c11eece262c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1193,7 +1193,7 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied) | |||
1193 | struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); | 1193 | struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); |
1194 | 1194 | ||
1195 | WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), | 1195 | WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), |
1196 | KERN_INFO "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", | 1196 | "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", |
1197 | tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); | 1197 | tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); |
1198 | #endif | 1198 | #endif |
1199 | 1199 | ||
@@ -1477,10 +1477,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1477 | * shouldn't happen. | 1477 | * shouldn't happen. |
1478 | */ | 1478 | */ |
1479 | if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), | 1479 | if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), |
1480 | KERN_INFO "recvmsg bug: copied %X " | 1480 | "recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n", |
1481 | "seq %X rcvnxt %X fl %X\n", *seq, | 1481 | *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, |
1482 | TCP_SKB_CB(skb)->seq, tp->rcv_nxt, | 1482 | flags)) |
1483 | flags)) | ||
1484 | break; | 1483 | break; |
1485 | 1484 | ||
1486 | offset = *seq - TCP_SKB_CB(skb)->seq; | 1485 | offset = *seq - TCP_SKB_CB(skb)->seq; |
@@ -1490,10 +1489,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1490 | goto found_ok_skb; | 1489 | goto found_ok_skb; |
1491 | if (tcp_hdr(skb)->fin) | 1490 | if (tcp_hdr(skb)->fin) |
1492 | goto found_fin_ok; | 1491 | goto found_fin_ok; |
1493 | WARN(!(flags & MSG_PEEK), KERN_INFO "recvmsg bug 2: " | 1492 | WARN(!(flags & MSG_PEEK), |
1494 | "copied %X seq %X rcvnxt %X fl %X\n", | 1493 | "recvmsg bug 2: copied %X seq %X rcvnxt %X fl %X\n", |
1495 | *seq, TCP_SKB_CB(skb)->seq, | 1494 | *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags); |
1496 | tp->rcv_nxt, flags); | ||
1497 | } | 1495 | } |
1498 | 1496 | ||
1499 | /* Well, if we have backlog, try to process it now yet. */ | 1497 | /* Well, if we have backlog, try to process it now yet. */ |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6d8ab1c4efc3..2549b29b062d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -734,7 +734,7 @@ void tcp_update_metrics(struct sock *sk) | |||
734 | * Reset our results. | 734 | * Reset our results. |
735 | */ | 735 | */ |
736 | if (!(dst_metric_locked(dst, RTAX_RTT))) | 736 | if (!(dst_metric_locked(dst, RTAX_RTT))) |
737 | dst->metrics[RTAX_RTT - 1] = 0; | 737 | dst_metric_set(dst, RTAX_RTT, 0); |
738 | return; | 738 | return; |
739 | } | 739 | } |
740 | 740 | ||
@@ -776,34 +776,38 @@ void tcp_update_metrics(struct sock *sk) | |||
776 | if (dst_metric(dst, RTAX_SSTHRESH) && | 776 | if (dst_metric(dst, RTAX_SSTHRESH) && |
777 | !dst_metric_locked(dst, RTAX_SSTHRESH) && | 777 | !dst_metric_locked(dst, RTAX_SSTHRESH) && |
778 | (tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH)) | 778 | (tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH)) |
779 | dst->metrics[RTAX_SSTHRESH-1] = tp->snd_cwnd >> 1; | 779 | dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_cwnd >> 1); |
780 | if (!dst_metric_locked(dst, RTAX_CWND) && | 780 | if (!dst_metric_locked(dst, RTAX_CWND) && |
781 | tp->snd_cwnd > dst_metric(dst, RTAX_CWND)) | 781 | tp->snd_cwnd > dst_metric(dst, RTAX_CWND)) |
782 | dst->metrics[RTAX_CWND - 1] = tp->snd_cwnd; | 782 | dst_metric_set(dst, RTAX_CWND, tp->snd_cwnd); |
783 | } else if (tp->snd_cwnd > tp->snd_ssthresh && | 783 | } else if (tp->snd_cwnd > tp->snd_ssthresh && |
784 | icsk->icsk_ca_state == TCP_CA_Open) { | 784 | icsk->icsk_ca_state == TCP_CA_Open) { |
785 | /* Cong. avoidance phase, cwnd is reliable. */ | 785 | /* Cong. avoidance phase, cwnd is reliable. */ |
786 | if (!dst_metric_locked(dst, RTAX_SSTHRESH)) | 786 | if (!dst_metric_locked(dst, RTAX_SSTHRESH)) |
787 | dst->metrics[RTAX_SSTHRESH-1] = | 787 | dst_metric_set(dst, RTAX_SSTHRESH, |
788 | max(tp->snd_cwnd >> 1, tp->snd_ssthresh); | 788 | max(tp->snd_cwnd >> 1, tp->snd_ssthresh)); |
789 | if (!dst_metric_locked(dst, RTAX_CWND)) | 789 | if (!dst_metric_locked(dst, RTAX_CWND)) |
790 | dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_cwnd) >> 1; | 790 | dst_metric_set(dst, RTAX_CWND, |
791 | (dst_metric(dst, RTAX_CWND) + | ||
792 | tp->snd_cwnd) >> 1); | ||
791 | } else { | 793 | } else { |
792 | /* Else slow start did not finish, cwnd is non-sense, | 794 | /* Else slow start did not finish, cwnd is non-sense, |
793 | ssthresh may be also invalid. | 795 | ssthresh may be also invalid. |
794 | */ | 796 | */ |
795 | if (!dst_metric_locked(dst, RTAX_CWND)) | 797 | if (!dst_metric_locked(dst, RTAX_CWND)) |
796 | dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_ssthresh) >> 1; | 798 | dst_metric_set(dst, RTAX_CWND, |
799 | (dst_metric(dst, RTAX_CWND) + | ||
800 | tp->snd_ssthresh) >> 1); | ||
797 | if (dst_metric(dst, RTAX_SSTHRESH) && | 801 | if (dst_metric(dst, RTAX_SSTHRESH) && |
798 | !dst_metric_locked(dst, RTAX_SSTHRESH) && | 802 | !dst_metric_locked(dst, RTAX_SSTHRESH) && |
799 | tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH)) | 803 | tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH)) |
800 | dst->metrics[RTAX_SSTHRESH-1] = tp->snd_ssthresh; | 804 | dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_ssthresh); |
801 | } | 805 | } |
802 | 806 | ||
803 | if (!dst_metric_locked(dst, RTAX_REORDERING)) { | 807 | if (!dst_metric_locked(dst, RTAX_REORDERING)) { |
804 | if (dst_metric(dst, RTAX_REORDERING) < tp->reordering && | 808 | if (dst_metric(dst, RTAX_REORDERING) < tp->reordering && |
805 | tp->reordering != sysctl_tcp_reordering) | 809 | tp->reordering != sysctl_tcp_reordering) |
806 | dst->metrics[RTAX_REORDERING-1] = tp->reordering; | 810 | dst_metric_set(dst, RTAX_REORDERING, tp->reordering); |
807 | } | 811 | } |
808 | } | 812 | } |
809 | } | 813 | } |
@@ -912,25 +916,20 @@ static void tcp_init_metrics(struct sock *sk) | |||
912 | tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk)); | 916 | tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk)); |
913 | } | 917 | } |
914 | tcp_set_rto(sk); | 918 | tcp_set_rto(sk); |
915 | if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp) | 919 | if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp) { |
916 | goto reset; | ||
917 | |||
918 | cwnd: | ||
919 | tp->snd_cwnd = tcp_init_cwnd(tp, dst); | ||
920 | tp->snd_cwnd_stamp = tcp_time_stamp; | ||
921 | return; | ||
922 | |||
923 | reset: | 920 | reset: |
924 | /* Play conservative. If timestamps are not | 921 | /* Play conservative. If timestamps are not |
925 | * supported, TCP will fail to recalculate correct | 922 | * supported, TCP will fail to recalculate correct |
926 | * rtt, if initial rto is too small. FORGET ALL AND RESET! | 923 | * rtt, if initial rto is too small. FORGET ALL AND RESET! |
927 | */ | 924 | */ |
928 | if (!tp->rx_opt.saw_tstamp && tp->srtt) { | 925 | if (!tp->rx_opt.saw_tstamp && tp->srtt) { |
929 | tp->srtt = 0; | 926 | tp->srtt = 0; |
930 | tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_INIT; | 927 | tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_INIT; |
931 | inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT; | 928 | inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT; |
929 | } | ||
932 | } | 930 | } |
933 | goto cwnd; | 931 | tp->snd_cwnd = tcp_init_cwnd(tp, dst); |
932 | tp->snd_cwnd_stamp = tcp_time_stamp; | ||
934 | } | 933 | } |
935 | 934 | ||
936 | static void tcp_update_reordering(struct sock *sk, const int metric, | 935 | static void tcp_update_reordering(struct sock *sk, const int metric, |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d978bb2f748b..856f68466d49 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1210,12 +1210,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { | |||
1210 | }; | 1210 | }; |
1211 | #endif | 1211 | #endif |
1212 | 1212 | ||
1213 | static struct timewait_sock_ops tcp_timewait_sock_ops = { | ||
1214 | .twsk_obj_size = sizeof(struct tcp_timewait_sock), | ||
1215 | .twsk_unique = tcp_twsk_unique, | ||
1216 | .twsk_destructor= tcp_twsk_destructor, | ||
1217 | }; | ||
1218 | |||
1219 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 1213 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
1220 | { | 1214 | { |
1221 | struct tcp_extend_values tmp_ext; | 1215 | struct tcp_extend_values tmp_ext; |
@@ -1347,7 +1341,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1347 | tcp_death_row.sysctl_tw_recycle && | 1341 | tcp_death_row.sysctl_tw_recycle && |
1348 | (dst = inet_csk_route_req(sk, req)) != NULL && | 1342 | (dst = inet_csk_route_req(sk, req)) != NULL && |
1349 | (peer = rt_get_peer((struct rtable *)dst)) != NULL && | 1343 | (peer = rt_get_peer((struct rtable *)dst)) != NULL && |
1350 | peer->v4daddr == saddr) { | 1344 | peer->daddr.a4 == saddr) { |
1351 | inet_peer_refcheck(peer); | 1345 | inet_peer_refcheck(peer); |
1352 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && | 1346 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && |
1353 | (s32)(peer->tcp_ts - req->ts_recent) > | 1347 | (s32)(peer->tcp_ts - req->ts_recent) > |
@@ -1442,7 +1436,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1442 | 1436 | ||
1443 | tcp_mtup_init(newsk); | 1437 | tcp_mtup_init(newsk); |
1444 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1438 | tcp_sync_mss(newsk, dst_mtu(dst)); |
1445 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1439 | newtp->advmss = dst_metric_advmss(dst); |
1446 | if (tcp_sk(sk)->rx_opt.user_mss && | 1440 | if (tcp_sk(sk)->rx_opt.user_mss && |
1447 | tcp_sk(sk)->rx_opt.user_mss < newtp->advmss) | 1441 | tcp_sk(sk)->rx_opt.user_mss < newtp->advmss) |
1448 | newtp->advmss = tcp_sk(sk)->rx_opt.user_mss; | 1442 | newtp->advmss = tcp_sk(sk)->rx_opt.user_mss; |
@@ -1763,64 +1757,40 @@ do_time_wait: | |||
1763 | goto discard_it; | 1757 | goto discard_it; |
1764 | } | 1758 | } |
1765 | 1759 | ||
1766 | /* VJ's idea. Save last timestamp seen from this destination | 1760 | struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it) |
1767 | * and hold it at least for normal timewait interval to use for duplicate | ||
1768 | * segment detection in subsequent connections, before they enter synchronized | ||
1769 | * state. | ||
1770 | */ | ||
1771 | |||
1772 | int tcp_v4_remember_stamp(struct sock *sk) | ||
1773 | { | 1761 | { |
1762 | struct rtable *rt = (struct rtable *) __sk_dst_get(sk); | ||
1774 | struct inet_sock *inet = inet_sk(sk); | 1763 | struct inet_sock *inet = inet_sk(sk); |
1775 | struct tcp_sock *tp = tcp_sk(sk); | 1764 | struct inet_peer *peer; |
1776 | struct rtable *rt = (struct rtable *)__sk_dst_get(sk); | ||
1777 | struct inet_peer *peer = NULL; | ||
1778 | int release_it = 0; | ||
1779 | 1765 | ||
1780 | if (!rt || rt->rt_dst != inet->inet_daddr) { | 1766 | if (!rt || rt->rt_dst != inet->inet_daddr) { |
1781 | peer = inet_getpeer(inet->inet_daddr, 1); | 1767 | peer = inet_getpeer_v4(inet->inet_daddr, 1); |
1782 | release_it = 1; | 1768 | *release_it = true; |
1783 | } else { | 1769 | } else { |
1784 | if (!rt->peer) | 1770 | if (!rt->peer) |
1785 | rt_bind_peer(rt, 1); | 1771 | rt_bind_peer(rt, 1); |
1786 | peer = rt->peer; | 1772 | peer = rt->peer; |
1773 | *release_it = false; | ||
1787 | } | 1774 | } |
1788 | 1775 | ||
1789 | if (peer) { | 1776 | return peer; |
1790 | if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 || | ||
1791 | ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | ||
1792 | peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) { | ||
1793 | peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp; | ||
1794 | peer->tcp_ts = tp->rx_opt.ts_recent; | ||
1795 | } | ||
1796 | if (release_it) | ||
1797 | inet_putpeer(peer); | ||
1798 | return 1; | ||
1799 | } | ||
1800 | |||
1801 | return 0; | ||
1802 | } | 1777 | } |
1803 | EXPORT_SYMBOL(tcp_v4_remember_stamp); | 1778 | EXPORT_SYMBOL(tcp_v4_get_peer); |
1804 | 1779 | ||
1805 | int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) | 1780 | void *tcp_v4_tw_get_peer(struct sock *sk) |
1806 | { | 1781 | { |
1807 | struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1); | 1782 | struct inet_timewait_sock *tw = inet_twsk(sk); |
1808 | |||
1809 | if (peer) { | ||
1810 | const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); | ||
1811 | |||
1812 | if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || | ||
1813 | ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | ||
1814 | peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { | ||
1815 | peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; | ||
1816 | peer->tcp_ts = tcptw->tw_ts_recent; | ||
1817 | } | ||
1818 | inet_putpeer(peer); | ||
1819 | return 1; | ||
1820 | } | ||
1821 | 1783 | ||
1822 | return 0; | 1784 | return inet_getpeer_v4(tw->tw_daddr, 1); |
1823 | } | 1785 | } |
1786 | EXPORT_SYMBOL(tcp_v4_tw_get_peer); | ||
1787 | |||
1788 | static struct timewait_sock_ops tcp_timewait_sock_ops = { | ||
1789 | .twsk_obj_size = sizeof(struct tcp_timewait_sock), | ||
1790 | .twsk_unique = tcp_twsk_unique, | ||
1791 | .twsk_destructor= tcp_twsk_destructor, | ||
1792 | .twsk_getpeer = tcp_v4_tw_get_peer, | ||
1793 | }; | ||
1824 | 1794 | ||
1825 | const struct inet_connection_sock_af_ops ipv4_specific = { | 1795 | const struct inet_connection_sock_af_ops ipv4_specific = { |
1826 | .queue_xmit = ip_queue_xmit, | 1796 | .queue_xmit = ip_queue_xmit, |
@@ -1828,7 +1798,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = { | |||
1828 | .rebuild_header = inet_sk_rebuild_header, | 1798 | .rebuild_header = inet_sk_rebuild_header, |
1829 | .conn_request = tcp_v4_conn_request, | 1799 | .conn_request = tcp_v4_conn_request, |
1830 | .syn_recv_sock = tcp_v4_syn_recv_sock, | 1800 | .syn_recv_sock = tcp_v4_syn_recv_sock, |
1831 | .remember_stamp = tcp_v4_remember_stamp, | 1801 | .get_peer = tcp_v4_get_peer, |
1832 | .net_header_len = sizeof(struct iphdr), | 1802 | .net_header_len = sizeof(struct iphdr), |
1833 | .setsockopt = ip_setsockopt, | 1803 | .setsockopt = ip_setsockopt, |
1834 | .getsockopt = ip_getsockopt, | 1804 | .getsockopt = ip_getsockopt, |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index a66735f75963..80b1f80759ab 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -49,6 +49,56 @@ struct inet_timewait_death_row tcp_death_row = { | |||
49 | }; | 49 | }; |
50 | EXPORT_SYMBOL_GPL(tcp_death_row); | 50 | EXPORT_SYMBOL_GPL(tcp_death_row); |
51 | 51 | ||
52 | /* VJ's idea. Save last timestamp seen from this destination | ||
53 | * and hold it at least for normal timewait interval to use for duplicate | ||
54 | * segment detection in subsequent connections, before they enter synchronized | ||
55 | * state. | ||
56 | */ | ||
57 | |||
58 | static int tcp_remember_stamp(struct sock *sk) | ||
59 | { | ||
60 | const struct inet_connection_sock *icsk = inet_csk(sk); | ||
61 | struct tcp_sock *tp = tcp_sk(sk); | ||
62 | struct inet_peer *peer; | ||
63 | bool release_it; | ||
64 | |||
65 | peer = icsk->icsk_af_ops->get_peer(sk, &release_it); | ||
66 | if (peer) { | ||
67 | if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 || | ||
68 | ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | ||
69 | peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) { | ||
70 | peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp; | ||
71 | peer->tcp_ts = tp->rx_opt.ts_recent; | ||
72 | } | ||
73 | if (release_it) | ||
74 | inet_putpeer(peer); | ||
75 | return 1; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int tcp_tw_remember_stamp(struct inet_timewait_sock *tw) | ||
82 | { | ||
83 | struct sock *sk = (struct sock *) tw; | ||
84 | struct inet_peer *peer; | ||
85 | |||
86 | peer = twsk_getpeer(sk); | ||
87 | if (peer) { | ||
88 | const struct tcp_timewait_sock *tcptw = tcp_twsk(sk); | ||
89 | |||
90 | if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 || | ||
91 | ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | ||
92 | peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { | ||
93 | peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; | ||
94 | peer->tcp_ts = tcptw->tw_ts_recent; | ||
95 | } | ||
96 | inet_putpeer(peer); | ||
97 | return 1; | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
52 | static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) | 102 | static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) |
53 | { | 103 | { |
54 | if (seq == s_win) | 104 | if (seq == s_win) |
@@ -149,14 +199,9 @@ kill_with_rst: | |||
149 | tcptw->tw_ts_recent = tmp_opt.rcv_tsval; | 199 | tcptw->tw_ts_recent = tmp_opt.rcv_tsval; |
150 | } | 200 | } |
151 | 201 | ||
152 | /* I am shamed, but failed to make it more elegant. | 202 | if (tcp_death_row.sysctl_tw_recycle && |
153 | * Yes, it is direct reference to IP, which is impossible | 203 | tcptw->tw_ts_recent_stamp && |
154 | * to generalize to IPv6. Taking into account that IPv6 | 204 | tcp_tw_remember_stamp(tw)) |
155 | * do not understand recycling in any case, it not | ||
156 | * a big problem in practice. --ANK */ | ||
157 | if (tw->tw_family == AF_INET && | ||
158 | tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp && | ||
159 | tcp_v4_tw_remember_stamp(tw)) | ||
160 | inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout, | 205 | inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout, |
161 | TCP_TIMEWAIT_LEN); | 206 | TCP_TIMEWAIT_LEN); |
162 | else | 207 | else |
@@ -274,7 +319,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
274 | int recycle_ok = 0; | 319 | int recycle_ok = 0; |
275 | 320 | ||
276 | if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) | 321 | if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) |
277 | recycle_ok = icsk->icsk_af_ops->remember_stamp(sk); | 322 | recycle_ok = tcp_remember_stamp(sk); |
278 | 323 | ||
279 | if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) | 324 | if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) |
280 | tw = inet_twsk_alloc(sk, state); | 325 | tw = inet_twsk_alloc(sk, state); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 61c2463e2753..dc7c096ddfef 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -55,7 +55,7 @@ int sysctl_tcp_workaround_signed_windows __read_mostly = 0; | |||
55 | int sysctl_tcp_tso_win_divisor __read_mostly = 3; | 55 | int sysctl_tcp_tso_win_divisor __read_mostly = 3; |
56 | 56 | ||
57 | int sysctl_tcp_mtu_probing __read_mostly = 0; | 57 | int sysctl_tcp_mtu_probing __read_mostly = 0; |
58 | int sysctl_tcp_base_mss __read_mostly = 512; | 58 | int sysctl_tcp_base_mss __read_mostly = TCP_BASE_MSS; |
59 | 59 | ||
60 | /* By default, RFC2861 behavior. */ | 60 | /* By default, RFC2861 behavior. */ |
61 | int sysctl_tcp_slow_start_after_idle __read_mostly = 1; | 61 | int sysctl_tcp_slow_start_after_idle __read_mostly = 1; |
@@ -119,9 +119,13 @@ static __u16 tcp_advertise_mss(struct sock *sk) | |||
119 | struct dst_entry *dst = __sk_dst_get(sk); | 119 | struct dst_entry *dst = __sk_dst_get(sk); |
120 | int mss = tp->advmss; | 120 | int mss = tp->advmss; |
121 | 121 | ||
122 | if (dst && dst_metric(dst, RTAX_ADVMSS) < mss) { | 122 | if (dst) { |
123 | mss = dst_metric(dst, RTAX_ADVMSS); | 123 | unsigned int metric = dst_metric_advmss(dst); |
124 | tp->advmss = mss; | 124 | |
125 | if (metric < mss) { | ||
126 | mss = metric; | ||
127 | tp->advmss = mss; | ||
128 | } | ||
125 | } | 129 | } |
126 | 130 | ||
127 | return (__u16)mss; | 131 | return (__u16)mss; |
@@ -224,10 +228,15 @@ void tcp_select_initial_window(int __space, __u32 mss, | |||
224 | } | 228 | } |
225 | } | 229 | } |
226 | 230 | ||
227 | /* Set initial window to value enough for senders, following RFC5681. */ | 231 | /* Set initial window to a value enough for senders starting with |
232 | * initial congestion window of TCP_DEFAULT_INIT_RCVWND. Place | ||
233 | * a limit on the initial window when mss is larger than 1460. | ||
234 | */ | ||
228 | if (mss > (1 << *rcv_wscale)) { | 235 | if (mss > (1 << *rcv_wscale)) { |
229 | int init_cwnd = rfc3390_bytes_to_packets(mss); | 236 | int init_cwnd = TCP_DEFAULT_INIT_RCVWND; |
230 | 237 | if (mss > 1460) | |
238 | init_cwnd = | ||
239 | max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2); | ||
231 | /* when initializing use the value from init_rcv_wnd | 240 | /* when initializing use the value from init_rcv_wnd |
232 | * rather than the default from above | 241 | * rather than the default from above |
233 | */ | 242 | */ |
@@ -824,8 +833,11 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
824 | &md5); | 833 | &md5); |
825 | tcp_header_size = tcp_options_size + sizeof(struct tcphdr); | 834 | tcp_header_size = tcp_options_size + sizeof(struct tcphdr); |
826 | 835 | ||
827 | if (tcp_packets_in_flight(tp) == 0) | 836 | if (tcp_packets_in_flight(tp) == 0) { |
828 | tcp_ca_event(sk, CA_EVENT_TX_START); | 837 | tcp_ca_event(sk, CA_EVENT_TX_START); |
838 | skb->ooo_okay = 1; | ||
839 | } else | ||
840 | skb->ooo_okay = 0; | ||
829 | 841 | ||
830 | skb_push(skb, tcp_header_size); | 842 | skb_push(skb, tcp_header_size); |
831 | skb_reset_transport_header(skb); | 843 | skb_reset_transport_header(skb); |
@@ -2419,7 +2431,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2419 | 2431 | ||
2420 | skb_dst_set(skb, dst_clone(dst)); | 2432 | skb_dst_set(skb, dst_clone(dst)); |
2421 | 2433 | ||
2422 | mss = dst_metric(dst, RTAX_ADVMSS); | 2434 | mss = dst_metric_advmss(dst); |
2423 | if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss) | 2435 | if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss) |
2424 | mss = tp->rx_opt.user_mss; | 2436 | mss = tp->rx_opt.user_mss; |
2425 | 2437 | ||
@@ -2553,7 +2565,7 @@ static void tcp_connect_init(struct sock *sk) | |||
2553 | 2565 | ||
2554 | if (!tp->window_clamp) | 2566 | if (!tp->window_clamp) |
2555 | tp->window_clamp = dst_metric(dst, RTAX_WINDOW); | 2567 | tp->window_clamp = dst_metric(dst, RTAX_WINDOW); |
2556 | tp->advmss = dst_metric(dst, RTAX_ADVMSS); | 2568 | tp->advmss = dst_metric_advmss(dst); |
2557 | if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < tp->advmss) | 2569 | if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < tp->advmss) |
2558 | tp->advmss = tp->rx_opt.user_mss; | 2570 | tp->advmss = tp->rx_opt.user_mss; |
2559 | 2571 | ||
@@ -2596,6 +2608,7 @@ int tcp_connect(struct sock *sk) | |||
2596 | { | 2608 | { |
2597 | struct tcp_sock *tp = tcp_sk(sk); | 2609 | struct tcp_sock *tp = tcp_sk(sk); |
2598 | struct sk_buff *buff; | 2610 | struct sk_buff *buff; |
2611 | int err; | ||
2599 | 2612 | ||
2600 | tcp_connect_init(sk); | 2613 | tcp_connect_init(sk); |
2601 | 2614 | ||
@@ -2618,7 +2631,9 @@ int tcp_connect(struct sock *sk) | |||
2618 | sk->sk_wmem_queued += buff->truesize; | 2631 | sk->sk_wmem_queued += buff->truesize; |
2619 | sk_mem_charge(sk, buff->truesize); | 2632 | sk_mem_charge(sk, buff->truesize); |
2620 | tp->packets_out += tcp_skb_pcount(buff); | 2633 | tp->packets_out += tcp_skb_pcount(buff); |
2621 | tcp_transmit_skb(sk, buff, 1, sk->sk_allocation); | 2634 | err = tcp_transmit_skb(sk, buff, 1, sk->sk_allocation); |
2635 | if (err == -ECONNREFUSED) | ||
2636 | return err; | ||
2622 | 2637 | ||
2623 | /* We change tp->snd_nxt after the tcp_transmit_skb() call | 2638 | /* We change tp->snd_nxt after the tcp_transmit_skb() call |
2624 | * in order to make this packet get counted in tcpOutSegs. | 2639 | * in order to make this packet get counted in tcpOutSegs. |
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 6211e2114173..85ee7eb7e38e 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c | |||
@@ -154,7 +154,7 @@ static int tcpprobe_sprint(char *tbuf, int n) | |||
154 | struct timespec tv | 154 | struct timespec tv |
155 | = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start)); | 155 | = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start)); |
156 | 156 | ||
157 | return snprintf(tbuf, n, | 157 | return scnprintf(tbuf, n, |
158 | "%lu.%09lu %pI4:%u %pI4:%u %d %#x %#x %u %u %u %u\n", | 158 | "%lu.%09lu %pI4:%u %pI4:%u %d %#x %#x %u %u %u %u\n", |
159 | (unsigned long) tv.tv_sec, | 159 | (unsigned long) tv.tv_sec, |
160 | (unsigned long) tv.tv_nsec, | 160 | (unsigned long) tv.tv_nsec, |
@@ -174,7 +174,7 @@ static ssize_t tcpprobe_read(struct file *file, char __user *buf, | |||
174 | return -EINVAL; | 174 | return -EINVAL; |
175 | 175 | ||
176 | while (cnt < len) { | 176 | while (cnt < len) { |
177 | char tbuf[128]; | 177 | char tbuf[164]; |
178 | int width; | 178 | int width; |
179 | 179 | ||
180 | /* Wait for data in buffer */ | 180 | /* Wait for data in buffer */ |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 2d3ded4d0786..8157b17959ee 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -430,7 +430,7 @@ begin: | |||
430 | 430 | ||
431 | if (result) { | 431 | if (result) { |
432 | exact_match: | 432 | exact_match: |
433 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | 433 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) |
434 | result = NULL; | 434 | result = NULL; |
435 | else if (unlikely(compute_score2(result, net, saddr, sport, | 435 | else if (unlikely(compute_score2(result, net, saddr, sport, |
436 | daddr, hnum, dif) < badness)) { | 436 | daddr, hnum, dif) < badness)) { |
@@ -500,7 +500,7 @@ begin: | |||
500 | goto begin; | 500 | goto begin; |
501 | 501 | ||
502 | if (result) { | 502 | if (result) { |
503 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | 503 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) |
504 | result = NULL; | 504 | result = NULL; |
505 | else if (unlikely(compute_score(result, net, saddr, hnum, sport, | 505 | else if (unlikely(compute_score(result, net, saddr, hnum, sport, |
506 | daddr, dport, dif) < badness)) { | 506 | daddr, dport, dif) < badness)) { |
@@ -890,15 +890,13 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
890 | if (rt == NULL) { | 890 | if (rt == NULL) { |
891 | struct flowi fl = { .oif = ipc.oif, | 891 | struct flowi fl = { .oif = ipc.oif, |
892 | .mark = sk->sk_mark, | 892 | .mark = sk->sk_mark, |
893 | .nl_u = { .ip4_u = | 893 | .fl4_dst = faddr, |
894 | { .daddr = faddr, | 894 | .fl4_src = saddr, |
895 | .saddr = saddr, | 895 | .fl4_tos = tos, |
896 | .tos = tos } }, | ||
897 | .proto = sk->sk_protocol, | 896 | .proto = sk->sk_protocol, |
898 | .flags = inet_sk_flowi_flags(sk), | 897 | .flags = inet_sk_flowi_flags(sk), |
899 | .uli_u = { .ports = | 898 | .fl_ip_sport = inet->inet_sport, |
900 | { .sport = inet->inet_sport, | 899 | .fl_ip_dport = dport }; |
901 | .dport = dport } } }; | ||
902 | struct net *net = sock_net(sk); | 900 | struct net *net = sock_net(sk); |
903 | 901 | ||
904 | security_sk_classify_flow(sk, &fl); | 902 | security_sk_classify_flow(sk, &fl); |
@@ -2229,7 +2227,7 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, int features) | |||
2229 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | 2227 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot |
2230 | * do checksum of UDP packets sent as multiple IP fragments. | 2228 | * do checksum of UDP packets sent as multiple IP fragments. |
2231 | */ | 2229 | */ |
2232 | offset = skb->csum_start - skb_headroom(skb); | 2230 | offset = skb_checksum_start_offset(skb); |
2233 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | 2231 | csum = skb_checksum(skb, offset, skb->len - offset, 0); |
2234 | offset += skb->csum_offset; | 2232 | offset += skb->csum_offset; |
2235 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | 2233 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 6f368413eb0e..534972e114ac 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
@@ -56,7 +56,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
56 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); | 56 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); |
57 | ip_select_ident(top_iph, dst->child, NULL); | 57 | ip_select_ident(top_iph, dst->child, NULL); |
58 | 58 | ||
59 | top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); | 59 | top_iph->ttl = ip4_dst_hoplimit(dst->child); |
60 | 60 | ||
61 | top_iph->saddr = x->props.saddr.a4; | 61 | top_iph->saddr = x->props.saddr.a4; |
62 | top_iph->daddr = x->id.daddr.a4; | 62 | top_iph->daddr = x->id.daddr.a4; |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 4464f3bff6a7..b057d40addec 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/err.h> | 11 | #include <linux/err.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/inetdevice.h> | 13 | #include <linux/inetdevice.h> |
14 | #include <linux/if_tunnel.h> | ||
14 | #include <net/dst.h> | 15 | #include <net/dst.h> |
15 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
16 | #include <net/ip.h> | 17 | #include <net/ip.h> |
@@ -22,12 +23,8 @@ static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, | |||
22 | xfrm_address_t *daddr) | 23 | xfrm_address_t *daddr) |
23 | { | 24 | { |
24 | struct flowi fl = { | 25 | struct flowi fl = { |
25 | .nl_u = { | 26 | .fl4_dst = daddr->a4, |
26 | .ip4_u = { | 27 | .fl4_tos = tos, |
27 | .tos = tos, | ||
28 | .daddr = daddr->a4, | ||
29 | }, | ||
30 | }, | ||
31 | }; | 28 | }; |
32 | struct dst_entry *dst; | 29 | struct dst_entry *dst; |
33 | struct rtable *rt; | 30 | struct rtable *rt; |
@@ -80,10 +77,6 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
80 | xdst->u.dst.dev = dev; | 77 | xdst->u.dst.dev = dev; |
81 | dev_hold(dev); | 78 | dev_hold(dev); |
82 | 79 | ||
83 | xdst->u.rt.idev = in_dev_get(dev); | ||
84 | if (!xdst->u.rt.idev) | ||
85 | return -ENODEV; | ||
86 | |||
87 | xdst->u.rt.peer = rt->peer; | 80 | xdst->u.rt.peer = rt->peer; |
88 | if (rt->peer) | 81 | if (rt->peer) |
89 | atomic_inc(&rt->peer->refcnt); | 82 | atomic_inc(&rt->peer->refcnt); |
@@ -158,6 +151,20 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
158 | fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); | 151 | fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); |
159 | } | 152 | } |
160 | break; | 153 | break; |
154 | |||
155 | case IPPROTO_GRE: | ||
156 | if (pskb_may_pull(skb, xprth + 12 - skb->data)) { | ||
157 | __be16 *greflags = (__be16 *)xprth; | ||
158 | __be32 *gre_hdr = (__be32 *)xprth; | ||
159 | |||
160 | if (greflags[0] & GRE_KEY) { | ||
161 | if (greflags[0] & GRE_CSUM) | ||
162 | gre_hdr++; | ||
163 | fl->fl_gre_key = gre_hdr[1]; | ||
164 | } | ||
165 | } | ||
166 | break; | ||
167 | |||
161 | default: | 168 | default: |
162 | fl->fl_ipsec_spi = 0; | 169 | fl->fl_ipsec_spi = 0; |
163 | break; | 170 | break; |
@@ -189,8 +196,6 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) | |||
189 | { | 196 | { |
190 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 197 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
191 | 198 | ||
192 | if (likely(xdst->u.rt.idev)) | ||
193 | in_dev_put(xdst->u.rt.idev); | ||
194 | if (likely(xdst->u.rt.peer)) | 199 | if (likely(xdst->u.rt.peer)) |
195 | inet_putpeer(xdst->u.rt.peer); | 200 | inet_putpeer(xdst->u.rt.peer); |
196 | xfrm_dst_destroy(xdst); | 201 | xfrm_dst_destroy(xdst); |
@@ -199,27 +204,9 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) | |||
199 | static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 204 | static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
200 | int unregister) | 205 | int unregister) |
201 | { | 206 | { |
202 | struct xfrm_dst *xdst; | ||
203 | |||
204 | if (!unregister) | 207 | if (!unregister) |
205 | return; | 208 | return; |
206 | 209 | ||
207 | xdst = (struct xfrm_dst *)dst; | ||
208 | if (xdst->u.rt.idev->dev == dev) { | ||
209 | struct in_device *loopback_idev = | ||
210 | in_dev_get(dev_net(dev)->loopback_dev); | ||
211 | BUG_ON(!loopback_idev); | ||
212 | |||
213 | do { | ||
214 | in_dev_put(xdst->u.rt.idev); | ||
215 | xdst->u.rt.idev = loopback_idev; | ||
216 | in_dev_hold(loopback_idev); | ||
217 | xdst = (struct xfrm_dst *)xdst->u.dst.child; | ||
218 | } while (xdst->u.dst.xfrm); | ||
219 | |||
220 | __in_dev_put(loopback_idev); | ||
221 | } | ||
222 | |||
223 | xfrm_dst_ifdown(dst, dev); | 210 | xfrm_dst_ifdown(dst, dev); |
224 | } | 211 | } |
225 | 212 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 848b35591042..5b189c97c2fc 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -2672,7 +2672,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2672 | /* Flush routes if device is being removed or it is not loopback */ | 2672 | /* Flush routes if device is being removed or it is not loopback */ |
2673 | if (how || !(dev->flags & IFF_LOOPBACK)) | 2673 | if (how || !(dev->flags & IFF_LOOPBACK)) |
2674 | rt6_ifdown(net, dev); | 2674 | rt6_ifdown(net, dev); |
2675 | neigh_ifdown(&nd_tbl, dev); | ||
2676 | 2675 | ||
2677 | idev = __in6_dev_get(dev); | 2676 | idev = __in6_dev_get(dev); |
2678 | if (idev == NULL) | 2677 | if (idev == NULL) |
@@ -3838,6 +3837,15 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3838 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | 3837 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; |
3839 | } | 3838 | } |
3840 | 3839 | ||
3840 | static inline size_t inet6_ifla6_size(void) | ||
3841 | { | ||
3842 | return nla_total_size(4) /* IFLA_INET6_FLAGS */ | ||
3843 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | ||
3844 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3845 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3846 | + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */ | ||
3847 | } | ||
3848 | |||
3841 | static inline size_t inet6_if_nlmsg_size(void) | 3849 | static inline size_t inet6_if_nlmsg_size(void) |
3842 | { | 3850 | { |
3843 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 3851 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
@@ -3845,13 +3853,7 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3845 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ | 3853 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ |
3846 | + nla_total_size(4) /* IFLA_MTU */ | 3854 | + nla_total_size(4) /* IFLA_MTU */ |
3847 | + nla_total_size(4) /* IFLA_LINK */ | 3855 | + nla_total_size(4) /* IFLA_LINK */ |
3848 | + nla_total_size( /* IFLA_PROTINFO */ | 3856 | + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ |
3849 | nla_total_size(4) /* IFLA_INET6_FLAGS */ | ||
3850 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | ||
3851 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3852 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3853 | + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ | ||
3854 | ); | ||
3855 | } | 3857 | } |
3856 | 3858 | ||
3857 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | 3859 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, |
@@ -3898,15 +3900,70 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3898 | } | 3900 | } |
3899 | } | 3901 | } |
3900 | 3902 | ||
3903 | static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | ||
3904 | { | ||
3905 | struct nlattr *nla; | ||
3906 | struct ifla_cacheinfo ci; | ||
3907 | |||
3908 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); | ||
3909 | |||
3910 | ci.max_reasm_len = IPV6_MAXPLEN; | ||
3911 | ci.tstamp = cstamp_delta(idev->tstamp); | ||
3912 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); | ||
3913 | ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); | ||
3914 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | ||
3915 | |||
3916 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | ||
3917 | if (nla == NULL) | ||
3918 | goto nla_put_failure; | ||
3919 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); | ||
3920 | |||
3921 | /* XXX - MC not implemented */ | ||
3922 | |||
3923 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3924 | if (nla == NULL) | ||
3925 | goto nla_put_failure; | ||
3926 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3927 | |||
3928 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3929 | if (nla == NULL) | ||
3930 | goto nla_put_failure; | ||
3931 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3932 | |||
3933 | return 0; | ||
3934 | |||
3935 | nla_put_failure: | ||
3936 | return -EMSGSIZE; | ||
3937 | } | ||
3938 | |||
3939 | static size_t inet6_get_link_af_size(const struct net_device *dev) | ||
3940 | { | ||
3941 | if (!__in6_dev_get(dev)) | ||
3942 | return 0; | ||
3943 | |||
3944 | return inet6_ifla6_size(); | ||
3945 | } | ||
3946 | |||
3947 | static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||
3948 | { | ||
3949 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
3950 | |||
3951 | if (!idev) | ||
3952 | return -ENODATA; | ||
3953 | |||
3954 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) | ||
3955 | return -EMSGSIZE; | ||
3956 | |||
3957 | return 0; | ||
3958 | } | ||
3959 | |||
3901 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3960 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
3902 | u32 pid, u32 seq, int event, unsigned int flags) | 3961 | u32 pid, u32 seq, int event, unsigned int flags) |
3903 | { | 3962 | { |
3904 | struct net_device *dev = idev->dev; | 3963 | struct net_device *dev = idev->dev; |
3905 | struct nlattr *nla; | ||
3906 | struct ifinfomsg *hdr; | 3964 | struct ifinfomsg *hdr; |
3907 | struct nlmsghdr *nlh; | 3965 | struct nlmsghdr *nlh; |
3908 | void *protoinfo; | 3966 | void *protoinfo; |
3909 | struct ifla_cacheinfo ci; | ||
3910 | 3967 | ||
3911 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); | 3968 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); |
3912 | if (nlh == NULL) | 3969 | if (nlh == NULL) |
@@ -3933,30 +3990,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | |||
3933 | if (protoinfo == NULL) | 3990 | if (protoinfo == NULL) |
3934 | goto nla_put_failure; | 3991 | goto nla_put_failure; |
3935 | 3992 | ||
3936 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); | 3993 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) |
3937 | |||
3938 | ci.max_reasm_len = IPV6_MAXPLEN; | ||
3939 | ci.tstamp = cstamp_delta(idev->tstamp); | ||
3940 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); | ||
3941 | ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); | ||
3942 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | ||
3943 | |||
3944 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | ||
3945 | if (nla == NULL) | ||
3946 | goto nla_put_failure; | ||
3947 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); | ||
3948 | |||
3949 | /* XXX - MC not implemented */ | ||
3950 | |||
3951 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3952 | if (nla == NULL) | ||
3953 | goto nla_put_failure; | ||
3954 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3955 | |||
3956 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3957 | if (nla == NULL) | ||
3958 | goto nla_put_failure; | 3994 | goto nla_put_failure; |
3959 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3960 | 3995 | ||
3961 | nla_nest_end(skb, protoinfo); | 3996 | nla_nest_end(skb, protoinfo); |
3962 | return nlmsg_end(skb, nlh); | 3997 | return nlmsg_end(skb, nlh); |
@@ -4627,6 +4662,12 @@ int unregister_inet6addr_notifier(struct notifier_block *nb) | |||
4627 | } | 4662 | } |
4628 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 4663 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
4629 | 4664 | ||
4665 | static struct rtnl_af_ops inet6_ops = { | ||
4666 | .family = AF_INET6, | ||
4667 | .fill_link_af = inet6_fill_link_af, | ||
4668 | .get_link_af_size = inet6_get_link_af_size, | ||
4669 | }; | ||
4670 | |||
4630 | /* | 4671 | /* |
4631 | * Init / cleanup code | 4672 | * Init / cleanup code |
4632 | */ | 4673 | */ |
@@ -4678,6 +4719,10 @@ int __init addrconf_init(void) | |||
4678 | 4719 | ||
4679 | addrconf_verify(0); | 4720 | addrconf_verify(0); |
4680 | 4721 | ||
4722 | err = rtnl_af_register(&inet6_ops); | ||
4723 | if (err < 0) | ||
4724 | goto errout_af; | ||
4725 | |||
4681 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); | 4726 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); |
4682 | if (err < 0) | 4727 | if (err < 0) |
4683 | goto errout; | 4728 | goto errout; |
@@ -4693,6 +4738,8 @@ int __init addrconf_init(void) | |||
4693 | 4738 | ||
4694 | return 0; | 4739 | return 0; |
4695 | errout: | 4740 | errout: |
4741 | rtnl_af_unregister(&inet6_ops); | ||
4742 | errout_af: | ||
4696 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4743 | unregister_netdevice_notifier(&ipv6_dev_notf); |
4697 | errlo: | 4744 | errlo: |
4698 | unregister_pernet_subsys(&addrconf_ops); | 4745 | unregister_pernet_subsys(&addrconf_ops); |
@@ -4713,6 +4760,8 @@ void addrconf_cleanup(void) | |||
4713 | 4760 | ||
4714 | rtnl_lock(); | 4761 | rtnl_lock(); |
4715 | 4762 | ||
4763 | __rtnl_af_unregister(&inet6_ops); | ||
4764 | |||
4716 | /* clean dev list */ | 4765 | /* clean dev list */ |
4717 | for_each_netdev(&init_net, dev) { | 4766 | for_each_netdev(&init_net, dev) { |
4718 | if (__in6_dev_get(dev) == NULL) | 4767 | if (__in6_dev_get(dev) == NULL) |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 54e8e42f7a88..059a3de647db 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -810,7 +810,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
810 | } | 810 | } |
811 | rcu_read_unlock(); | 811 | rcu_read_unlock(); |
812 | 812 | ||
813 | if (unlikely(IS_ERR(segs))) | 813 | if (IS_ERR(segs)) |
814 | goto out; | 814 | goto out; |
815 | 815 | ||
816 | for (skb = segs; skb; skb = skb->next) { | 816 | for (skb = segs; skb; skb = skb->next) { |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index ee9b93bdd6a2..1b5c9825743b 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -49,6 +49,8 @@ struct esp_skb_cb { | |||
49 | 49 | ||
50 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) | 50 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) |
51 | 51 | ||
52 | static u32 esp6_get_mtu(struct xfrm_state *x, int mtu); | ||
53 | |||
52 | /* | 54 | /* |
53 | * Allocate an AEAD request structure with extra space for SG and IV. | 55 | * Allocate an AEAD request structure with extra space for SG and IV. |
54 | * | 56 | * |
@@ -140,6 +142,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
140 | int blksize; | 142 | int blksize; |
141 | int clen; | 143 | int clen; |
142 | int alen; | 144 | int alen; |
145 | int plen; | ||
146 | int tfclen; | ||
143 | int nfrags; | 147 | int nfrags; |
144 | u8 *iv; | 148 | u8 *iv; |
145 | u8 *tail; | 149 | u8 *tail; |
@@ -148,18 +152,26 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
148 | /* skb is pure payload to encrypt */ | 152 | /* skb is pure payload to encrypt */ |
149 | err = -ENOMEM; | 153 | err = -ENOMEM; |
150 | 154 | ||
151 | /* Round to block size */ | ||
152 | clen = skb->len; | ||
153 | |||
154 | aead = esp->aead; | 155 | aead = esp->aead; |
155 | alen = crypto_aead_authsize(aead); | 156 | alen = crypto_aead_authsize(aead); |
156 | 157 | ||
158 | tfclen = 0; | ||
159 | if (x->tfcpad) { | ||
160 | struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); | ||
161 | u32 padto; | ||
162 | |||
163 | padto = min(x->tfcpad, esp6_get_mtu(x, dst->child_mtu_cached)); | ||
164 | if (skb->len < padto) | ||
165 | tfclen = padto - skb->len; | ||
166 | } | ||
157 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); | 167 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); |
158 | clen = ALIGN(clen + 2, blksize); | 168 | clen = ALIGN(skb->len + 2 + tfclen, blksize); |
159 | if (esp->padlen) | 169 | if (esp->padlen) |
160 | clen = ALIGN(clen, esp->padlen); | 170 | clen = ALIGN(clen, esp->padlen); |
171 | plen = clen - skb->len - tfclen; | ||
161 | 172 | ||
162 | if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0) | 173 | err = skb_cow_data(skb, tfclen + plen + alen, &trailer); |
174 | if (err < 0) | ||
163 | goto error; | 175 | goto error; |
164 | nfrags = err; | 176 | nfrags = err; |
165 | 177 | ||
@@ -174,13 +186,17 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
174 | 186 | ||
175 | /* Fill padding... */ | 187 | /* Fill padding... */ |
176 | tail = skb_tail_pointer(trailer); | 188 | tail = skb_tail_pointer(trailer); |
189 | if (tfclen) { | ||
190 | memset(tail, 0, tfclen); | ||
191 | tail += tfclen; | ||
192 | } | ||
177 | do { | 193 | do { |
178 | int i; | 194 | int i; |
179 | for (i=0; i<clen-skb->len - 2; i++) | 195 | for (i = 0; i < plen - 2; i++) |
180 | tail[i] = i + 1; | 196 | tail[i] = i + 1; |
181 | } while (0); | 197 | } while (0); |
182 | tail[clen-skb->len - 2] = (clen - skb->len) - 2; | 198 | tail[plen - 2] = plen - 2; |
183 | tail[clen - skb->len - 1] = *skb_mac_header(skb); | 199 | tail[plen - 1] = *skb_mac_header(skb); |
184 | pskb_put(skb, trailer, clen - skb->len + alen); | 200 | pskb_put(skb, trailer, clen - skb->len + alen); |
185 | 201 | ||
186 | skb_push(skb, -skb_network_offset(skb)); | 202 | skb_push(skb, -skb_network_offset(skb)); |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 8a1628023bd1..e46305d1815a 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -54,24 +54,54 @@ int inet6_csk_bind_conflict(const struct sock *sk, | |||
54 | 54 | ||
55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); | 55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); |
56 | 56 | ||
57 | struct dst_entry *inet6_csk_route_req(struct sock *sk, | ||
58 | const struct request_sock *req) | ||
59 | { | ||
60 | struct inet6_request_sock *treq = inet6_rsk(req); | ||
61 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
62 | struct in6_addr *final_p, final; | ||
63 | struct dst_entry *dst; | ||
64 | struct flowi fl; | ||
65 | |||
66 | memset(&fl, 0, sizeof(fl)); | ||
67 | fl.proto = IPPROTO_TCP; | ||
68 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | ||
69 | final_p = fl6_update_dst(&fl, np->opt, &final); | ||
70 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | ||
71 | fl.oif = sk->sk_bound_dev_if; | ||
72 | fl.mark = sk->sk_mark; | ||
73 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | ||
74 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | ||
75 | security_req_classify_flow(req, &fl); | ||
76 | |||
77 | if (ip6_dst_lookup(sk, &dst, &fl)) | ||
78 | return NULL; | ||
79 | |||
80 | if (final_p) | ||
81 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
82 | |||
83 | if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | ||
84 | return NULL; | ||
85 | |||
86 | return dst; | ||
87 | } | ||
88 | |||
57 | /* | 89 | /* |
58 | * request_sock (formerly open request) hash tables. | 90 | * request_sock (formerly open request) hash tables. |
59 | */ | 91 | */ |
60 | static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport, | 92 | static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport, |
61 | const u32 rnd, const u16 synq_hsize) | 93 | const u32 rnd, const u16 synq_hsize) |
62 | { | 94 | { |
63 | u32 a = (__force u32)raddr->s6_addr32[0]; | 95 | u32 c; |
64 | u32 b = (__force u32)raddr->s6_addr32[1]; | 96 | |
65 | u32 c = (__force u32)raddr->s6_addr32[2]; | 97 | c = jhash_3words((__force u32)raddr->s6_addr32[0], |
66 | 98 | (__force u32)raddr->s6_addr32[1], | |
67 | a += JHASH_GOLDEN_RATIO; | 99 | (__force u32)raddr->s6_addr32[2], |
68 | b += JHASH_GOLDEN_RATIO; | 100 | rnd); |
69 | c += rnd; | 101 | |
70 | __jhash_mix(a, b, c); | 102 | c = jhash_2words((__force u32)raddr->s6_addr32[3], |
71 | 103 | (__force u32)rport, | |
72 | a += (__force u32)raddr->s6_addr32[3]; | 104 | c); |
73 | b += (__force u32)rport; | ||
74 | __jhash_mix(a, b, c); | ||
75 | 105 | ||
76 | return c & (synq_hsize - 1); | 106 | return c & (synq_hsize - 1); |
77 | } | 107 | } |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 70e891a20fb9..4f4483e697bd 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -58,8 +58,6 @@ MODULE_AUTHOR("Ville Nuorvala"); | |||
58 | MODULE_DESCRIPTION("IPv6 tunneling device"); | 58 | MODULE_DESCRIPTION("IPv6 tunneling device"); |
59 | MODULE_LICENSE("GPL"); | 59 | MODULE_LICENSE("GPL"); |
60 | 60 | ||
61 | #define IPV6_TLV_TEL_DST_SIZE 8 | ||
62 | |||
63 | #ifdef IP6_TNL_DEBUG | 61 | #ifdef IP6_TNL_DEBUG |
64 | #define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__) | 62 | #define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__) |
65 | #else | 63 | #else |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 6f32ffce7022..9fab274019c0 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -1843,9 +1843,7 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt, | |||
1843 | 1843 | ||
1844 | fl = (struct flowi) { | 1844 | fl = (struct flowi) { |
1845 | .oif = vif->link, | 1845 | .oif = vif->link, |
1846 | .nl_u = { .ip6_u = | 1846 | .fl6_dst = ipv6h->daddr, |
1847 | { .daddr = ipv6h->daddr, } | ||
1848 | } | ||
1849 | }; | 1847 | }; |
1850 | 1848 | ||
1851 | dst = ip6_route_output(net, NULL, &fl); | 1849 | dst = ip6_route_output(net, NULL, &fl); |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index d1444b95ad7e..49f986d626a0 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -82,7 +82,7 @@ static void *__mld2_query_bugs[] __attribute__((__unused__)) = { | |||
82 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | 82 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; |
83 | 83 | ||
84 | /* Big mc list lock for all the sockets */ | 84 | /* Big mc list lock for all the sockets */ |
85 | static DEFINE_RWLOCK(ipv6_sk_mc_lock); | 85 | static DEFINE_SPINLOCK(ipv6_sk_mc_lock); |
86 | 86 | ||
87 | static void igmp6_join_group(struct ifmcaddr6 *ma); | 87 | static void igmp6_join_group(struct ifmcaddr6 *ma); |
88 | static void igmp6_leave_group(struct ifmcaddr6 *ma); | 88 | static void igmp6_leave_group(struct ifmcaddr6 *ma); |
@@ -123,6 +123,11 @@ int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; | |||
123 | * socket join on multicast group | 123 | * socket join on multicast group |
124 | */ | 124 | */ |
125 | 125 | ||
126 | #define for_each_pmc_rcu(np, pmc) \ | ||
127 | for (pmc = rcu_dereference(np->ipv6_mc_list); \ | ||
128 | pmc != NULL; \ | ||
129 | pmc = rcu_dereference(pmc->next)) | ||
130 | |||
126 | int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | 131 | int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) |
127 | { | 132 | { |
128 | struct net_device *dev = NULL; | 133 | struct net_device *dev = NULL; |
@@ -134,15 +139,15 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
134 | if (!ipv6_addr_is_multicast(addr)) | 139 | if (!ipv6_addr_is_multicast(addr)) |
135 | return -EINVAL; | 140 | return -EINVAL; |
136 | 141 | ||
137 | read_lock_bh(&ipv6_sk_mc_lock); | 142 | rcu_read_lock(); |
138 | for (mc_lst=np->ipv6_mc_list; mc_lst; mc_lst=mc_lst->next) { | 143 | for_each_pmc_rcu(np, mc_lst) { |
139 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && | 144 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && |
140 | ipv6_addr_equal(&mc_lst->addr, addr)) { | 145 | ipv6_addr_equal(&mc_lst->addr, addr)) { |
141 | read_unlock_bh(&ipv6_sk_mc_lock); | 146 | rcu_read_unlock(); |
142 | return -EADDRINUSE; | 147 | return -EADDRINUSE; |
143 | } | 148 | } |
144 | } | 149 | } |
145 | read_unlock_bh(&ipv6_sk_mc_lock); | 150 | rcu_read_unlock(); |
146 | 151 | ||
147 | mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); | 152 | mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); |
148 | 153 | ||
@@ -186,33 +191,41 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
186 | return err; | 191 | return err; |
187 | } | 192 | } |
188 | 193 | ||
189 | write_lock_bh(&ipv6_sk_mc_lock); | 194 | spin_lock(&ipv6_sk_mc_lock); |
190 | mc_lst->next = np->ipv6_mc_list; | 195 | mc_lst->next = np->ipv6_mc_list; |
191 | np->ipv6_mc_list = mc_lst; | 196 | rcu_assign_pointer(np->ipv6_mc_list, mc_lst); |
192 | write_unlock_bh(&ipv6_sk_mc_lock); | 197 | spin_unlock(&ipv6_sk_mc_lock); |
193 | 198 | ||
194 | rcu_read_unlock(); | 199 | rcu_read_unlock(); |
195 | 200 | ||
196 | return 0; | 201 | return 0; |
197 | } | 202 | } |
198 | 203 | ||
204 | static void ipv6_mc_socklist_reclaim(struct rcu_head *head) | ||
205 | { | ||
206 | kfree(container_of(head, struct ipv6_mc_socklist, rcu)); | ||
207 | } | ||
199 | /* | 208 | /* |
200 | * socket leave on multicast group | 209 | * socket leave on multicast group |
201 | */ | 210 | */ |
202 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | 211 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) |
203 | { | 212 | { |
204 | struct ipv6_pinfo *np = inet6_sk(sk); | 213 | struct ipv6_pinfo *np = inet6_sk(sk); |
205 | struct ipv6_mc_socklist *mc_lst, **lnk; | 214 | struct ipv6_mc_socklist *mc_lst; |
215 | struct ipv6_mc_socklist __rcu **lnk; | ||
206 | struct net *net = sock_net(sk); | 216 | struct net *net = sock_net(sk); |
207 | 217 | ||
208 | write_lock_bh(&ipv6_sk_mc_lock); | 218 | spin_lock(&ipv6_sk_mc_lock); |
209 | for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { | 219 | for (lnk = &np->ipv6_mc_list; |
220 | (mc_lst = rcu_dereference_protected(*lnk, | ||
221 | lockdep_is_held(&ipv6_sk_mc_lock))) !=NULL ; | ||
222 | lnk = &mc_lst->next) { | ||
210 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && | 223 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && |
211 | ipv6_addr_equal(&mc_lst->addr, addr)) { | 224 | ipv6_addr_equal(&mc_lst->addr, addr)) { |
212 | struct net_device *dev; | 225 | struct net_device *dev; |
213 | 226 | ||
214 | *lnk = mc_lst->next; | 227 | *lnk = mc_lst->next; |
215 | write_unlock_bh(&ipv6_sk_mc_lock); | 228 | spin_unlock(&ipv6_sk_mc_lock); |
216 | 229 | ||
217 | rcu_read_lock(); | 230 | rcu_read_lock(); |
218 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | 231 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); |
@@ -225,11 +238,12 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
225 | } else | 238 | } else |
226 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 239 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
227 | rcu_read_unlock(); | 240 | rcu_read_unlock(); |
228 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 241 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); |
242 | call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim); | ||
229 | return 0; | 243 | return 0; |
230 | } | 244 | } |
231 | } | 245 | } |
232 | write_unlock_bh(&ipv6_sk_mc_lock); | 246 | spin_unlock(&ipv6_sk_mc_lock); |
233 | 247 | ||
234 | return -EADDRNOTAVAIL; | 248 | return -EADDRNOTAVAIL; |
235 | } | 249 | } |
@@ -257,7 +271,7 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, | |||
257 | return NULL; | 271 | return NULL; |
258 | idev = __in6_dev_get(dev); | 272 | idev = __in6_dev_get(dev); |
259 | if (!idev) | 273 | if (!idev) |
260 | return NULL;; | 274 | return NULL; |
261 | read_lock_bh(&idev->lock); | 275 | read_lock_bh(&idev->lock); |
262 | if (idev->dead) { | 276 | if (idev->dead) { |
263 | read_unlock_bh(&idev->lock); | 277 | read_unlock_bh(&idev->lock); |
@@ -272,12 +286,13 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
272 | struct ipv6_mc_socklist *mc_lst; | 286 | struct ipv6_mc_socklist *mc_lst; |
273 | struct net *net = sock_net(sk); | 287 | struct net *net = sock_net(sk); |
274 | 288 | ||
275 | write_lock_bh(&ipv6_sk_mc_lock); | 289 | spin_lock(&ipv6_sk_mc_lock); |
276 | while ((mc_lst = np->ipv6_mc_list) != NULL) { | 290 | while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list, |
291 | lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) { | ||
277 | struct net_device *dev; | 292 | struct net_device *dev; |
278 | 293 | ||
279 | np->ipv6_mc_list = mc_lst->next; | 294 | np->ipv6_mc_list = mc_lst->next; |
280 | write_unlock_bh(&ipv6_sk_mc_lock); | 295 | spin_unlock(&ipv6_sk_mc_lock); |
281 | 296 | ||
282 | rcu_read_lock(); | 297 | rcu_read_lock(); |
283 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | 298 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); |
@@ -290,11 +305,13 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
290 | } else | 305 | } else |
291 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 306 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
292 | rcu_read_unlock(); | 307 | rcu_read_unlock(); |
293 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | ||
294 | 308 | ||
295 | write_lock_bh(&ipv6_sk_mc_lock); | 309 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); |
310 | call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim); | ||
311 | |||
312 | spin_lock(&ipv6_sk_mc_lock); | ||
296 | } | 313 | } |
297 | write_unlock_bh(&ipv6_sk_mc_lock); | 314 | spin_unlock(&ipv6_sk_mc_lock); |
298 | } | 315 | } |
299 | 316 | ||
300 | int ip6_mc_source(int add, int omode, struct sock *sk, | 317 | int ip6_mc_source(int add, int omode, struct sock *sk, |
@@ -328,8 +345,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
328 | 345 | ||
329 | err = -EADDRNOTAVAIL; | 346 | err = -EADDRNOTAVAIL; |
330 | 347 | ||
331 | read_lock(&ipv6_sk_mc_lock); | 348 | for_each_pmc_rcu(inet6, pmc) { |
332 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | ||
333 | if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) | 349 | if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) |
334 | continue; | 350 | continue; |
335 | if (ipv6_addr_equal(&pmc->addr, group)) | 351 | if (ipv6_addr_equal(&pmc->addr, group)) |
@@ -428,7 +444,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
428 | done: | 444 | done: |
429 | if (pmclocked) | 445 | if (pmclocked) |
430 | write_unlock(&pmc->sflock); | 446 | write_unlock(&pmc->sflock); |
431 | read_unlock(&ipv6_sk_mc_lock); | ||
432 | read_unlock_bh(&idev->lock); | 447 | read_unlock_bh(&idev->lock); |
433 | rcu_read_unlock(); | 448 | rcu_read_unlock(); |
434 | if (leavegroup) | 449 | if (leavegroup) |
@@ -466,14 +481,13 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
466 | dev = idev->dev; | 481 | dev = idev->dev; |
467 | 482 | ||
468 | err = 0; | 483 | err = 0; |
469 | read_lock(&ipv6_sk_mc_lock); | ||
470 | 484 | ||
471 | if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { | 485 | if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { |
472 | leavegroup = 1; | 486 | leavegroup = 1; |
473 | goto done; | 487 | goto done; |
474 | } | 488 | } |
475 | 489 | ||
476 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | 490 | for_each_pmc_rcu(inet6, pmc) { |
477 | if (pmc->ifindex != gsf->gf_interface) | 491 | if (pmc->ifindex != gsf->gf_interface) |
478 | continue; | 492 | continue; |
479 | if (ipv6_addr_equal(&pmc->addr, group)) | 493 | if (ipv6_addr_equal(&pmc->addr, group)) |
@@ -521,7 +535,6 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
521 | write_unlock(&pmc->sflock); | 535 | write_unlock(&pmc->sflock); |
522 | err = 0; | 536 | err = 0; |
523 | done: | 537 | done: |
524 | read_unlock(&ipv6_sk_mc_lock); | ||
525 | read_unlock_bh(&idev->lock); | 538 | read_unlock_bh(&idev->lock); |
526 | rcu_read_unlock(); | 539 | rcu_read_unlock(); |
527 | if (leavegroup) | 540 | if (leavegroup) |
@@ -562,7 +575,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
562 | * so reading the list is safe. | 575 | * so reading the list is safe. |
563 | */ | 576 | */ |
564 | 577 | ||
565 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | 578 | for_each_pmc_rcu(inet6, pmc) { |
566 | if (pmc->ifindex != gsf->gf_interface) | 579 | if (pmc->ifindex != gsf->gf_interface) |
567 | continue; | 580 | continue; |
568 | if (ipv6_addr_equal(group, &pmc->addr)) | 581 | if (ipv6_addr_equal(group, &pmc->addr)) |
@@ -612,13 +625,13 @@ int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, | |||
612 | struct ip6_sf_socklist *psl; | 625 | struct ip6_sf_socklist *psl; |
613 | int rv = 1; | 626 | int rv = 1; |
614 | 627 | ||
615 | read_lock(&ipv6_sk_mc_lock); | 628 | rcu_read_lock(); |
616 | for (mc = np->ipv6_mc_list; mc; mc = mc->next) { | 629 | for_each_pmc_rcu(np, mc) { |
617 | if (ipv6_addr_equal(&mc->addr, mc_addr)) | 630 | if (ipv6_addr_equal(&mc->addr, mc_addr)) |
618 | break; | 631 | break; |
619 | } | 632 | } |
620 | if (!mc) { | 633 | if (!mc) { |
621 | read_unlock(&ipv6_sk_mc_lock); | 634 | rcu_read_unlock(); |
622 | return 1; | 635 | return 1; |
623 | } | 636 | } |
624 | read_lock(&mc->sflock); | 637 | read_lock(&mc->sflock); |
@@ -638,7 +651,7 @@ int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, | |||
638 | rv = 0; | 651 | rv = 0; |
639 | } | 652 | } |
640 | read_unlock(&mc->sflock); | 653 | read_unlock(&mc->sflock); |
641 | read_unlock(&ipv6_sk_mc_lock); | 654 | rcu_read_unlock(); |
642 | 655 | ||
643 | return rv; | 656 | return rv; |
644 | } | 657 | } |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 998d6d27e7cf..2342545a5ee9 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -141,18 +141,18 @@ struct neigh_table nd_tbl = { | |||
141 | .proxy_redo = pndisc_redo, | 141 | .proxy_redo = pndisc_redo, |
142 | .id = "ndisc_cache", | 142 | .id = "ndisc_cache", |
143 | .parms = { | 143 | .parms = { |
144 | .tbl = &nd_tbl, | 144 | .tbl = &nd_tbl, |
145 | .base_reachable_time = 30 * HZ, | 145 | .base_reachable_time = ND_REACHABLE_TIME, |
146 | .retrans_time = 1 * HZ, | 146 | .retrans_time = ND_RETRANS_TIMER, |
147 | .gc_staletime = 60 * HZ, | 147 | .gc_staletime = 60 * HZ, |
148 | .reachable_time = 30 * HZ, | 148 | .reachable_time = ND_REACHABLE_TIME, |
149 | .delay_probe_time = 5 * HZ, | 149 | .delay_probe_time = 5 * HZ, |
150 | .queue_len = 3, | 150 | .queue_len = 3, |
151 | .ucast_probes = 3, | 151 | .ucast_probes = 3, |
152 | .mcast_probes = 3, | 152 | .mcast_probes = 3, |
153 | .anycast_delay = 1 * HZ, | 153 | .anycast_delay = 1 * HZ, |
154 | .proxy_delay = (8 * HZ) / 10, | 154 | .proxy_delay = (8 * HZ) / 10, |
155 | .proxy_qlen = 64, | 155 | .proxy_qlen = 64, |
156 | }, | 156 | }, |
157 | .gc_interval = 30 * HZ, | 157 | .gc_interval = 30 * HZ, |
158 | .gc_thresh1 = 128, | 158 | .gc_thresh1 = 128, |
@@ -1259,7 +1259,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1259 | if (ra_msg->icmph.icmp6_hop_limit) { | 1259 | if (ra_msg->icmph.icmp6_hop_limit) { |
1260 | in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; | 1260 | in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; |
1261 | if (rt) | 1261 | if (rt) |
1262 | rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; | 1262 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, |
1263 | ra_msg->icmph.icmp6_hop_limit); | ||
1263 | } | 1264 | } |
1264 | 1265 | ||
1265 | skip_defrtr: | 1266 | skip_defrtr: |
@@ -1377,7 +1378,7 @@ skip_linkparms: | |||
1377 | in6_dev->cnf.mtu6 = mtu; | 1378 | in6_dev->cnf.mtu6 = mtu; |
1378 | 1379 | ||
1379 | if (rt) | 1380 | if (rt) |
1380 | rt->dst.metrics[RTAX_MTU-1] = mtu; | 1381 | dst_metric_set(&rt->dst, RTAX_MTU, mtu); |
1381 | 1382 | ||
1382 | rt6_mtu_change(skb->dev, mtu); | 1383 | rt6_mtu_change(skb->dev, mtu); |
1383 | } | 1384 | } |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 7155b2451d7c..35915e8617f0 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -18,10 +18,8 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
18 | struct flowi fl = { | 18 | struct flowi fl = { |
19 | .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, | 19 | .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, |
20 | .mark = skb->mark, | 20 | .mark = skb->mark, |
21 | .nl_u = | 21 | .fl6_dst = iph->daddr, |
22 | { .ip6_u = | 22 | .fl6_src = iph->saddr, |
23 | { .daddr = iph->daddr, | ||
24 | .saddr = iph->saddr, } }, | ||
25 | }; | 23 | }; |
26 | 24 | ||
27 | dst = ip6_route_output(net, skb->sk, &fl); | 25 | dst = ip6_route_output(net, skb->sk, &fl); |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 0a432c9b0795..abfee91ce816 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -11,13 +11,13 @@ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o | |||
11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o | 11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o |
12 | 12 | ||
13 | # objects for l3 independent conntrack | 13 | # objects for l3 independent conntrack |
14 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o | 14 | nf_conntrack_ipv6-y := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o |
15 | 15 | ||
16 | # l3 independent conntrack | 16 | # l3 independent conntrack |
17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o |
18 | 18 | ||
19 | # defrag | 19 | # defrag |
20 | nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | 20 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o |
21 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | 21 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o |
22 | 22 | ||
23 | # matches | 23 | # matches |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 2933396e0281..bf998feac14e 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -124,7 +124,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
124 | skb_reset_network_header(nskb); | 124 | skb_reset_network_header(nskb); |
125 | ip6h = ipv6_hdr(nskb); | 125 | ip6h = ipv6_hdr(nskb); |
126 | ip6h->version = 6; | 126 | ip6h->version = 6; |
127 | ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT); | 127 | ip6h->hop_limit = ip6_dst_hoplimit(dst); |
128 | ip6h->nexthdr = IPPROTO_TCP; | 128 | ip6h->nexthdr = IPPROTO_TCP; |
129 | ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); | 129 | ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); |
130 | ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr); | 130 | ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr); |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 0f2766453759..07beeb06f752 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -104,26 +104,22 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
104 | unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, | 104 | unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, |
105 | const struct in6_addr *daddr, u32 rnd) | 105 | const struct in6_addr *daddr, u32 rnd) |
106 | { | 106 | { |
107 | u32 a, b, c; | 107 | u32 c; |
108 | 108 | ||
109 | a = (__force u32)saddr->s6_addr32[0]; | 109 | c = jhash_3words((__force u32)saddr->s6_addr32[0], |
110 | b = (__force u32)saddr->s6_addr32[1]; | 110 | (__force u32)saddr->s6_addr32[1], |
111 | c = (__force u32)saddr->s6_addr32[2]; | 111 | (__force u32)saddr->s6_addr32[2], |
112 | 112 | rnd); | |
113 | a += JHASH_GOLDEN_RATIO; | 113 | |
114 | b += JHASH_GOLDEN_RATIO; | 114 | c = jhash_3words((__force u32)saddr->s6_addr32[3], |
115 | c += rnd; | 115 | (__force u32)daddr->s6_addr32[0], |
116 | __jhash_mix(a, b, c); | 116 | (__force u32)daddr->s6_addr32[1], |
117 | 117 | c); | |
118 | a += (__force u32)saddr->s6_addr32[3]; | 118 | |
119 | b += (__force u32)daddr->s6_addr32[0]; | 119 | c = jhash_3words((__force u32)daddr->s6_addr32[2], |
120 | c += (__force u32)daddr->s6_addr32[1]; | 120 | (__force u32)daddr->s6_addr32[3], |
121 | __jhash_mix(a, b, c); | 121 | (__force u32)id, |
122 | 122 | c); | |
123 | a += (__force u32)daddr->s6_addr32[2]; | ||
124 | b += (__force u32)daddr->s6_addr32[3]; | ||
125 | c += (__force u32)id; | ||
126 | __jhash_mix(a, b, c); | ||
127 | 123 | ||
128 | return c & (INETFRAGS_HASHSZ - 1); | 124 | return c & (INETFRAGS_HASHSZ - 1); |
129 | } | 125 | } |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7659d6f16e6b..373bd0416f69 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -76,6 +76,8 @@ | |||
76 | 76 | ||
77 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); | 77 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); |
78 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); | 78 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); |
79 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); | ||
80 | static unsigned int ip6_default_mtu(const struct dst_entry *dst); | ||
79 | static struct dst_entry *ip6_negative_advice(struct dst_entry *); | 81 | static struct dst_entry *ip6_negative_advice(struct dst_entry *); |
80 | static void ip6_dst_destroy(struct dst_entry *); | 82 | static void ip6_dst_destroy(struct dst_entry *); |
81 | static void ip6_dst_ifdown(struct dst_entry *, | 83 | static void ip6_dst_ifdown(struct dst_entry *, |
@@ -103,6 +105,8 @@ static struct dst_ops ip6_dst_ops_template = { | |||
103 | .gc = ip6_dst_gc, | 105 | .gc = ip6_dst_gc, |
104 | .gc_thresh = 1024, | 106 | .gc_thresh = 1024, |
105 | .check = ip6_dst_check, | 107 | .check = ip6_dst_check, |
108 | .default_advmss = ip6_default_advmss, | ||
109 | .default_mtu = ip6_default_mtu, | ||
106 | .destroy = ip6_dst_destroy, | 110 | .destroy = ip6_dst_destroy, |
107 | .ifdown = ip6_dst_ifdown, | 111 | .ifdown = ip6_dst_ifdown, |
108 | .negative_advice = ip6_negative_advice, | 112 | .negative_advice = ip6_negative_advice, |
@@ -129,7 +133,6 @@ static struct rt6_info ip6_null_entry_template = { | |||
129 | .__use = 1, | 133 | .__use = 1, |
130 | .obsolete = -1, | 134 | .obsolete = -1, |
131 | .error = -ENETUNREACH, | 135 | .error = -ENETUNREACH, |
132 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
133 | .input = ip6_pkt_discard, | 136 | .input = ip6_pkt_discard, |
134 | .output = ip6_pkt_discard_out, | 137 | .output = ip6_pkt_discard_out, |
135 | }, | 138 | }, |
@@ -150,7 +153,6 @@ static struct rt6_info ip6_prohibit_entry_template = { | |||
150 | .__use = 1, | 153 | .__use = 1, |
151 | .obsolete = -1, | 154 | .obsolete = -1, |
152 | .error = -EACCES, | 155 | .error = -EACCES, |
153 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
154 | .input = ip6_pkt_prohibit, | 156 | .input = ip6_pkt_prohibit, |
155 | .output = ip6_pkt_prohibit_out, | 157 | .output = ip6_pkt_prohibit_out, |
156 | }, | 158 | }, |
@@ -166,7 +168,6 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
166 | .__use = 1, | 168 | .__use = 1, |
167 | .obsolete = -1, | 169 | .obsolete = -1, |
168 | .error = -EINVAL, | 170 | .error = -EINVAL, |
169 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
170 | .input = dst_discard, | 171 | .input = dst_discard, |
171 | .output = dst_discard, | 172 | .output = dst_discard, |
172 | }, | 173 | }, |
@@ -188,11 +189,29 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
188 | { | 189 | { |
189 | struct rt6_info *rt = (struct rt6_info *)dst; | 190 | struct rt6_info *rt = (struct rt6_info *)dst; |
190 | struct inet6_dev *idev = rt->rt6i_idev; | 191 | struct inet6_dev *idev = rt->rt6i_idev; |
192 | struct inet_peer *peer = rt->rt6i_peer; | ||
191 | 193 | ||
192 | if (idev != NULL) { | 194 | if (idev != NULL) { |
193 | rt->rt6i_idev = NULL; | 195 | rt->rt6i_idev = NULL; |
194 | in6_dev_put(idev); | 196 | in6_dev_put(idev); |
195 | } | 197 | } |
198 | if (peer) { | ||
199 | BUG_ON(!(rt->rt6i_flags & RTF_CACHE)); | ||
200 | rt->rt6i_peer = NULL; | ||
201 | inet_putpeer(peer); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | void rt6_bind_peer(struct rt6_info *rt, int create) | ||
206 | { | ||
207 | struct inet_peer *peer; | ||
208 | |||
209 | if (WARN_ON(!(rt->rt6i_flags & RTF_CACHE))) | ||
210 | return; | ||
211 | |||
212 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); | ||
213 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) | ||
214 | inet_putpeer(peer); | ||
196 | } | 215 | } |
197 | 216 | ||
198 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 217 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -558,11 +577,7 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, | |||
558 | { | 577 | { |
559 | struct flowi fl = { | 578 | struct flowi fl = { |
560 | .oif = oif, | 579 | .oif = oif, |
561 | .nl_u = { | 580 | .fl6_dst = *daddr, |
562 | .ip6_u = { | ||
563 | .daddr = *daddr, | ||
564 | }, | ||
565 | }, | ||
566 | }; | 581 | }; |
567 | struct dst_entry *dst; | 582 | struct dst_entry *dst; |
568 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; | 583 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; |
@@ -778,13 +793,9 @@ void ip6_route_input(struct sk_buff *skb) | |||
778 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 793 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
779 | struct flowi fl = { | 794 | struct flowi fl = { |
780 | .iif = skb->dev->ifindex, | 795 | .iif = skb->dev->ifindex, |
781 | .nl_u = { | 796 | .fl6_dst = iph->daddr, |
782 | .ip6_u = { | 797 | .fl6_src = iph->saddr, |
783 | .daddr = iph->daddr, | 798 | .fl6_flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, |
784 | .saddr = iph->saddr, | ||
785 | .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, | ||
786 | }, | ||
787 | }, | ||
788 | .mark = skb->mark, | 799 | .mark = skb->mark, |
789 | .proto = iph->nexthdr, | 800 | .proto = iph->nexthdr, |
790 | }; | 801 | }; |
@@ -834,7 +845,7 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
834 | new->input = dst_discard; | 845 | new->input = dst_discard; |
835 | new->output = dst_discard; | 846 | new->output = dst_discard; |
836 | 847 | ||
837 | memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); | 848 | dst_copy_metrics(new, &ort->dst); |
838 | new->dev = ort->dst.dev; | 849 | new->dev = ort->dst.dev; |
839 | if (new->dev) | 850 | if (new->dev) |
840 | dev_hold(new->dev); | 851 | dev_hold(new->dev); |
@@ -918,18 +929,22 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
918 | if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) { | 929 | if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) { |
919 | rt6->rt6i_flags |= RTF_MODIFIED; | 930 | rt6->rt6i_flags |= RTF_MODIFIED; |
920 | if (mtu < IPV6_MIN_MTU) { | 931 | if (mtu < IPV6_MIN_MTU) { |
932 | u32 features = dst_metric(dst, RTAX_FEATURES); | ||
921 | mtu = IPV6_MIN_MTU; | 933 | mtu = IPV6_MIN_MTU; |
922 | dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 934 | features |= RTAX_FEATURE_ALLFRAG; |
935 | dst_metric_set(dst, RTAX_FEATURES, features); | ||
923 | } | 936 | } |
924 | dst->metrics[RTAX_MTU-1] = mtu; | 937 | dst_metric_set(dst, RTAX_MTU, mtu); |
925 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | 938 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); |
926 | } | 939 | } |
927 | } | 940 | } |
928 | 941 | ||
929 | static int ipv6_get_mtu(struct net_device *dev); | 942 | static unsigned int ip6_default_advmss(const struct dst_entry *dst) |
930 | |||
931 | static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu) | ||
932 | { | 943 | { |
944 | struct net_device *dev = dst->dev; | ||
945 | unsigned int mtu = dst_mtu(dst); | ||
946 | struct net *net = dev_net(dev); | ||
947 | |||
933 | mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); | 948 | mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); |
934 | 949 | ||
935 | if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) | 950 | if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) |
@@ -946,6 +961,20 @@ static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu) | |||
946 | return mtu; | 961 | return mtu; |
947 | } | 962 | } |
948 | 963 | ||
964 | static unsigned int ip6_default_mtu(const struct dst_entry *dst) | ||
965 | { | ||
966 | unsigned int mtu = IPV6_MIN_MTU; | ||
967 | struct inet6_dev *idev; | ||
968 | |||
969 | rcu_read_lock(); | ||
970 | idev = __in6_dev_get(dst->dev); | ||
971 | if (idev) | ||
972 | mtu = idev->cnf.mtu6; | ||
973 | rcu_read_unlock(); | ||
974 | |||
975 | return mtu; | ||
976 | } | ||
977 | |||
949 | static struct dst_entry *icmp6_dst_gc_list; | 978 | static struct dst_entry *icmp6_dst_gc_list; |
950 | static DEFINE_SPINLOCK(icmp6_dst_lock); | 979 | static DEFINE_SPINLOCK(icmp6_dst_lock); |
951 | 980 | ||
@@ -979,9 +1008,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
979 | rt->rt6i_idev = idev; | 1008 | rt->rt6i_idev = idev; |
980 | rt->rt6i_nexthop = neigh; | 1009 | rt->rt6i_nexthop = neigh; |
981 | atomic_set(&rt->dst.__refcnt, 1); | 1010 | atomic_set(&rt->dst.__refcnt, 1); |
982 | rt->dst.metrics[RTAX_HOPLIMIT-1] = 255; | 1011 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); |
983 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); | ||
984 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); | ||
985 | rt->dst.output = ip6_output; | 1012 | rt->dst.output = ip6_output; |
986 | 1013 | ||
987 | #if 0 /* there's no chance to use these for ndisc */ | 1014 | #if 0 /* there's no chance to use these for ndisc */ |
@@ -1080,23 +1107,10 @@ out: | |||
1080 | Remove it only when all the things will work! | 1107 | Remove it only when all the things will work! |
1081 | */ | 1108 | */ |
1082 | 1109 | ||
1083 | static int ipv6_get_mtu(struct net_device *dev) | ||
1084 | { | ||
1085 | int mtu = IPV6_MIN_MTU; | ||
1086 | struct inet6_dev *idev; | ||
1087 | |||
1088 | rcu_read_lock(); | ||
1089 | idev = __in6_dev_get(dev); | ||
1090 | if (idev) | ||
1091 | mtu = idev->cnf.mtu6; | ||
1092 | rcu_read_unlock(); | ||
1093 | return mtu; | ||
1094 | } | ||
1095 | |||
1096 | int ip6_dst_hoplimit(struct dst_entry *dst) | 1110 | int ip6_dst_hoplimit(struct dst_entry *dst) |
1097 | { | 1111 | { |
1098 | int hoplimit = dst_metric(dst, RTAX_HOPLIMIT); | 1112 | int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); |
1099 | if (hoplimit < 0) { | 1113 | if (hoplimit == 0) { |
1100 | struct net_device *dev = dst->dev; | 1114 | struct net_device *dev = dst->dev; |
1101 | struct inet6_dev *idev; | 1115 | struct inet6_dev *idev; |
1102 | 1116 | ||
@@ -1110,6 +1124,7 @@ int ip6_dst_hoplimit(struct dst_entry *dst) | |||
1110 | } | 1124 | } |
1111 | return hoplimit; | 1125 | return hoplimit; |
1112 | } | 1126 | } |
1127 | EXPORT_SYMBOL(ip6_dst_hoplimit); | ||
1113 | 1128 | ||
1114 | /* | 1129 | /* |
1115 | * | 1130 | * |
@@ -1295,17 +1310,11 @@ install_route: | |||
1295 | goto out; | 1310 | goto out; |
1296 | } | 1311 | } |
1297 | 1312 | ||
1298 | rt->dst.metrics[type - 1] = nla_get_u32(nla); | 1313 | dst_metric_set(&rt->dst, type, nla_get_u32(nla)); |
1299 | } | 1314 | } |
1300 | } | 1315 | } |
1301 | } | 1316 | } |
1302 | 1317 | ||
1303 | if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0) | ||
1304 | rt->dst.metrics[RTAX_HOPLIMIT-1] = -1; | ||
1305 | if (!dst_mtu(&rt->dst)) | ||
1306 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); | ||
1307 | if (!dst_metric(&rt->dst, RTAX_ADVMSS)) | ||
1308 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); | ||
1309 | rt->dst.dev = dev; | 1318 | rt->dst.dev = dev; |
1310 | rt->rt6i_idev = idev; | 1319 | rt->rt6i_idev = idev; |
1311 | rt->rt6i_table = table; | 1320 | rt->rt6i_table = table; |
@@ -1463,12 +1472,8 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | |||
1463 | struct ip6rd_flowi rdfl = { | 1472 | struct ip6rd_flowi rdfl = { |
1464 | .fl = { | 1473 | .fl = { |
1465 | .oif = dev->ifindex, | 1474 | .oif = dev->ifindex, |
1466 | .nl_u = { | 1475 | .fl6_dst = *dest, |
1467 | .ip6_u = { | 1476 | .fl6_src = *src, |
1468 | .daddr = *dest, | ||
1469 | .saddr = *src, | ||
1470 | }, | ||
1471 | }, | ||
1472 | }, | 1477 | }, |
1473 | }; | 1478 | }; |
1474 | 1479 | ||
@@ -1534,10 +1539,6 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | |||
1534 | 1539 | ||
1535 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); | 1540 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); |
1536 | nrt->rt6i_nexthop = neigh_clone(neigh); | 1541 | nrt->rt6i_nexthop = neigh_clone(neigh); |
1537 | /* Reset pmtu, it may be better */ | ||
1538 | nrt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); | ||
1539 | nrt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev), | ||
1540 | dst_mtu(&nrt->dst)); | ||
1541 | 1542 | ||
1542 | if (ip6_ins_rt(nrt)) | 1543 | if (ip6_ins_rt(nrt)) |
1543 | goto out; | 1544 | goto out; |
@@ -1601,9 +1602,12 @@ again: | |||
1601 | would return automatically. | 1602 | would return automatically. |
1602 | */ | 1603 | */ |
1603 | if (rt->rt6i_flags & RTF_CACHE) { | 1604 | if (rt->rt6i_flags & RTF_CACHE) { |
1604 | rt->dst.metrics[RTAX_MTU-1] = pmtu; | 1605 | dst_metric_set(&rt->dst, RTAX_MTU, pmtu); |
1605 | if (allfrag) | 1606 | if (allfrag) { |
1606 | rt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1607 | u32 features = dst_metric(&rt->dst, RTAX_FEATURES); |
1608 | features |= RTAX_FEATURE_ALLFRAG; | ||
1609 | dst_metric_set(&rt->dst, RTAX_FEATURES, features); | ||
1610 | } | ||
1607 | dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); | 1611 | dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); |
1608 | rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; | 1612 | rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; |
1609 | goto out; | 1613 | goto out; |
@@ -1620,9 +1624,12 @@ again: | |||
1620 | nrt = rt6_alloc_clone(rt, daddr); | 1624 | nrt = rt6_alloc_clone(rt, daddr); |
1621 | 1625 | ||
1622 | if (nrt) { | 1626 | if (nrt) { |
1623 | nrt->dst.metrics[RTAX_MTU-1] = pmtu; | 1627 | dst_metric_set(&nrt->dst, RTAX_MTU, pmtu); |
1624 | if (allfrag) | 1628 | if (allfrag) { |
1625 | nrt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1629 | u32 features = dst_metric(&nrt->dst, RTAX_FEATURES); |
1630 | features |= RTAX_FEATURE_ALLFRAG; | ||
1631 | dst_metric_set(&nrt->dst, RTAX_FEATURES, features); | ||
1632 | } | ||
1626 | 1633 | ||
1627 | /* According to RFC 1981, detecting PMTU increase shouldn't be | 1634 | /* According to RFC 1981, detecting PMTU increase shouldn't be |
1628 | * happened within 5 mins, the recommended timer is 10 mins. | 1635 | * happened within 5 mins, the recommended timer is 10 mins. |
@@ -1673,7 +1680,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1673 | rt->dst.input = ort->dst.input; | 1680 | rt->dst.input = ort->dst.input; |
1674 | rt->dst.output = ort->dst.output; | 1681 | rt->dst.output = ort->dst.output; |
1675 | 1682 | ||
1676 | memcpy(rt->dst.metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); | 1683 | dst_copy_metrics(&rt->dst, &ort->dst); |
1677 | rt->dst.error = ort->dst.error; | 1684 | rt->dst.error = ort->dst.error; |
1678 | rt->dst.dev = ort->dst.dev; | 1685 | rt->dst.dev = ort->dst.dev; |
1679 | if (rt->dst.dev) | 1686 | if (rt->dst.dev) |
@@ -1965,9 +1972,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1965 | rt->dst.output = ip6_output; | 1972 | rt->dst.output = ip6_output; |
1966 | rt->rt6i_dev = net->loopback_dev; | 1973 | rt->rt6i_dev = net->loopback_dev; |
1967 | rt->rt6i_idev = idev; | 1974 | rt->rt6i_idev = idev; |
1968 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); | 1975 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1); |
1969 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); | ||
1970 | rt->dst.metrics[RTAX_HOPLIMIT-1] = -1; | ||
1971 | rt->dst.obsolete = -1; | 1976 | rt->dst.obsolete = -1; |
1972 | 1977 | ||
1973 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; | 1978 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; |
@@ -2004,11 +2009,11 @@ struct arg_dev_net { | |||
2004 | 2009 | ||
2005 | static int fib6_ifdown(struct rt6_info *rt, void *arg) | 2010 | static int fib6_ifdown(struct rt6_info *rt, void *arg) |
2006 | { | 2011 | { |
2007 | struct net_device *dev = ((struct arg_dev_net *)arg)->dev; | 2012 | const struct arg_dev_net *adn = arg; |
2008 | struct net *net = ((struct arg_dev_net *)arg)->net; | 2013 | const struct net_device *dev = adn->dev; |
2009 | 2014 | ||
2010 | if (((void *)rt->rt6i_dev == dev || dev == NULL) && | 2015 | if ((rt->rt6i_dev == dev || dev == NULL) && |
2011 | rt != net->ipv6.ip6_null_entry) { | 2016 | rt != adn->net->ipv6.ip6_null_entry) { |
2012 | RT6_TRACE("deleted by ifdown %p\n", rt); | 2017 | RT6_TRACE("deleted by ifdown %p\n", rt); |
2013 | return -1; | 2018 | return -1; |
2014 | } | 2019 | } |
@@ -2036,7 +2041,6 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
2036 | { | 2041 | { |
2037 | struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; | 2042 | struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; |
2038 | struct inet6_dev *idev; | 2043 | struct inet6_dev *idev; |
2039 | struct net *net = dev_net(arg->dev); | ||
2040 | 2044 | ||
2041 | /* In IPv6 pmtu discovery is not optional, | 2045 | /* In IPv6 pmtu discovery is not optional, |
2042 | so that RTAX_MTU lock cannot disable it. | 2046 | so that RTAX_MTU lock cannot disable it. |
@@ -2067,8 +2071,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
2067 | (dst_mtu(&rt->dst) >= arg->mtu || | 2071 | (dst_mtu(&rt->dst) >= arg->mtu || |
2068 | (dst_mtu(&rt->dst) < arg->mtu && | 2072 | (dst_mtu(&rt->dst) < arg->mtu && |
2069 | dst_mtu(&rt->dst) == idev->cnf.mtu6))) { | 2073 | dst_mtu(&rt->dst) == idev->cnf.mtu6))) { |
2070 | rt->dst.metrics[RTAX_MTU-1] = arg->mtu; | 2074 | dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu); |
2071 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu); | ||
2072 | } | 2075 | } |
2073 | return 0; | 2076 | return 0; |
2074 | } | 2077 | } |
@@ -2294,7 +2297,7 @@ static int rt6_fill_node(struct net *net, | |||
2294 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2297 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
2295 | } | 2298 | } |
2296 | 2299 | ||
2297 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) | 2300 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2298 | goto nla_put_failure; | 2301 | goto nla_put_failure; |
2299 | 2302 | ||
2300 | if (rt->dst.neighbour) | 2303 | if (rt->dst.neighbour) |
@@ -2470,8 +2473,6 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
2470 | 2473 | ||
2471 | #ifdef CONFIG_PROC_FS | 2474 | #ifdef CONFIG_PROC_FS |
2472 | 2475 | ||
2473 | #define RT6_INFO_LEN (32 + 4 + 32 + 4 + 32 + 40 + 5 + 1) | ||
2474 | |||
2475 | struct rt6_proc_arg | 2476 | struct rt6_proc_arg |
2476 | { | 2477 | { |
2477 | char *buffer; | 2478 | char *buffer; |
@@ -2687,6 +2688,7 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2687 | net->ipv6.ip6_null_entry->dst.path = | 2688 | net->ipv6.ip6_null_entry->dst.path = |
2688 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2689 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
2689 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2690 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2691 | dst_metric_set(&net->ipv6.ip6_null_entry->dst, RTAX_HOPLIMIT, 255); | ||
2690 | 2692 | ||
2691 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2693 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
2692 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, | 2694 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, |
@@ -2697,6 +2699,7 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2697 | net->ipv6.ip6_prohibit_entry->dst.path = | 2699 | net->ipv6.ip6_prohibit_entry->dst.path = |
2698 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | 2700 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; |
2699 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2701 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2702 | dst_metric_set(&net->ipv6.ip6_prohibit_entry->dst, RTAX_HOPLIMIT, 255); | ||
2700 | 2703 | ||
2701 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, | 2704 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, |
2702 | sizeof(*net->ipv6.ip6_blk_hole_entry), | 2705 | sizeof(*net->ipv6.ip6_blk_hole_entry), |
@@ -2706,6 +2709,7 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2706 | net->ipv6.ip6_blk_hole_entry->dst.path = | 2709 | net->ipv6.ip6_blk_hole_entry->dst.path = |
2707 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | 2710 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; |
2708 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2711 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2712 | dst_metric_set(&net->ipv6.ip6_blk_hole_entry->dst, RTAX_HOPLIMIT, 255); | ||
2709 | #endif | 2713 | #endif |
2710 | 2714 | ||
2711 | net->ipv6.sysctl.flush_delay = 0; | 2715 | net->ipv6.sysctl.flush_delay = 0; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 8c4d00c7cd2b..8ce38f10a547 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -731,10 +731,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
731 | } | 731 | } |
732 | 732 | ||
733 | { | 733 | { |
734 | struct flowi fl = { .nl_u = { .ip4_u = | 734 | struct flowi fl = { .fl4_dst = dst, |
735 | { .daddr = dst, | 735 | .fl4_src = tiph->saddr, |
736 | .saddr = tiph->saddr, | 736 | .fl4_tos = RT_TOS(tos), |
737 | .tos = RT_TOS(tos) } }, | ||
738 | .oif = tunnel->parms.link, | 737 | .oif = tunnel->parms.link, |
739 | .proto = IPPROTO_IPV6 }; | 738 | .proto = IPPROTO_IPV6 }; |
740 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 739 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { |
@@ -856,10 +855,9 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
856 | iph = &tunnel->parms.iph; | 855 | iph = &tunnel->parms.iph; |
857 | 856 | ||
858 | if (iph->daddr) { | 857 | if (iph->daddr) { |
859 | struct flowi fl = { .nl_u = { .ip4_u = | 858 | struct flowi fl = { .fl4_dst = iph->daddr, |
860 | { .daddr = iph->daddr, | 859 | .fl4_src = iph->saddr, |
861 | .saddr = iph->saddr, | 860 | .fl4_tos = RT_TOS(iph->tos), |
862 | .tos = RT_TOS(iph->tos) } }, | ||
863 | .oif = tunnel->parms.link, | 861 | .oif = tunnel->parms.link, |
864 | .proto = IPPROTO_IPV6 }; | 862 | .proto = IPPROTO_IPV6 }; |
865 | struct rtable *rt; | 863 | struct rtable *rt; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7e41e2cbb85e..20aa95e37359 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -130,6 +130,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
130 | struct ipv6_pinfo *np = inet6_sk(sk); | 130 | struct ipv6_pinfo *np = inet6_sk(sk); |
131 | struct tcp_sock *tp = tcp_sk(sk); | 131 | struct tcp_sock *tp = tcp_sk(sk); |
132 | struct in6_addr *saddr = NULL, *final_p, final; | 132 | struct in6_addr *saddr = NULL, *final_p, final; |
133 | struct rt6_info *rt; | ||
133 | struct flowi fl; | 134 | struct flowi fl; |
134 | struct dst_entry *dst; | 135 | struct dst_entry *dst; |
135 | int addr_type; | 136 | int addr_type; |
@@ -280,6 +281,26 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
280 | sk->sk_gso_type = SKB_GSO_TCPV6; | 281 | sk->sk_gso_type = SKB_GSO_TCPV6; |
281 | __ip6_dst_store(sk, dst, NULL, NULL); | 282 | __ip6_dst_store(sk, dst, NULL, NULL); |
282 | 283 | ||
284 | rt = (struct rt6_info *) dst; | ||
285 | if (tcp_death_row.sysctl_tw_recycle && | ||
286 | !tp->rx_opt.ts_recent_stamp && | ||
287 | ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) { | ||
288 | struct inet_peer *peer = rt6_get_peer(rt); | ||
289 | /* | ||
290 | * VJ's idea. We save last timestamp seen from | ||
291 | * the destination in peer table, when entering state | ||
292 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, | ||
293 | * when trying new connection. | ||
294 | */ | ||
295 | if (peer) { | ||
296 | inet_peer_refcheck(peer); | ||
297 | if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { | ||
298 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; | ||
299 | tp->rx_opt.ts_recent = peer->tcp_ts; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | |||
283 | icsk->icsk_ext_hdr_len = 0; | 304 | icsk->icsk_ext_hdr_len = 0; |
284 | if (np->opt) | 305 | if (np->opt) |
285 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | 306 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + |
@@ -906,12 +927,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | |||
906 | }; | 927 | }; |
907 | #endif | 928 | #endif |
908 | 929 | ||
909 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
910 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
911 | .twsk_unique = tcp_twsk_unique, | ||
912 | .twsk_destructor= tcp_twsk_destructor, | ||
913 | }; | ||
914 | |||
915 | static void __tcp_v6_send_check(struct sk_buff *skb, | 930 | static void __tcp_v6_send_check(struct sk_buff *skb, |
916 | struct in6_addr *saddr, struct in6_addr *daddr) | 931 | struct in6_addr *saddr, struct in6_addr *daddr) |
917 | { | 932 | { |
@@ -1176,6 +1191,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1176 | struct ipv6_pinfo *np = inet6_sk(sk); | 1191 | struct ipv6_pinfo *np = inet6_sk(sk); |
1177 | struct tcp_sock *tp = tcp_sk(sk); | 1192 | struct tcp_sock *tp = tcp_sk(sk); |
1178 | __u32 isn = TCP_SKB_CB(skb)->when; | 1193 | __u32 isn = TCP_SKB_CB(skb)->when; |
1194 | struct dst_entry *dst = NULL; | ||
1179 | #ifdef CONFIG_SYN_COOKIES | 1195 | #ifdef CONFIG_SYN_COOKIES |
1180 | int want_cookie = 0; | 1196 | int want_cookie = 0; |
1181 | #else | 1197 | #else |
@@ -1273,6 +1289,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1273 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1289 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
1274 | 1290 | ||
1275 | if (!isn) { | 1291 | if (!isn) { |
1292 | struct inet_peer *peer = NULL; | ||
1293 | |||
1276 | if (ipv6_opt_accepted(sk, skb) || | 1294 | if (ipv6_opt_accepted(sk, skb) || |
1277 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1295 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
1278 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1296 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
@@ -1285,13 +1303,57 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1285 | if (!sk->sk_bound_dev_if && | 1303 | if (!sk->sk_bound_dev_if && |
1286 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 1304 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
1287 | treq->iif = inet6_iif(skb); | 1305 | treq->iif = inet6_iif(skb); |
1288 | if (!want_cookie) { | 1306 | |
1289 | isn = tcp_v6_init_sequence(skb); | 1307 | if (want_cookie) { |
1290 | } else { | ||
1291 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | 1308 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); |
1292 | req->cookie_ts = tmp_opt.tstamp_ok; | 1309 | req->cookie_ts = tmp_opt.tstamp_ok; |
1310 | goto have_isn; | ||
1293 | } | 1311 | } |
1312 | |||
1313 | /* VJ's idea. We save last timestamp seen | ||
1314 | * from the destination in peer table, when entering | ||
1315 | * state TIME-WAIT, and check against it before | ||
1316 | * accepting new connection request. | ||
1317 | * | ||
1318 | * If "isn" is not zero, this request hit alive | ||
1319 | * timewait bucket, so that all the necessary checks | ||
1320 | * are made in the function processing timewait state. | ||
1321 | */ | ||
1322 | if (tmp_opt.saw_tstamp && | ||
1323 | tcp_death_row.sysctl_tw_recycle && | ||
1324 | (dst = inet6_csk_route_req(sk, req)) != NULL && | ||
1325 | (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL && | ||
1326 | ipv6_addr_equal((struct in6_addr *)peer->daddr.a6, | ||
1327 | &treq->rmt_addr)) { | ||
1328 | inet_peer_refcheck(peer); | ||
1329 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && | ||
1330 | (s32)(peer->tcp_ts - req->ts_recent) > | ||
1331 | TCP_PAWS_WINDOW) { | ||
1332 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
1333 | goto drop_and_release; | ||
1334 | } | ||
1335 | } | ||
1336 | /* Kill the following clause, if you dislike this way. */ | ||
1337 | else if (!sysctl_tcp_syncookies && | ||
1338 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
1339 | (sysctl_max_syn_backlog >> 2)) && | ||
1340 | (!peer || !peer->tcp_ts_stamp) && | ||
1341 | (!dst || !dst_metric(dst, RTAX_RTT))) { | ||
1342 | /* Without syncookies last quarter of | ||
1343 | * backlog is filled with destinations, | ||
1344 | * proven to be alive. | ||
1345 | * It means that we continue to communicate | ||
1346 | * to destinations, already remembered | ||
1347 | * to the moment of synflood. | ||
1348 | */ | ||
1349 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", | ||
1350 | &treq->rmt_addr, ntohs(tcp_hdr(skb)->source)); | ||
1351 | goto drop_and_release; | ||
1352 | } | ||
1353 | |||
1354 | isn = tcp_v6_init_sequence(skb); | ||
1294 | } | 1355 | } |
1356 | have_isn: | ||
1295 | tcp_rsk(req)->snt_isn = isn; | 1357 | tcp_rsk(req)->snt_isn = isn; |
1296 | 1358 | ||
1297 | security_inet_conn_request(sk, skb, req); | 1359 | security_inet_conn_request(sk, skb, req); |
@@ -1304,6 +1366,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1304 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1366 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
1305 | return 0; | 1367 | return 0; |
1306 | 1368 | ||
1369 | drop_and_release: | ||
1370 | dst_release(dst); | ||
1307 | drop_and_free: | 1371 | drop_and_free: |
1308 | reqsk_free(req); | 1372 | reqsk_free(req); |
1309 | drop: | 1373 | drop: |
@@ -1382,28 +1446,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1382 | if (sk_acceptq_is_full(sk)) | 1446 | if (sk_acceptq_is_full(sk)) |
1383 | goto out_overflow; | 1447 | goto out_overflow; |
1384 | 1448 | ||
1385 | if (dst == NULL) { | 1449 | if (!dst) { |
1386 | struct in6_addr *final_p, final; | 1450 | dst = inet6_csk_route_req(sk, req); |
1387 | struct flowi fl; | 1451 | if (!dst) |
1388 | |||
1389 | memset(&fl, 0, sizeof(fl)); | ||
1390 | fl.proto = IPPROTO_TCP; | ||
1391 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | ||
1392 | final_p = fl6_update_dst(&fl, opt, &final); | ||
1393 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | ||
1394 | fl.oif = sk->sk_bound_dev_if; | ||
1395 | fl.mark = sk->sk_mark; | ||
1396 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | ||
1397 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | ||
1398 | security_req_classify_flow(req, &fl); | ||
1399 | |||
1400 | if (ip6_dst_lookup(sk, &dst, &fl)) | ||
1401 | goto out; | ||
1402 | |||
1403 | if (final_p) | ||
1404 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
1405 | |||
1406 | if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | ||
1407 | goto out; | 1452 | goto out; |
1408 | } | 1453 | } |
1409 | 1454 | ||
@@ -1476,7 +1521,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1476 | 1521 | ||
1477 | tcp_mtup_init(newsk); | 1522 | tcp_mtup_init(newsk); |
1478 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1523 | tcp_sync_mss(newsk, dst_mtu(dst)); |
1479 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1524 | newtp->advmss = dst_metric_advmss(dst); |
1480 | tcp_initialize_rcv_mss(newsk); | 1525 | tcp_initialize_rcv_mss(newsk); |
1481 | 1526 | ||
1482 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; | 1527 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; |
@@ -1818,19 +1863,51 @@ do_time_wait: | |||
1818 | goto discard_it; | 1863 | goto discard_it; |
1819 | } | 1864 | } |
1820 | 1865 | ||
1821 | static int tcp_v6_remember_stamp(struct sock *sk) | 1866 | static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) |
1822 | { | 1867 | { |
1823 | /* Alas, not yet... */ | 1868 | struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk); |
1824 | return 0; | 1869 | struct ipv6_pinfo *np = inet6_sk(sk); |
1870 | struct inet_peer *peer; | ||
1871 | |||
1872 | if (!rt || | ||
1873 | !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) { | ||
1874 | peer = inet_getpeer_v6(&np->daddr, 1); | ||
1875 | *release_it = true; | ||
1876 | } else { | ||
1877 | if (!rt->rt6i_peer) | ||
1878 | rt6_bind_peer(rt, 1); | ||
1879 | peer = rt->rt6i_peer; | ||
1880 | *release_it = false; | ||
1881 | } | ||
1882 | |||
1883 | return peer; | ||
1825 | } | 1884 | } |
1826 | 1885 | ||
1886 | static void *tcp_v6_tw_get_peer(struct sock *sk) | ||
1887 | { | ||
1888 | struct inet6_timewait_sock *tw6 = inet6_twsk(sk); | ||
1889 | struct inet_timewait_sock *tw = inet_twsk(sk); | ||
1890 | |||
1891 | if (tw->tw_family == AF_INET) | ||
1892 | return tcp_v4_tw_get_peer(sk); | ||
1893 | |||
1894 | return inet_getpeer_v6(&tw6->tw_v6_daddr, 1); | ||
1895 | } | ||
1896 | |||
1897 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
1898 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
1899 | .twsk_unique = tcp_twsk_unique, | ||
1900 | .twsk_destructor= tcp_twsk_destructor, | ||
1901 | .twsk_getpeer = tcp_v6_tw_get_peer, | ||
1902 | }; | ||
1903 | |||
1827 | static const struct inet_connection_sock_af_ops ipv6_specific = { | 1904 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
1828 | .queue_xmit = inet6_csk_xmit, | 1905 | .queue_xmit = inet6_csk_xmit, |
1829 | .send_check = tcp_v6_send_check, | 1906 | .send_check = tcp_v6_send_check, |
1830 | .rebuild_header = inet6_sk_rebuild_header, | 1907 | .rebuild_header = inet6_sk_rebuild_header, |
1831 | .conn_request = tcp_v6_conn_request, | 1908 | .conn_request = tcp_v6_conn_request, |
1832 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1909 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1833 | .remember_stamp = tcp_v6_remember_stamp, | 1910 | .get_peer = tcp_v6_get_peer, |
1834 | .net_header_len = sizeof(struct ipv6hdr), | 1911 | .net_header_len = sizeof(struct ipv6hdr), |
1835 | .setsockopt = ipv6_setsockopt, | 1912 | .setsockopt = ipv6_setsockopt, |
1836 | .getsockopt = ipv6_getsockopt, | 1913 | .getsockopt = ipv6_getsockopt, |
@@ -1862,7 +1939,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1862 | .rebuild_header = inet_sk_rebuild_header, | 1939 | .rebuild_header = inet_sk_rebuild_header, |
1863 | .conn_request = tcp_v6_conn_request, | 1940 | .conn_request = tcp_v6_conn_request, |
1864 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1941 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1865 | .remember_stamp = tcp_v4_remember_stamp, | 1942 | .get_peer = tcp_v4_get_peer, |
1866 | .net_header_len = sizeof(struct iphdr), | 1943 | .net_header_len = sizeof(struct iphdr), |
1867 | .setsockopt = ipv6_setsockopt, | 1944 | .setsockopt = ipv6_setsockopt, |
1868 | .getsockopt = ipv6_getsockopt, | 1945 | .getsockopt = ipv6_getsockopt, |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index cd6cb7c3e563..9a009c66c8a3 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -54,8 +54,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
54 | { | 54 | { |
55 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | 55 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; |
56 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 56 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
57 | __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr; | 57 | __be32 sk1_rcv_saddr = sk_rcv_saddr(sk); |
58 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 58 | __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); |
59 | int sk_ipv6only = ipv6_only_sock(sk); | 59 | int sk_ipv6only = ipv6_only_sock(sk); |
60 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 60 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
61 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); | 61 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); |
@@ -227,7 +227,7 @@ begin: | |||
227 | 227 | ||
228 | if (result) { | 228 | if (result) { |
229 | exact_match: | 229 | exact_match: |
230 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | 230 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) |
231 | result = NULL; | 231 | result = NULL; |
232 | else if (unlikely(compute_score2(result, net, saddr, sport, | 232 | else if (unlikely(compute_score2(result, net, saddr, sport, |
233 | daddr, hnum, dif) < badness)) { | 233 | daddr, hnum, dif) < badness)) { |
@@ -294,7 +294,7 @@ begin: | |||
294 | goto begin; | 294 | goto begin; |
295 | 295 | ||
296 | if (result) { | 296 | if (result) { |
297 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | 297 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) |
298 | result = NULL; | 298 | result = NULL; |
299 | else if (unlikely(compute_score(result, net, hnum, saddr, sport, | 299 | else if (unlikely(compute_score(result, net, hnum, saddr, sport, |
300 | daddr, dport, dif) < badness)) { | 300 | daddr, dport, dif) < badness)) { |
@@ -602,7 +602,7 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
602 | 602 | ||
603 | sk = stack[i]; | 603 | sk = stack[i]; |
604 | if (skb1) { | 604 | if (skb1) { |
605 | if (sk_rcvqueues_full(sk, skb)) { | 605 | if (sk_rcvqueues_full(sk, skb1)) { |
606 | kfree_skb(skb1); | 606 | kfree_skb(skb1); |
607 | goto drop; | 607 | goto drop; |
608 | } | 608 | } |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index b809812c8d30..645cb968d450 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <net/dsfield.h> | 14 | #include <net/dsfield.h> |
15 | #include <net/dst.h> | 15 | #include <net/dst.h> |
16 | #include <net/inet_ecn.h> | 16 | #include <net/inet_ecn.h> |
17 | #include <net/ip6_route.h> | ||
17 | #include <net/ipv6.h> | 18 | #include <net/ipv6.h> |
18 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
19 | 20 | ||
@@ -53,7 +54,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
53 | if (x->props.flags & XFRM_STATE_NOECN) | 54 | if (x->props.flags & XFRM_STATE_NOECN) |
54 | dsfield &= ~INET_ECN_MASK; | 55 | dsfield &= ~INET_ECN_MASK; |
55 | ipv6_change_dsfield(top_iph, 0, dsfield); | 56 | ipv6_change_dsfield(top_iph, 0, dsfield); |
56 | top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); | 57 | top_iph->hop_limit = ip6_dst_hoplimit(dst->child); |
57 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | 58 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); |
58 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | 59 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); |
59 | return 0; | 60 | return 0; |
diff --git a/net/irda/ircomm/Makefile b/net/irda/ircomm/Makefile index 48689458c086..ab23b5ba7e33 100644 --- a/net/irda/ircomm/Makefile +++ b/net/irda/ircomm/Makefile | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_IRCOMM) += ircomm.o ircomm-tty.o | 5 | obj-$(CONFIG_IRCOMM) += ircomm.o ircomm-tty.o |
6 | 6 | ||
7 | ircomm-objs := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o | 7 | ircomm-y := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o |
8 | ircomm-tty-objs := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o | 8 | ircomm-tty-y := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o |
diff --git a/net/irda/irlan/Makefile b/net/irda/irlan/Makefile index 77549bc8641b..94eefbc8e6b9 100644 --- a/net/irda/irlan/Makefile +++ b/net/irda/irlan/Makefile | |||
@@ -4,4 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_IRLAN) += irlan.o | 5 | obj-$(CONFIG_IRLAN) += irlan.o |
6 | 6 | ||
7 | irlan-objs := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o | 7 | irlan-y := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o |
diff --git a/net/irda/irnet/Makefile b/net/irda/irnet/Makefile index b3ee01e0def3..61c365c8a2a0 100644 --- a/net/irda/irnet/Makefile +++ b/net/irda/irnet/Makefile | |||
@@ -4,4 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_IRNET) += irnet.o | 5 | obj-$(CONFIG_IRNET) += irnet.o |
6 | 6 | ||
7 | irnet-objs := irnet_ppp.o irnet_irda.o | 7 | irnet-y := irnet_ppp.o irnet_irda.o |
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 522e219f3558..110efb704c9b 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -476,15 +476,13 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
476 | 476 | ||
477 | { | 477 | { |
478 | struct flowi fl = { .oif = sk->sk_bound_dev_if, | 478 | struct flowi fl = { .oif = sk->sk_bound_dev_if, |
479 | .nl_u = { .ip4_u = { | 479 | .fl4_dst = daddr, |
480 | .daddr = daddr, | 480 | .fl4_src = inet->inet_saddr, |
481 | .saddr = inet->inet_saddr, | 481 | .fl4_tos = RT_CONN_FLAGS(sk), |
482 | .tos = RT_CONN_FLAGS(sk) } }, | ||
483 | .proto = sk->sk_protocol, | 482 | .proto = sk->sk_protocol, |
484 | .flags = inet_sk_flowi_flags(sk), | 483 | .flags = inet_sk_flowi_flags(sk), |
485 | .uli_u = { .ports = { | 484 | .fl_ip_sport = inet->inet_sport, |
486 | .sport = inet->inet_sport, | 485 | .fl_ip_dport = inet->inet_dport }; |
487 | .dport = inet->inet_dport } } }; | ||
488 | 486 | ||
489 | /* If this fails, retransmit mechanism of transport layer will | 487 | /* If this fails, retransmit mechanism of transport layer will |
490 | * keep trying until route appears or the connection times | 488 | * keep trying until route appears or the connection times |
diff --git a/net/lapb/Makefile b/net/lapb/Makefile index 53f7c90db163..fff797dfc88c 100644 --- a/net/lapb/Makefile +++ b/net/lapb/Makefile | |||
@@ -4,4 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_LAPB) += lapb.o | 5 | obj-$(CONFIG_LAPB) += lapb.o |
6 | 6 | ||
7 | lapb-objs := lapb_in.o lapb_out.o lapb_subr.o lapb_timer.o lapb_iface.o | 7 | lapb-y := lapb_in.o lapb_out.o lapb_subr.o lapb_timer.o lapb_iface.o |
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index e35dbe55f520..dfd3a648a551 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
@@ -316,7 +316,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
316 | if (unlikely(addr->sllc_family != AF_LLC)) | 316 | if (unlikely(addr->sllc_family != AF_LLC)) |
317 | goto out; | 317 | goto out; |
318 | rc = -ENODEV; | 318 | rc = -ENODEV; |
319 | rtnl_lock(); | ||
320 | rcu_read_lock(); | 319 | rcu_read_lock(); |
321 | if (sk->sk_bound_dev_if) { | 320 | if (sk->sk_bound_dev_if) { |
322 | llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); | 321 | llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); |
@@ -334,10 +333,11 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
334 | } | 333 | } |
335 | } | 334 | } |
336 | } else | 335 | } else |
337 | llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, | 336 | llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, |
338 | addr->sllc_mac); | 337 | addr->sllc_mac); |
338 | if (llc->dev) | ||
339 | dev_hold(llc->dev); | ||
339 | rcu_read_unlock(); | 340 | rcu_read_unlock(); |
340 | rtnl_unlock(); | ||
341 | if (!llc->dev) | 341 | if (!llc->dev) |
342 | goto out; | 342 | goto out; |
343 | if (!addr->sllc_sap) { | 343 | if (!addr->sllc_sap) { |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 8e8ea9cb7093..9109262abd24 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -6,6 +6,7 @@ config MAC80211 | |||
6 | select CRYPTO_ARC4 | 6 | select CRYPTO_ARC4 |
7 | select CRYPTO_AES | 7 | select CRYPTO_AES |
8 | select CRC32 | 8 | select CRC32 |
9 | select AVERAGE | ||
9 | ---help--- | 10 | ---help--- |
10 | This option enables the hardware independent IEEE 802.11 | 11 | This option enables the hardware independent IEEE 802.11 |
11 | networking stack. | 12 | networking stack. |
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index d2b03e0851ef..4bd6ef0be380 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -147,6 +147,5 @@ struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) | |||
147 | 147 | ||
148 | void ieee80211_aes_key_free(struct crypto_cipher *tfm) | 148 | void ieee80211_aes_key_free(struct crypto_cipher *tfm) |
149 | { | 149 | { |
150 | if (tfm) | 150 | crypto_free_cipher(tfm); |
151 | crypto_free_cipher(tfm); | ||
152 | } | 151 | } |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index b4d66cca76d6..d502b2684a66 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
@@ -128,6 +128,5 @@ struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]) | |||
128 | 128 | ||
129 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm) | 129 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm) |
130 | { | 130 | { |
131 | if (tfm) | 131 | crypto_free_cipher(tfm); |
132 | crypto_free_cipher(tfm); | ||
133 | } | 132 | } |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 720b7a84af59..f138b195d657 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -129,9 +129,7 @@ static void sta_rx_agg_reorder_timer_expired(unsigned long data) | |||
129 | timer_to_tid[0]); | 129 | timer_to_tid[0]); |
130 | 130 | ||
131 | rcu_read_lock(); | 131 | rcu_read_lock(); |
132 | spin_lock(&sta->lock); | ||
133 | ieee80211_release_reorder_timeout(sta, *ptid); | 132 | ieee80211_release_reorder_timeout(sta, *ptid); |
134 | spin_unlock(&sta->lock); | ||
135 | rcu_read_unlock(); | 133 | rcu_read_unlock(); |
136 | } | 134 | } |
137 | 135 | ||
@@ -256,7 +254,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
256 | } | 254 | } |
257 | 255 | ||
258 | /* prepare A-MPDU MLME for Rx aggregation */ | 256 | /* prepare A-MPDU MLME for Rx aggregation */ |
259 | tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | 257 | tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); |
260 | if (!tid_agg_rx) { | 258 | if (!tid_agg_rx) { |
261 | #ifdef CONFIG_MAC80211_HT_DEBUG | 259 | #ifdef CONFIG_MAC80211_HT_DEBUG |
262 | if (net_ratelimit()) | 260 | if (net_ratelimit()) |
@@ -280,9 +278,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
280 | 278 | ||
281 | /* prepare reordering buffer */ | 279 | /* prepare reordering buffer */ |
282 | tid_agg_rx->reorder_buf = | 280 | tid_agg_rx->reorder_buf = |
283 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); | 281 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL); |
284 | tid_agg_rx->reorder_time = | 282 | tid_agg_rx->reorder_time = |
285 | kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC); | 283 | kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL); |
286 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { | 284 | if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { |
287 | #ifdef CONFIG_MAC80211_HT_DEBUG | 285 | #ifdef CONFIG_MAC80211_HT_DEBUG |
288 | if (net_ratelimit()) | 286 | if (net_ratelimit()) |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d4679b265ba8..9cc472c6a6a5 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -342,10 +342,11 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | |||
342 | /* send AddBA request */ | 342 | /* send AddBA request */ |
343 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, | 343 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, |
344 | tid_tx->dialog_token, start_seq_num, | 344 | tid_tx->dialog_token, start_seq_num, |
345 | 0x40, 5000); | 345 | 0x40, tid_tx->timeout); |
346 | } | 346 | } |
347 | 347 | ||
348 | int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | 348 | int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, |
349 | u16 timeout) | ||
349 | { | 350 | { |
350 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 351 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
351 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 352 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -420,6 +421,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
420 | skb_queue_head_init(&tid_tx->pending); | 421 | skb_queue_head_init(&tid_tx->pending); |
421 | __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); | 422 | __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); |
422 | 423 | ||
424 | tid_tx->timeout = timeout; | ||
425 | |||
423 | /* Tx timer */ | 426 | /* Tx timer */ |
424 | tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; | 427 | tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; |
425 | tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | 428 | tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 18bd0e550600..5892b0302454 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -19,9 +19,10 @@ | |||
19 | #include "rate.h" | 19 | #include "rate.h" |
20 | #include "mesh.h" | 20 | #include "mesh.h" |
21 | 21 | ||
22 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 22 | static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, |
23 | enum nl80211_iftype type, u32 *flags, | 23 | enum nl80211_iftype type, |
24 | struct vif_params *params) | 24 | u32 *flags, |
25 | struct vif_params *params) | ||
25 | { | 26 | { |
26 | struct ieee80211_local *local = wiphy_priv(wiphy); | 27 | struct ieee80211_local *local = wiphy_priv(wiphy); |
27 | struct net_device *dev; | 28 | struct net_device *dev; |
@@ -29,12 +30,15 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
29 | int err; | 30 | int err; |
30 | 31 | ||
31 | err = ieee80211_if_add(local, name, &dev, type, params); | 32 | err = ieee80211_if_add(local, name, &dev, type, params); |
32 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) | 33 | if (err) |
33 | return err; | 34 | return ERR_PTR(err); |
34 | 35 | ||
35 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 36 | if (type == NL80211_IFTYPE_MONITOR && flags) { |
36 | sdata->u.mntr_flags = *flags; | 37 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
37 | return 0; | 38 | sdata->u.mntr_flags = *flags; |
39 | } | ||
40 | |||
41 | return dev; | ||
38 | } | 42 | } |
39 | 43 | ||
40 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) | 44 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) |
@@ -56,11 +60,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
56 | if (ret) | 60 | if (ret) |
57 | return ret; | 61 | return ret; |
58 | 62 | ||
59 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | ||
60 | ieee80211_sdata_set_mesh_id(sdata, | ||
61 | params->mesh_id_len, | ||
62 | params->mesh_id); | ||
63 | |||
64 | if (type == NL80211_IFTYPE_AP_VLAN && | 63 | if (type == NL80211_IFTYPE_AP_VLAN && |
65 | params && params->use_4addr == 0) | 64 | params && params->use_4addr == 0) |
66 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | 65 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); |
@@ -296,11 +295,12 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
296 | 295 | ||
297 | static int ieee80211_config_default_key(struct wiphy *wiphy, | 296 | static int ieee80211_config_default_key(struct wiphy *wiphy, |
298 | struct net_device *dev, | 297 | struct net_device *dev, |
299 | u8 key_idx) | 298 | u8 key_idx, bool uni, |
299 | bool multi) | ||
300 | { | 300 | { |
301 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 301 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
302 | 302 | ||
303 | ieee80211_set_default_key(sdata, key_idx); | 303 | ieee80211_set_default_key(sdata, key_idx, uni, multi); |
304 | 304 | ||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
@@ -343,8 +343,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
343 | 343 | ||
344 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | 344 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
345 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | 345 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { |
346 | sinfo->filled |= STATION_INFO_SIGNAL; | 346 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; |
347 | sinfo->signal = (s8)sta->last_signal; | 347 | sinfo->signal = (s8)sta->last_signal; |
348 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
348 | } | 349 | } |
349 | 350 | ||
350 | sinfo->txrate.flags = 0; | 351 | sinfo->txrate.flags = 0; |
@@ -983,7 +984,7 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
983 | return 0; | 984 | return 0; |
984 | } | 985 | } |
985 | 986 | ||
986 | static int ieee80211_get_mesh_params(struct wiphy *wiphy, | 987 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, |
987 | struct net_device *dev, | 988 | struct net_device *dev, |
988 | struct mesh_config *conf) | 989 | struct mesh_config *conf) |
989 | { | 990 | { |
@@ -999,9 +1000,39 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) | |||
999 | return (mask >> (parm-1)) & 0x1; | 1000 | return (mask >> (parm-1)) & 0x1; |
1000 | } | 1001 | } |
1001 | 1002 | ||
1002 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, | 1003 | static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, |
1003 | struct net_device *dev, | 1004 | const struct mesh_setup *setup) |
1004 | const struct mesh_config *nconf, u32 mask) | 1005 | { |
1006 | u8 *new_ie; | ||
1007 | const u8 *old_ie; | ||
1008 | |||
1009 | /* first allocate the new vendor information element */ | ||
1010 | new_ie = NULL; | ||
1011 | old_ie = ifmsh->vendor_ie; | ||
1012 | |||
1013 | ifmsh->vendor_ie_len = setup->vendor_ie_len; | ||
1014 | if (setup->vendor_ie_len) { | ||
1015 | new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, | ||
1016 | GFP_KERNEL); | ||
1017 | if (!new_ie) | ||
1018 | return -ENOMEM; | ||
1019 | } | ||
1020 | |||
1021 | /* now copy the rest of the setup parameters */ | ||
1022 | ifmsh->mesh_id_len = setup->mesh_id_len; | ||
1023 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | ||
1024 | ifmsh->mesh_pp_id = setup->path_sel_proto; | ||
1025 | ifmsh->mesh_pm_id = setup->path_metric; | ||
1026 | ifmsh->vendor_ie = new_ie; | ||
1027 | |||
1028 | kfree(old_ie); | ||
1029 | |||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static int ieee80211_update_mesh_config(struct wiphy *wiphy, | ||
1034 | struct net_device *dev, u32 mask, | ||
1035 | const struct mesh_config *nconf) | ||
1005 | { | 1036 | { |
1006 | struct mesh_config *conf; | 1037 | struct mesh_config *conf; |
1007 | struct ieee80211_sub_if_data *sdata; | 1038 | struct ieee80211_sub_if_data *sdata; |
@@ -1024,6 +1055,8 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1024 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; | 1055 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; |
1025 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) | 1056 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) |
1026 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1057 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1058 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) | ||
1059 | conf->dot11MeshTTL = nconf->element_ttl; | ||
1027 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1060 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) |
1028 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1061 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1029 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) | 1062 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) |
@@ -1050,6 +1083,31 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1050 | return 0; | 1083 | return 0; |
1051 | } | 1084 | } |
1052 | 1085 | ||
1086 | static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | ||
1087 | const struct mesh_config *conf, | ||
1088 | const struct mesh_setup *setup) | ||
1089 | { | ||
1090 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1091 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
1092 | int err; | ||
1093 | |||
1094 | memcpy(&ifmsh->mshcfg, conf, sizeof(struct mesh_config)); | ||
1095 | err = copy_mesh_setup(ifmsh, setup); | ||
1096 | if (err) | ||
1097 | return err; | ||
1098 | ieee80211_start_mesh(sdata); | ||
1099 | |||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | ||
1104 | { | ||
1105 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1106 | |||
1107 | ieee80211_stop_mesh(sdata); | ||
1108 | |||
1109 | return 0; | ||
1110 | } | ||
1053 | #endif | 1111 | #endif |
1054 | 1112 | ||
1055 | static int ieee80211_change_bss(struct wiphy *wiphy, | 1113 | static int ieee80211_change_bss(struct wiphy *wiphy, |
@@ -1108,6 +1166,12 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1108 | sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; | 1166 | sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; |
1109 | } | 1167 | } |
1110 | 1168 | ||
1169 | if (params->ht_opmode >= 0) { | ||
1170 | sdata->vif.bss_conf.ht_operation_mode = | ||
1171 | (u16) params->ht_opmode; | ||
1172 | changed |= BSS_CHANGED_HT; | ||
1173 | } | ||
1174 | |||
1111 | ieee80211_bss_info_change_notify(sdata, changed); | 1175 | ieee80211_bss_info_change_notify(sdata, changed); |
1112 | 1176 | ||
1113 | return 0; | 1177 | return 0; |
@@ -1299,6 +1363,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1299 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1363 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1300 | int err; | 1364 | int err; |
1301 | 1365 | ||
1366 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | ||
1367 | err = drv_set_frag_threshold(local, wiphy->frag_threshold); | ||
1368 | |||
1369 | if (err) | ||
1370 | return err; | ||
1371 | } | ||
1372 | |||
1302 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | 1373 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { |
1303 | err = drv_set_coverage_class(local, wiphy->coverage_class); | 1374 | err = drv_set_coverage_class(local, wiphy->coverage_class); |
1304 | 1375 | ||
@@ -1544,27 +1615,54 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
1544 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | 1615 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); |
1545 | } | 1616 | } |
1546 | 1617 | ||
1618 | static enum work_done_result | ||
1619 | ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) | ||
1620 | { | ||
1621 | /* | ||
1622 | * Use the data embedded in the work struct for reporting | ||
1623 | * here so if the driver mangled the SKB before dropping | ||
1624 | * it (which is the only way we really should get here) | ||
1625 | * then we don't report mangled data. | ||
1626 | * | ||
1627 | * If there was no wait time, then by the time we get here | ||
1628 | * the driver will likely not have reported the status yet, | ||
1629 | * so in that case userspace will have to deal with it. | ||
1630 | */ | ||
1631 | |||
1632 | if (wk->offchan_tx.wait && wk->offchan_tx.frame) | ||
1633 | cfg80211_mgmt_tx_status(wk->sdata->dev, | ||
1634 | (unsigned long) wk->offchan_tx.frame, | ||
1635 | wk->ie, wk->ie_len, false, GFP_KERNEL); | ||
1636 | |||
1637 | return WORK_DONE_DESTROY; | ||
1638 | } | ||
1639 | |||
1547 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | 1640 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, |
1548 | struct ieee80211_channel *chan, | 1641 | struct ieee80211_channel *chan, bool offchan, |
1549 | enum nl80211_channel_type channel_type, | 1642 | enum nl80211_channel_type channel_type, |
1550 | bool channel_type_valid, | 1643 | bool channel_type_valid, unsigned int wait, |
1551 | const u8 *buf, size_t len, u64 *cookie) | 1644 | const u8 *buf, size_t len, u64 *cookie) |
1552 | { | 1645 | { |
1553 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1646 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1554 | struct ieee80211_local *local = sdata->local; | 1647 | struct ieee80211_local *local = sdata->local; |
1555 | struct sk_buff *skb; | 1648 | struct sk_buff *skb; |
1556 | struct sta_info *sta; | 1649 | struct sta_info *sta; |
1650 | struct ieee80211_work *wk; | ||
1557 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 1651 | const struct ieee80211_mgmt *mgmt = (void *)buf; |
1558 | u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | 1652 | u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | |
1559 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1653 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
1654 | bool is_offchan = false; | ||
1560 | 1655 | ||
1561 | /* Check that we are on the requested channel for transmission */ | 1656 | /* Check that we are on the requested channel for transmission */ |
1562 | if (chan != local->tmp_channel && | 1657 | if (chan != local->tmp_channel && |
1563 | chan != local->oper_channel) | 1658 | chan != local->oper_channel) |
1564 | return -EBUSY; | 1659 | is_offchan = true; |
1565 | if (channel_type_valid && | 1660 | if (channel_type_valid && |
1566 | (channel_type != local->tmp_channel_type && | 1661 | (channel_type != local->tmp_channel_type && |
1567 | channel_type != local->_oper_channel_type)) | 1662 | channel_type != local->_oper_channel_type)) |
1663 | is_offchan = true; | ||
1664 | |||
1665 | if (is_offchan && !offchan) | ||
1568 | return -EBUSY; | 1666 | return -EBUSY; |
1569 | 1667 | ||
1570 | switch (sdata->vif.type) { | 1668 | switch (sdata->vif.type) { |
@@ -1572,6 +1670,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1572 | case NL80211_IFTYPE_AP: | 1670 | case NL80211_IFTYPE_AP: |
1573 | case NL80211_IFTYPE_AP_VLAN: | 1671 | case NL80211_IFTYPE_AP_VLAN: |
1574 | case NL80211_IFTYPE_P2P_GO: | 1672 | case NL80211_IFTYPE_P2P_GO: |
1673 | case NL80211_IFTYPE_MESH_POINT: | ||
1575 | if (!ieee80211_is_action(mgmt->frame_control) || | 1674 | if (!ieee80211_is_action(mgmt->frame_control) || |
1576 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | 1675 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) |
1577 | break; | 1676 | break; |
@@ -1598,12 +1697,70 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1598 | IEEE80211_SKB_CB(skb)->flags = flags; | 1697 | IEEE80211_SKB_CB(skb)->flags = flags; |
1599 | 1698 | ||
1600 | skb->dev = sdata->dev; | 1699 | skb->dev = sdata->dev; |
1601 | ieee80211_tx_skb(sdata, skb); | ||
1602 | 1700 | ||
1603 | *cookie = (unsigned long) skb; | 1701 | *cookie = (unsigned long) skb; |
1702 | |||
1703 | /* | ||
1704 | * Can transmit right away if the channel was the | ||
1705 | * right one and there's no wait involved... If a | ||
1706 | * wait is involved, we might otherwise not be on | ||
1707 | * the right channel for long enough! | ||
1708 | */ | ||
1709 | if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) { | ||
1710 | ieee80211_tx_skb(sdata, skb); | ||
1711 | return 0; | ||
1712 | } | ||
1713 | |||
1714 | wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL); | ||
1715 | if (!wk) { | ||
1716 | kfree_skb(skb); | ||
1717 | return -ENOMEM; | ||
1718 | } | ||
1719 | |||
1720 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; | ||
1721 | wk->chan = chan; | ||
1722 | wk->sdata = sdata; | ||
1723 | wk->done = ieee80211_offchan_tx_done; | ||
1724 | wk->offchan_tx.frame = skb; | ||
1725 | wk->offchan_tx.wait = wait; | ||
1726 | wk->ie_len = len; | ||
1727 | memcpy(wk->ie, buf, len); | ||
1728 | |||
1729 | ieee80211_add_work(wk); | ||
1604 | return 0; | 1730 | return 0; |
1605 | } | 1731 | } |
1606 | 1732 | ||
1733 | static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | ||
1734 | struct net_device *dev, | ||
1735 | u64 cookie) | ||
1736 | { | ||
1737 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1738 | struct ieee80211_local *local = sdata->local; | ||
1739 | struct ieee80211_work *wk; | ||
1740 | int ret = -ENOENT; | ||
1741 | |||
1742 | mutex_lock(&local->mtx); | ||
1743 | list_for_each_entry(wk, &local->work_list, list) { | ||
1744 | if (wk->sdata != sdata) | ||
1745 | continue; | ||
1746 | |||
1747 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) | ||
1748 | continue; | ||
1749 | |||
1750 | if (cookie != (unsigned long) wk->offchan_tx.frame) | ||
1751 | continue; | ||
1752 | |||
1753 | wk->timeout = jiffies; | ||
1754 | |||
1755 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
1756 | ret = 0; | ||
1757 | break; | ||
1758 | } | ||
1759 | mutex_unlock(&local->mtx); | ||
1760 | |||
1761 | return ret; | ||
1762 | } | ||
1763 | |||
1607 | static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | 1764 | static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, |
1608 | struct net_device *dev, | 1765 | struct net_device *dev, |
1609 | u16 frame_type, bool reg) | 1766 | u16 frame_type, bool reg) |
@@ -1621,6 +1778,23 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | |||
1621 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | 1778 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); |
1622 | } | 1779 | } |
1623 | 1780 | ||
1781 | static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) | ||
1782 | { | ||
1783 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1784 | |||
1785 | if (local->started) | ||
1786 | return -EOPNOTSUPP; | ||
1787 | |||
1788 | return drv_set_antenna(local, tx_ant, rx_ant); | ||
1789 | } | ||
1790 | |||
1791 | static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | ||
1792 | { | ||
1793 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1794 | |||
1795 | return drv_get_antenna(local, tx_ant, rx_ant); | ||
1796 | } | ||
1797 | |||
1624 | struct cfg80211_ops mac80211_config_ops = { | 1798 | struct cfg80211_ops mac80211_config_ops = { |
1625 | .add_virtual_intf = ieee80211_add_iface, | 1799 | .add_virtual_intf = ieee80211_add_iface, |
1626 | .del_virtual_intf = ieee80211_del_iface, | 1800 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1645,8 +1819,10 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1645 | .change_mpath = ieee80211_change_mpath, | 1819 | .change_mpath = ieee80211_change_mpath, |
1646 | .get_mpath = ieee80211_get_mpath, | 1820 | .get_mpath = ieee80211_get_mpath, |
1647 | .dump_mpath = ieee80211_dump_mpath, | 1821 | .dump_mpath = ieee80211_dump_mpath, |
1648 | .set_mesh_params = ieee80211_set_mesh_params, | 1822 | .update_mesh_config = ieee80211_update_mesh_config, |
1649 | .get_mesh_params = ieee80211_get_mesh_params, | 1823 | .get_mesh_config = ieee80211_get_mesh_config, |
1824 | .join_mesh = ieee80211_join_mesh, | ||
1825 | .leave_mesh = ieee80211_leave_mesh, | ||
1650 | #endif | 1826 | #endif |
1651 | .change_bss = ieee80211_change_bss, | 1827 | .change_bss = ieee80211_change_bss, |
1652 | .set_txq_params = ieee80211_set_txq_params, | 1828 | .set_txq_params = ieee80211_set_txq_params, |
@@ -1671,6 +1847,9 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1671 | .remain_on_channel = ieee80211_remain_on_channel, | 1847 | .remain_on_channel = ieee80211_remain_on_channel, |
1672 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | 1848 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, |
1673 | .mgmt_tx = ieee80211_mgmt_tx, | 1849 | .mgmt_tx = ieee80211_mgmt_tx, |
1850 | .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait, | ||
1674 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, | 1851 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, |
1675 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 1852 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
1853 | .set_antenna = ieee80211_set_antenna, | ||
1854 | .get_antenna = ieee80211_get_antenna, | ||
1676 | }; | 1855 | }; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 18260aa99c56..1f02e599a318 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -21,16 +21,30 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file) | |||
21 | return 0; | 21 | return 0; |
22 | } | 22 | } |
23 | 23 | ||
24 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | 24 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 |
25 | |||
26 | int mac80211_format_buffer(char __user *userbuf, size_t count, | ||
27 | loff_t *ppos, char *fmt, ...) | ||
28 | { | ||
29 | va_list args; | ||
30 | char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; | ||
31 | int res; | ||
32 | |||
33 | va_start(args, fmt); | ||
34 | res = vscnprintf(buf, sizeof(buf), fmt, args); | ||
35 | va_end(args); | ||
36 | |||
37 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
38 | } | ||
39 | |||
40 | #define DEBUGFS_READONLY_FILE(name, fmt, value...) \ | ||
25 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | 41 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ |
26 | size_t count, loff_t *ppos) \ | 42 | size_t count, loff_t *ppos) \ |
27 | { \ | 43 | { \ |
28 | struct ieee80211_local *local = file->private_data; \ | 44 | struct ieee80211_local *local = file->private_data; \ |
29 | char buf[buflen]; \ | ||
30 | int res; \ | ||
31 | \ | 45 | \ |
32 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | 46 | return mac80211_format_buffer(userbuf, count, ppos, \ |
33 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | 47 | fmt "\n", ##value); \ |
34 | } \ | 48 | } \ |
35 | \ | 49 | \ |
36 | static const struct file_operations name## _ops = { \ | 50 | static const struct file_operations name## _ops = { \ |
@@ -46,13 +60,13 @@ static const struct file_operations name## _ops = { \ | |||
46 | debugfs_create_file(#name, mode, phyd, local, &name## _ops); | 60 | debugfs_create_file(#name, mode, phyd, local, &name## _ops); |
47 | 61 | ||
48 | 62 | ||
49 | DEBUGFS_READONLY_FILE(frequency, 20, "%d", | 63 | DEBUGFS_READONLY_FILE(frequency, "%d", |
50 | local->hw.conf.channel->center_freq); | 64 | local->hw.conf.channel->center_freq); |
51 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", | 65 | DEBUGFS_READONLY_FILE(total_ps_buffered, "%d", |
52 | local->total_ps_buffered); | 66 | local->total_ps_buffered); |
53 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", | 67 | DEBUGFS_READONLY_FILE(wep_iv, "%#08x", |
54 | local->wep_iv & 0xffffff); | 68 | local->wep_iv & 0xffffff); |
55 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", | 69 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", |
56 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); | 70 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); |
57 | 71 | ||
58 | static ssize_t tsf_read(struct file *file, char __user *user_buf, | 72 | static ssize_t tsf_read(struct file *file, char __user *user_buf, |
@@ -60,13 +74,11 @@ static ssize_t tsf_read(struct file *file, char __user *user_buf, | |||
60 | { | 74 | { |
61 | struct ieee80211_local *local = file->private_data; | 75 | struct ieee80211_local *local = file->private_data; |
62 | u64 tsf; | 76 | u64 tsf; |
63 | char buf[100]; | ||
64 | 77 | ||
65 | tsf = drv_get_tsf(local); | 78 | tsf = drv_get_tsf(local); |
66 | 79 | ||
67 | snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf); | 80 | return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n", |
68 | 81 | (unsigned long long) tsf); | |
69 | return simple_read_from_buffer(user_buf, count, ppos, buf, 19); | ||
70 | } | 82 | } |
71 | 83 | ||
72 | static ssize_t tsf_write(struct file *file, | 84 | static ssize_t tsf_write(struct file *file, |
@@ -131,12 +143,9 @@ static ssize_t noack_read(struct file *file, char __user *user_buf, | |||
131 | size_t count, loff_t *ppos) | 143 | size_t count, loff_t *ppos) |
132 | { | 144 | { |
133 | struct ieee80211_local *local = file->private_data; | 145 | struct ieee80211_local *local = file->private_data; |
134 | int res; | ||
135 | char buf[10]; | ||
136 | 146 | ||
137 | res = scnprintf(buf, sizeof(buf), "%d\n", local->wifi_wme_noack_test); | 147 | return mac80211_format_buffer(user_buf, count, ppos, "%d\n", |
138 | 148 | local->wifi_wme_noack_test); | |
139 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
140 | } | 149 | } |
141 | 150 | ||
142 | static ssize_t noack_write(struct file *file, | 151 | static ssize_t noack_write(struct file *file, |
@@ -168,12 +177,8 @@ static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, | |||
168 | size_t count, loff_t *ppos) | 177 | size_t count, loff_t *ppos) |
169 | { | 178 | { |
170 | struct ieee80211_local *local = file->private_data; | 179 | struct ieee80211_local *local = file->private_data; |
171 | int res; | 180 | return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n", |
172 | char buf[10]; | 181 | local->uapsd_queues); |
173 | |||
174 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); | ||
175 | |||
176 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
177 | } | 182 | } |
178 | 183 | ||
179 | static ssize_t uapsd_queues_write(struct file *file, | 184 | static ssize_t uapsd_queues_write(struct file *file, |
@@ -215,12 +220,9 @@ static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, | |||
215 | size_t count, loff_t *ppos) | 220 | size_t count, loff_t *ppos) |
216 | { | 221 | { |
217 | struct ieee80211_local *local = file->private_data; | 222 | struct ieee80211_local *local = file->private_data; |
218 | int res; | ||
219 | char buf[10]; | ||
220 | 223 | ||
221 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); | 224 | return mac80211_format_buffer(user_buf, count, ppos, "0x%x\n", |
222 | 225 | local->uapsd_max_sp_len); | |
223 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
224 | } | 226 | } |
225 | 227 | ||
226 | static ssize_t uapsd_max_sp_len_write(struct file *file, | 228 | static ssize_t uapsd_max_sp_len_write(struct file *file, |
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 09cc9be34796..7c87529630f5 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | 4 | #ifdef CONFIG_MAC80211_DEBUGFS |
5 | extern void debugfs_hw_add(struct ieee80211_local *local); | 5 | extern void debugfs_hw_add(struct ieee80211_local *local); |
6 | extern int mac80211_open_file_generic(struct inode *inode, struct file *file); | 6 | extern int mac80211_open_file_generic(struct inode *inode, struct file *file); |
7 | extern int mac80211_format_buffer(char __user *userbuf, size_t count, | ||
8 | loff_t *ppos, char *fmt, ...); | ||
7 | #else | 9 | #else |
8 | static inline void debugfs_hw_add(struct ieee80211_local *local) | 10 | static inline void debugfs_hw_add(struct ieee80211_local *local) |
9 | { | 11 | { |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 1243d1db5c59..f7ef3477c24a 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -15,18 +15,17 @@ | |||
15 | #include "debugfs.h" | 15 | #include "debugfs.h" |
16 | #include "debugfs_key.h" | 16 | #include "debugfs_key.h" |
17 | 17 | ||
18 | #define KEY_READ(name, prop, buflen, format_string) \ | 18 | #define KEY_READ(name, prop, format_string) \ |
19 | static ssize_t key_##name##_read(struct file *file, \ | 19 | static ssize_t key_##name##_read(struct file *file, \ |
20 | char __user *userbuf, \ | 20 | char __user *userbuf, \ |
21 | size_t count, loff_t *ppos) \ | 21 | size_t count, loff_t *ppos) \ |
22 | { \ | 22 | { \ |
23 | char buf[buflen]; \ | ||
24 | struct ieee80211_key *key = file->private_data; \ | 23 | struct ieee80211_key *key = file->private_data; \ |
25 | int res = scnprintf(buf, buflen, format_string, key->prop); \ | 24 | return mac80211_format_buffer(userbuf, count, ppos, \ |
26 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | 25 | format_string, key->prop); \ |
27 | } | 26 | } |
28 | #define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n") | 27 | #define KEY_READ_D(name) KEY_READ(name, name, "%d\n") |
29 | #define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n") | 28 | #define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n") |
30 | 29 | ||
31 | #define KEY_OPS(name) \ | 30 | #define KEY_OPS(name) \ |
32 | static const struct file_operations key_ ##name## _ops = { \ | 31 | static const struct file_operations key_ ##name## _ops = { \ |
@@ -39,9 +38,9 @@ static const struct file_operations key_ ##name## _ops = { \ | |||
39 | KEY_READ_##format(name) \ | 38 | KEY_READ_##format(name) \ |
40 | KEY_OPS(name) | 39 | KEY_OPS(name) |
41 | 40 | ||
42 | #define KEY_CONF_READ(name, buflen, format_string) \ | 41 | #define KEY_CONF_READ(name, format_string) \ |
43 | KEY_READ(conf_##name, conf.name, buflen, format_string) | 42 | KEY_READ(conf_##name, conf.name, format_string) |
44 | #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n") | 43 | #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n") |
45 | 44 | ||
46 | #define KEY_CONF_OPS(name) \ | 45 | #define KEY_CONF_OPS(name) \ |
47 | static const struct file_operations key_ ##name## _ops = { \ | 46 | static const struct file_operations key_ ##name## _ops = { \ |
@@ -59,7 +58,7 @@ KEY_CONF_FILE(keyidx, D); | |||
59 | KEY_CONF_FILE(hw_key_idx, D); | 58 | KEY_CONF_FILE(hw_key_idx, D); |
60 | KEY_FILE(flags, X); | 59 | KEY_FILE(flags, X); |
61 | KEY_FILE(tx_rx_count, D); | 60 | KEY_FILE(tx_rx_count, D); |
62 | KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n"); | 61 | KEY_READ(ifindex, sdata->name, "%s\n"); |
63 | KEY_OPS(ifindex); | 62 | KEY_OPS(ifindex); |
64 | 63 | ||
65 | static ssize_t key_algorithm_read(struct file *file, | 64 | static ssize_t key_algorithm_read(struct file *file, |
@@ -275,7 +274,8 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | |||
275 | debugfs_remove_recursive(key->debugfs.dir); | 274 | debugfs_remove_recursive(key->debugfs.dir); |
276 | key->debugfs.dir = NULL; | 275 | key->debugfs.dir = NULL; |
277 | } | 276 | } |
278 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) | 277 | |
278 | void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | ||
279 | { | 279 | { |
280 | char buf[50]; | 280 | char buf[50]; |
281 | struct ieee80211_key *key; | 281 | struct ieee80211_key *key; |
@@ -283,25 +283,29 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) | |||
283 | if (!sdata->debugfs.dir) | 283 | if (!sdata->debugfs.dir) |
284 | return; | 284 | return; |
285 | 285 | ||
286 | /* this is running under the key lock */ | 286 | lockdep_assert_held(&sdata->local->key_mtx); |
287 | 287 | ||
288 | key = sdata->default_key; | 288 | if (sdata->default_unicast_key) { |
289 | if (key) { | 289 | key = sdata->default_unicast_key; |
290 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | 290 | sprintf(buf, "../keys/%d", key->debugfs.cnt); |
291 | sdata->debugfs.default_key = | 291 | sdata->debugfs.default_unicast_key = |
292 | debugfs_create_symlink("default_key", | 292 | debugfs_create_symlink("default_unicast_key", |
293 | sdata->debugfs.dir, buf); | 293 | sdata->debugfs.dir, buf); |
294 | } else | 294 | } else { |
295 | ieee80211_debugfs_key_remove_default(sdata); | 295 | debugfs_remove(sdata->debugfs.default_unicast_key); |
296 | } | 296 | sdata->debugfs.default_unicast_key = NULL; |
297 | 297 | } | |
298 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) | ||
299 | { | ||
300 | if (!sdata) | ||
301 | return; | ||
302 | 298 | ||
303 | debugfs_remove(sdata->debugfs.default_key); | 299 | if (sdata->default_multicast_key) { |
304 | sdata->debugfs.default_key = NULL; | 300 | key = sdata->default_multicast_key; |
301 | sprintf(buf, "../keys/%d", key->debugfs.cnt); | ||
302 | sdata->debugfs.default_multicast_key = | ||
303 | debugfs_create_symlink("default_multicast_key", | ||
304 | sdata->debugfs.dir, buf); | ||
305 | } else { | ||
306 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
307 | sdata->debugfs.default_multicast_key = NULL; | ||
308 | } | ||
305 | } | 309 | } |
306 | 310 | ||
307 | void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) | 311 | void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h index 54717b4e1371..32adc77e9c77 100644 --- a/net/mac80211/debugfs_key.h +++ b/net/mac80211/debugfs_key.h | |||
@@ -4,8 +4,7 @@ | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | 4 | #ifdef CONFIG_MAC80211_DEBUGFS |
5 | void ieee80211_debugfs_key_add(struct ieee80211_key *key); | 5 | void ieee80211_debugfs_key_add(struct ieee80211_key *key); |
6 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); | 6 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); |
7 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); | 7 | void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata); |
8 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); | ||
9 | void ieee80211_debugfs_key_add_mgmt_default( | 8 | void ieee80211_debugfs_key_add_mgmt_default( |
10 | struct ieee80211_sub_if_data *sdata); | 9 | struct ieee80211_sub_if_data *sdata); |
11 | void ieee80211_debugfs_key_remove_mgmt_default( | 10 | void ieee80211_debugfs_key_remove_mgmt_default( |
@@ -17,10 +16,7 @@ static inline void ieee80211_debugfs_key_add(struct ieee80211_key *key) | |||
17 | {} | 16 | {} |
18 | static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | 17 | static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) |
19 | {} | 18 | {} |
20 | static inline void ieee80211_debugfs_key_add_default( | 19 | static inline void ieee80211_debugfs_key_update_default( |
21 | struct ieee80211_sub_if_data *sdata) | ||
22 | {} | ||
23 | static inline void ieee80211_debugfs_key_remove_default( | ||
24 | struct ieee80211_sub_if_data *sdata) | 20 | struct ieee80211_sub_if_data *sdata) |
25 | {} | 21 | {} |
26 | static inline void ieee80211_debugfs_key_add_mgmt_default( | 22 | static inline void ieee80211_debugfs_key_add_mgmt_default( |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index cbdf36d7841c..2dabdf7680d0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -251,6 +251,7 @@ IEEE80211_IF_FILE(dot11MeshConfirmTimeout, | |||
251 | IEEE80211_IF_FILE(dot11MeshHoldingTimeout, | 251 | IEEE80211_IF_FILE(dot11MeshHoldingTimeout, |
252 | u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); | 252 | u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); |
253 | IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); | 253 | IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); |
254 | IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC); | ||
254 | IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); | 255 | IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); |
255 | IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, | 256 | IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, |
256 | u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); | 257 | u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); |
@@ -355,6 +356,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) | |||
355 | MESHPARAMS_ADD(dot11MeshConfirmTimeout); | 356 | MESHPARAMS_ADD(dot11MeshConfirmTimeout); |
356 | MESHPARAMS_ADD(dot11MeshHoldingTimeout); | 357 | MESHPARAMS_ADD(dot11MeshHoldingTimeout); |
357 | MESHPARAMS_ADD(dot11MeshTTL); | 358 | MESHPARAMS_ADD(dot11MeshTTL); |
359 | MESHPARAMS_ADD(element_ttl); | ||
358 | MESHPARAMS_ADD(auto_open_plinks); | 360 | MESHPARAMS_ADD(auto_open_plinks); |
359 | MESHPARAMS_ADD(dot11MeshMaxPeerLinks); | 361 | MESHPARAMS_ADD(dot11MeshMaxPeerLinks); |
360 | MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); | 362 | MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 4601fea1784d..c04a1396cf8d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -17,20 +17,18 @@ | |||
17 | 17 | ||
18 | /* sta attributtes */ | 18 | /* sta attributtes */ |
19 | 19 | ||
20 | #define STA_READ(name, buflen, field, format_string) \ | 20 | #define STA_READ(name, field, format_string) \ |
21 | static ssize_t sta_ ##name## _read(struct file *file, \ | 21 | static ssize_t sta_ ##name## _read(struct file *file, \ |
22 | char __user *userbuf, \ | 22 | char __user *userbuf, \ |
23 | size_t count, loff_t *ppos) \ | 23 | size_t count, loff_t *ppos) \ |
24 | { \ | 24 | { \ |
25 | int res; \ | ||
26 | struct sta_info *sta = file->private_data; \ | 25 | struct sta_info *sta = file->private_data; \ |
27 | char buf[buflen]; \ | 26 | return mac80211_format_buffer(userbuf, count, ppos, \ |
28 | res = scnprintf(buf, buflen, format_string, sta->field); \ | 27 | format_string, sta->field); \ |
29 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
30 | } | 28 | } |
31 | #define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n") | 29 | #define STA_READ_D(name, field) STA_READ(name, field, "%d\n") |
32 | #define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n") | 30 | #define STA_READ_U(name, field) STA_READ(name, field, "%u\n") |
33 | #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n") | 31 | #define STA_READ_S(name, field) STA_READ(name, field, "%s\n") |
34 | 32 | ||
35 | #define STA_OPS(name) \ | 33 | #define STA_OPS(name) \ |
36 | static const struct file_operations sta_ ##name## _ops = { \ | 34 | static const struct file_operations sta_ ##name## _ops = { \ |
@@ -79,22 +77,18 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file, | |||
79 | char __user *userbuf, | 77 | char __user *userbuf, |
80 | size_t count, loff_t *ppos) | 78 | size_t count, loff_t *ppos) |
81 | { | 79 | { |
82 | char buf[20]; | ||
83 | struct sta_info *sta = file->private_data; | 80 | struct sta_info *sta = file->private_data; |
84 | int res = scnprintf(buf, sizeof(buf), "%u\n", | 81 | return mac80211_format_buffer(userbuf, count, ppos, "%u\n", |
85 | skb_queue_len(&sta->ps_tx_buf)); | 82 | skb_queue_len(&sta->ps_tx_buf)); |
86 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
87 | } | 83 | } |
88 | STA_OPS(num_ps_buf_frames); | 84 | STA_OPS(num_ps_buf_frames); |
89 | 85 | ||
90 | static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, | 86 | static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, |
91 | size_t count, loff_t *ppos) | 87 | size_t count, loff_t *ppos) |
92 | { | 88 | { |
93 | char buf[20]; | ||
94 | struct sta_info *sta = file->private_data; | 89 | struct sta_info *sta = file->private_data; |
95 | int res = scnprintf(buf, sizeof(buf), "%d\n", | 90 | return mac80211_format_buffer(userbuf, count, ppos, "%d\n", |
96 | jiffies_to_msecs(jiffies - sta->last_rx)); | 91 | jiffies_to_msecs(jiffies - sta->last_rx)); |
97 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | ||
98 | } | 92 | } |
99 | STA_OPS(inactive_ms); | 93 | STA_OPS(inactive_ms); |
100 | 94 | ||
@@ -118,34 +112,35 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
118 | char buf[71 + STA_TID_NUM * 40], *p = buf; | 112 | char buf[71 + STA_TID_NUM * 40], *p = buf; |
119 | int i; | 113 | int i; |
120 | struct sta_info *sta = file->private_data; | 114 | struct sta_info *sta = file->private_data; |
115 | struct tid_ampdu_rx *tid_rx; | ||
116 | struct tid_ampdu_tx *tid_tx; | ||
117 | |||
118 | rcu_read_lock(); | ||
121 | 119 | ||
122 | spin_lock_bh(&sta->lock); | ||
123 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", | 120 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", |
124 | sta->ampdu_mlme.dialog_token_allocator + 1); | 121 | sta->ampdu_mlme.dialog_token_allocator + 1); |
125 | p += scnprintf(p, sizeof(buf) + buf - p, | 122 | p += scnprintf(p, sizeof(buf) + buf - p, |
126 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); | 123 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); |
124 | |||
127 | for (i = 0; i < STA_TID_NUM; i++) { | 125 | for (i = 0; i < STA_TID_NUM; i++) { |
126 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); | ||
127 | tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); | ||
128 | |||
128 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); | 129 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
129 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 130 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx); |
130 | !!sta->ampdu_mlme.tid_rx[i]); | ||
131 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", | 131 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
132 | sta->ampdu_mlme.tid_rx[i] ? | 132 | tid_rx ? tid_rx->dialog_token : 0); |
133 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); | ||
134 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", | 133 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
135 | sta->ampdu_mlme.tid_rx[i] ? | 134 | tid_rx ? tid_rx->ssn : 0); |
136 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); | ||
137 | 135 | ||
138 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 136 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_tx); |
139 | !!sta->ampdu_mlme.tid_tx[i]); | ||
140 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", | 137 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
141 | sta->ampdu_mlme.tid_tx[i] ? | 138 | tid_tx ? tid_tx->dialog_token : 0); |
142 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); | ||
143 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", | 139 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", |
144 | sta->ampdu_mlme.tid_tx[i] ? | 140 | tid_tx ? skb_queue_len(&tid_tx->pending) : 0); |
145 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); | ||
146 | p += scnprintf(p, sizeof(buf) + buf - p, "\n"); | 141 | p += scnprintf(p, sizeof(buf) + buf - p, "\n"); |
147 | } | 142 | } |
148 | spin_unlock_bh(&sta->lock); | 143 | rcu_read_unlock(); |
149 | 144 | ||
150 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | 145 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); |
151 | } | 146 | } |
@@ -194,7 +189,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu | |||
194 | 189 | ||
195 | if (tx) { | 190 | if (tx) { |
196 | if (start) | 191 | if (start) |
197 | ret = ieee80211_start_tx_ba_session(&sta->sta, tid); | 192 | ret = ieee80211_start_tx_ba_session(&sta->sta, tid, 5000); |
198 | else | 193 | else |
199 | ret = ieee80211_stop_tx_ba_session(&sta->sta, tid); | 194 | ret = ieee80211_stop_tx_ba_session(&sta->sta, tid); |
200 | } else { | 195 | } else { |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 16983825f8e8..af0c4398cceb 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -233,6 +233,20 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local, | |||
233 | trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16); | 233 | trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16); |
234 | } | 234 | } |
235 | 235 | ||
236 | static inline int drv_set_frag_threshold(struct ieee80211_local *local, | ||
237 | u32 value) | ||
238 | { | ||
239 | int ret = 0; | ||
240 | |||
241 | might_sleep(); | ||
242 | |||
243 | trace_drv_set_frag_threshold(local, value); | ||
244 | if (local->ops->set_frag_threshold) | ||
245 | ret = local->ops->set_frag_threshold(&local->hw, value); | ||
246 | trace_drv_return_int(local, ret); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
236 | static inline int drv_set_rts_threshold(struct ieee80211_local *local, | 250 | static inline int drv_set_rts_threshold(struct ieee80211_local *local, |
237 | u32 value) | 251 | u32 value) |
238 | { | 252 | { |
@@ -353,7 +367,7 @@ static inline void drv_reset_tsf(struct ieee80211_local *local) | |||
353 | 367 | ||
354 | static inline int drv_tx_last_beacon(struct ieee80211_local *local) | 368 | static inline int drv_tx_last_beacon(struct ieee80211_local *local) |
355 | { | 369 | { |
356 | int ret = 1; | 370 | int ret = 0; /* default unsuported op for less congestion */ |
357 | 371 | ||
358 | might_sleep(); | 372 | might_sleep(); |
359 | 373 | ||
@@ -428,4 +442,27 @@ static inline void drv_channel_switch(struct ieee80211_local *local, | |||
428 | trace_drv_return_void(local); | 442 | trace_drv_return_void(local); |
429 | } | 443 | } |
430 | 444 | ||
445 | |||
446 | static inline int drv_set_antenna(struct ieee80211_local *local, | ||
447 | u32 tx_ant, u32 rx_ant) | ||
448 | { | ||
449 | int ret = -EOPNOTSUPP; | ||
450 | might_sleep(); | ||
451 | if (local->ops->set_antenna) | ||
452 | ret = local->ops->set_antenna(&local->hw, tx_ant, rx_ant); | ||
453 | trace_drv_set_antenna(local, tx_ant, rx_ant, ret); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static inline int drv_get_antenna(struct ieee80211_local *local, | ||
458 | u32 *tx_ant, u32 *rx_ant) | ||
459 | { | ||
460 | int ret = -EOPNOTSUPP; | ||
461 | might_sleep(); | ||
462 | if (local->ops->get_antenna) | ||
463 | ret = local->ops->get_antenna(&local->hw, tx_ant, rx_ant); | ||
464 | trace_drv_get_antenna(local, *tx_ant, *rx_ant, ret); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
431 | #endif /* __MAC80211_DRIVER_OPS */ | 468 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 6831fb1641c8..c2772f23ac9c 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -531,6 +531,27 @@ TRACE_EVENT(drv_get_tkip_seq, | |||
531 | ) | 531 | ) |
532 | ); | 532 | ); |
533 | 533 | ||
534 | TRACE_EVENT(drv_set_frag_threshold, | ||
535 | TP_PROTO(struct ieee80211_local *local, u32 value), | ||
536 | |||
537 | TP_ARGS(local, value), | ||
538 | |||
539 | TP_STRUCT__entry( | ||
540 | LOCAL_ENTRY | ||
541 | __field(u32, value) | ||
542 | ), | ||
543 | |||
544 | TP_fast_assign( | ||
545 | LOCAL_ASSIGN; | ||
546 | __entry->value = value; | ||
547 | ), | ||
548 | |||
549 | TP_printk( | ||
550 | LOCAL_PR_FMT " value:%d", | ||
551 | LOCAL_PR_ARG, __entry->value | ||
552 | ) | ||
553 | ); | ||
554 | |||
534 | TRACE_EVENT(drv_set_rts_threshold, | 555 | TRACE_EVENT(drv_set_rts_threshold, |
535 | TP_PROTO(struct ieee80211_local *local, u32 value), | 556 | TP_PROTO(struct ieee80211_local *local, u32 value), |
536 | 557 | ||
@@ -862,6 +883,56 @@ TRACE_EVENT(drv_channel_switch, | |||
862 | ) | 883 | ) |
863 | ); | 884 | ); |
864 | 885 | ||
886 | TRACE_EVENT(drv_set_antenna, | ||
887 | TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret), | ||
888 | |||
889 | TP_ARGS(local, tx_ant, rx_ant, ret), | ||
890 | |||
891 | TP_STRUCT__entry( | ||
892 | LOCAL_ENTRY | ||
893 | __field(u32, tx_ant) | ||
894 | __field(u32, rx_ant) | ||
895 | __field(int, ret) | ||
896 | ), | ||
897 | |||
898 | TP_fast_assign( | ||
899 | LOCAL_ASSIGN; | ||
900 | __entry->tx_ant = tx_ant; | ||
901 | __entry->rx_ant = rx_ant; | ||
902 | __entry->ret = ret; | ||
903 | ), | ||
904 | |||
905 | TP_printk( | ||
906 | LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d", | ||
907 | LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret | ||
908 | ) | ||
909 | ); | ||
910 | |||
911 | TRACE_EVENT(drv_get_antenna, | ||
912 | TP_PROTO(struct ieee80211_local *local, u32 tx_ant, u32 rx_ant, int ret), | ||
913 | |||
914 | TP_ARGS(local, tx_ant, rx_ant, ret), | ||
915 | |||
916 | TP_STRUCT__entry( | ||
917 | LOCAL_ENTRY | ||
918 | __field(u32, tx_ant) | ||
919 | __field(u32, rx_ant) | ||
920 | __field(int, ret) | ||
921 | ), | ||
922 | |||
923 | TP_fast_assign( | ||
924 | LOCAL_ASSIGN; | ||
925 | __entry->tx_ant = tx_ant; | ||
926 | __entry->rx_ant = rx_ant; | ||
927 | __entry->ret = ret; | ||
928 | ), | ||
929 | |||
930 | TP_printk( | ||
931 | LOCAL_PR_FMT " tx_ant:%d rx_ant:%d ret:%d", | ||
932 | LOCAL_PR_ARG, __entry->tx_ant, __entry->rx_ant, __entry->ret | ||
933 | ) | ||
934 | ); | ||
935 | |||
865 | /* | 936 | /* |
866 | * Tracing for API calls that drivers call. | 937 | * Tracing for API calls that drivers call. |
867 | */ | 938 | */ |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 077a93dd1671..53c7077ffd4f 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -919,6 +919,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
919 | 919 | ||
920 | sdata->u.ibss.privacy = params->privacy; | 920 | sdata->u.ibss.privacy = params->privacy; |
921 | sdata->u.ibss.basic_rates = params->basic_rates; | 921 | sdata->u.ibss.basic_rates = params->basic_rates; |
922 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, | ||
923 | sizeof(params->mcast_rate)); | ||
922 | 924 | ||
923 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 925 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
924 | 926 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b80c38689927..a05893a238b7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/types.h> | 23 | #include <linux/types.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
26 | #include <linux/leds.h> | ||
26 | #include <net/ieee80211_radiotap.h> | 27 | #include <net/ieee80211_radiotap.h> |
27 | #include <net/cfg80211.h> | 28 | #include <net/cfg80211.h> |
28 | #include <net/mac80211.h> | 29 | #include <net/mac80211.h> |
@@ -260,6 +261,7 @@ enum ieee80211_work_type { | |||
260 | IEEE80211_WORK_ASSOC_BEACON_WAIT, | 261 | IEEE80211_WORK_ASSOC_BEACON_WAIT, |
261 | IEEE80211_WORK_ASSOC, | 262 | IEEE80211_WORK_ASSOC, |
262 | IEEE80211_WORK_REMAIN_ON_CHANNEL, | 263 | IEEE80211_WORK_REMAIN_ON_CHANNEL, |
264 | IEEE80211_WORK_OFFCHANNEL_TX, | ||
263 | }; | 265 | }; |
264 | 266 | ||
265 | /** | 267 | /** |
@@ -320,6 +322,10 @@ struct ieee80211_work { | |||
320 | struct { | 322 | struct { |
321 | u32 duration; | 323 | u32 duration; |
322 | } remain; | 324 | } remain; |
325 | struct { | ||
326 | struct sk_buff *frame; | ||
327 | u32 wait; | ||
328 | } offchan_tx; | ||
323 | }; | 329 | }; |
324 | 330 | ||
325 | int ie_len; | 331 | int ie_len; |
@@ -349,8 +355,10 @@ struct ieee80211_if_managed { | |||
349 | struct work_struct chswitch_work; | 355 | struct work_struct chswitch_work; |
350 | struct work_struct beacon_connection_loss_work; | 356 | struct work_struct beacon_connection_loss_work; |
351 | 357 | ||
358 | unsigned long beacon_timeout; | ||
352 | unsigned long probe_timeout; | 359 | unsigned long probe_timeout; |
353 | int probe_send_count; | 360 | int probe_send_count; |
361 | bool nullfunc_failed; | ||
354 | 362 | ||
355 | struct mutex mtx; | 363 | struct mutex mtx; |
356 | struct cfg80211_bss *associated; | 364 | struct cfg80211_bss *associated; |
@@ -477,6 +485,8 @@ struct ieee80211_if_mesh { | |||
477 | struct mesh_config mshcfg; | 485 | struct mesh_config mshcfg; |
478 | u32 mesh_seqnum; | 486 | u32 mesh_seqnum; |
479 | bool accepting_plinks; | 487 | bool accepting_plinks; |
488 | const u8 *vendor_ie; | ||
489 | u8 vendor_ie_len; | ||
480 | }; | 490 | }; |
481 | 491 | ||
482 | #ifdef CONFIG_MAC80211_MESH | 492 | #ifdef CONFIG_MAC80211_MESH |
@@ -550,7 +560,7 @@ struct ieee80211_sub_if_data { | |||
550 | unsigned int fragment_next; | 560 | unsigned int fragment_next; |
551 | 561 | ||
552 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 562 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
553 | struct ieee80211_key *default_key; | 563 | struct ieee80211_key *default_unicast_key, *default_multicast_key; |
554 | struct ieee80211_key *default_mgmt_key; | 564 | struct ieee80211_key *default_mgmt_key; |
555 | 565 | ||
556 | u16 sequence_number; | 566 | u16 sequence_number; |
@@ -578,9 +588,7 @@ struct ieee80211_sub_if_data { | |||
578 | struct ieee80211_if_vlan vlan; | 588 | struct ieee80211_if_vlan vlan; |
579 | struct ieee80211_if_managed mgd; | 589 | struct ieee80211_if_managed mgd; |
580 | struct ieee80211_if_ibss ibss; | 590 | struct ieee80211_if_ibss ibss; |
581 | #ifdef CONFIG_MAC80211_MESH | ||
582 | struct ieee80211_if_mesh mesh; | 591 | struct ieee80211_if_mesh mesh; |
583 | #endif | ||
584 | u32 mntr_flags; | 592 | u32 mntr_flags; |
585 | } u; | 593 | } u; |
586 | 594 | ||
@@ -588,7 +596,8 @@ struct ieee80211_sub_if_data { | |||
588 | struct { | 596 | struct { |
589 | struct dentry *dir; | 597 | struct dentry *dir; |
590 | struct dentry *subdir_stations; | 598 | struct dentry *subdir_stations; |
591 | struct dentry *default_key; | 599 | struct dentry *default_unicast_key; |
600 | struct dentry *default_multicast_key; | ||
592 | struct dentry *default_mgmt_key; | 601 | struct dentry *default_mgmt_key; |
593 | } debugfs; | 602 | } debugfs; |
594 | #endif | 603 | #endif |
@@ -602,19 +611,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) | |||
602 | return container_of(p, struct ieee80211_sub_if_data, vif); | 611 | return container_of(p, struct ieee80211_sub_if_data, vif); |
603 | } | 612 | } |
604 | 613 | ||
605 | static inline void | ||
606 | ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata, | ||
607 | u8 mesh_id_len, u8 *mesh_id) | ||
608 | { | ||
609 | #ifdef CONFIG_MAC80211_MESH | ||
610 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
611 | ifmsh->mesh_id_len = mesh_id_len; | ||
612 | memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len); | ||
613 | #else | ||
614 | WARN_ON(1); | ||
615 | #endif | ||
616 | } | ||
617 | |||
618 | enum sdata_queue_type { | 614 | enum sdata_queue_type { |
619 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 615 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
620 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 616 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
@@ -635,6 +631,20 @@ enum queue_stop_reason { | |||
635 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, | 631 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD, |
636 | }; | 632 | }; |
637 | 633 | ||
634 | #ifdef CONFIG_MAC80211_LEDS | ||
635 | struct tpt_led_trigger { | ||
636 | struct led_trigger trig; | ||
637 | char name[32]; | ||
638 | const struct ieee80211_tpt_blink *blink_table; | ||
639 | unsigned int blink_table_len; | ||
640 | struct timer_list timer; | ||
641 | unsigned long prev_traffic; | ||
642 | unsigned long tx_bytes, rx_bytes; | ||
643 | unsigned int active, want; | ||
644 | bool running; | ||
645 | }; | ||
646 | #endif | ||
647 | |||
638 | /** | 648 | /** |
639 | * mac80211 scan flags - currently active scan mode | 649 | * mac80211 scan flags - currently active scan mode |
640 | * | 650 | * |
@@ -843,6 +853,7 @@ struct ieee80211_local { | |||
843 | #ifdef CONFIG_MAC80211_LEDS | 853 | #ifdef CONFIG_MAC80211_LEDS |
844 | int tx_led_counter, rx_led_counter; | 854 | int tx_led_counter, rx_led_counter; |
845 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; | 855 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; |
856 | struct tpt_led_trigger *tpt_led_trigger; | ||
846 | char tx_led_name[32], rx_led_name[32], | 857 | char tx_led_name[32], rx_led_name[32], |
847 | assoc_led_name[32], radio_led_name[32]; | 858 | assoc_led_name[32], radio_led_name[32]; |
848 | #endif | 859 | #endif |
@@ -1264,6 +1275,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1264 | int powersave); | 1275 | int powersave); |
1265 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1276 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1266 | struct ieee80211_hdr *hdr); | 1277 | struct ieee80211_hdr *hdr); |
1278 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | ||
1279 | struct ieee80211_hdr *hdr, bool ack); | ||
1267 | void ieee80211_beacon_connection_loss_work(struct work_struct *work); | 1280 | void ieee80211_beacon_connection_loss_work(struct work_struct *work); |
1268 | 1281 | ||
1269 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1282 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
@@ -1278,6 +1291,9 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
1278 | struct sk_buff *skb); | 1291 | struct sk_buff *skb); |
1279 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | 1292 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, |
1280 | struct sk_buff_head *skbs); | 1293 | struct sk_buff_head *skbs); |
1294 | int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | ||
1295 | struct sk_buff_head *skbs, | ||
1296 | void (*fn)(void *data), void *data); | ||
1281 | 1297 | ||
1282 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1298 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1283 | u16 transaction, u16 auth_alg, | 1299 | u16 transaction, u16 auth_alg, |
@@ -1287,6 +1303,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1287 | const u8 *ie, size_t ie_len, | 1303 | const u8 *ie, size_t ie_len, |
1288 | enum ieee80211_band band, u32 rate_mask, | 1304 | enum ieee80211_band band, u32 rate_mask, |
1289 | u8 channel); | 1305 | u8 channel); |
1306 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | ||
1307 | u8 *dst, | ||
1308 | const u8 *ssid, size_t ssid_len, | ||
1309 | const u8 *ie, size_t ie_len); | ||
1290 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1310 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1291 | const u8 *ssid, size_t ssid_len, | 1311 | const u8 *ssid, size_t ssid_len, |
1292 | const u8 *ie, size_t ie_len); | 1312 | const u8 *ie, size_t ie_len); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7aa85591dbe7..b6db237672ff 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -197,11 +197,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
197 | sdata->bss = &sdata->u.ap; | 197 | sdata->bss = &sdata->u.ap; |
198 | break; | 198 | break; |
199 | case NL80211_IFTYPE_MESH_POINT: | 199 | case NL80211_IFTYPE_MESH_POINT: |
200 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
201 | break; | ||
202 | /* mesh ifaces must set allmulti to forward mcast traffic */ | ||
203 | atomic_inc(&local->iff_allmultis); | ||
204 | break; | ||
205 | case NL80211_IFTYPE_STATION: | 200 | case NL80211_IFTYPE_STATION: |
206 | case NL80211_IFTYPE_MONITOR: | 201 | case NL80211_IFTYPE_MONITOR: |
207 | case NL80211_IFTYPE_ADHOC: | 202 | case NL80211_IFTYPE_ADHOC: |
@@ -225,6 +220,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
225 | /* we're brought up, everything changes */ | 220 | /* we're brought up, everything changes */ |
226 | hw_reconf_flags = ~0; | 221 | hw_reconf_flags = ~0; |
227 | ieee80211_led_radio(local, true); | 222 | ieee80211_led_radio(local, true); |
223 | ieee80211_mod_tpt_led_trig(local, | ||
224 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | ||
228 | } | 225 | } |
229 | 226 | ||
230 | /* | 227 | /* |
@@ -273,12 +270,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
273 | goto err_stop; | 270 | goto err_stop; |
274 | } | 271 | } |
275 | 272 | ||
276 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 273 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
277 | local->fif_other_bss++; | ||
278 | ieee80211_configure_filter(local); | ||
279 | |||
280 | ieee80211_start_mesh(sdata); | ||
281 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
282 | local->fif_pspoll++; | 274 | local->fif_pspoll++; |
283 | local->fif_probe_req++; | 275 | local->fif_probe_req++; |
284 | 276 | ||
@@ -503,18 +495,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
503 | ieee80211_adjust_monitor_flags(sdata, -1); | 495 | ieee80211_adjust_monitor_flags(sdata, -1); |
504 | ieee80211_configure_filter(local); | 496 | ieee80211_configure_filter(local); |
505 | break; | 497 | break; |
506 | case NL80211_IFTYPE_MESH_POINT: | ||
507 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
508 | /* other_bss and allmulti are always set on mesh | ||
509 | * ifaces */ | ||
510 | local->fif_other_bss--; | ||
511 | atomic_dec(&local->iff_allmultis); | ||
512 | |||
513 | ieee80211_configure_filter(local); | ||
514 | |||
515 | ieee80211_stop_mesh(sdata); | ||
516 | } | ||
517 | /* fall through */ | ||
518 | default: | 498 | default: |
519 | flush_work(&sdata->work); | 499 | flush_work(&sdata->work); |
520 | /* | 500 | /* |
@@ -1204,12 +1184,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1204 | if (ret) | 1184 | if (ret) |
1205 | goto fail; | 1185 | goto fail; |
1206 | 1186 | ||
1207 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
1208 | params && params->mesh_id_len) | ||
1209 | ieee80211_sdata_set_mesh_id(sdata, | ||
1210 | params->mesh_id_len, | ||
1211 | params->mesh_id); | ||
1212 | |||
1213 | mutex_lock(&local->iflist_mtx); | 1187 | mutex_lock(&local->iflist_mtx); |
1214 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 1188 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
1215 | mutex_unlock(&local->iflist_mtx); | 1189 | mutex_unlock(&local->iflist_mtx); |
@@ -1292,6 +1266,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1292 | int count = 0; | 1266 | int count = 0; |
1293 | bool working = false, scanning = false; | 1267 | bool working = false, scanning = false; |
1294 | struct ieee80211_work *wk; | 1268 | struct ieee80211_work *wk; |
1269 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
1295 | 1270 | ||
1296 | #ifdef CONFIG_PROVE_LOCKING | 1271 | #ifdef CONFIG_PROVE_LOCKING |
1297 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | 1272 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && |
@@ -1341,6 +1316,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1341 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 1316 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); |
1342 | } | 1317 | } |
1343 | 1318 | ||
1319 | if (working || scanning) | ||
1320 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1321 | else | ||
1322 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1323 | |||
1324 | if (count) | ||
1325 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1326 | else | ||
1327 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1328 | |||
1329 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
1330 | |||
1344 | if (working) | 1331 | if (working) |
1345 | return ieee80211_idle_off(local, "working"); | 1332 | return ieee80211_idle_off(local, "working"); |
1346 | if (scanning) | 1333 | if (scanning) |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ccd676b2f599..84cf9196820f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -84,10 +84,17 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
84 | goto out_unsupported; | 84 | goto out_unsupported; |
85 | 85 | ||
86 | sdata = key->sdata; | 86 | sdata = key->sdata; |
87 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 87 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
88 | /* | ||
89 | * The driver doesn't know anything about VLAN interfaces. | ||
90 | * Hence, don't send GTKs for VLAN interfaces to the driver. | ||
91 | */ | ||
92 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
93 | goto out_unsupported; | ||
88 | sdata = container_of(sdata->bss, | 94 | sdata = container_of(sdata->bss, |
89 | struct ieee80211_sub_if_data, | 95 | struct ieee80211_sub_if_data, |
90 | u.ap); | 96 | u.ap); |
97 | } | ||
91 | 98 | ||
92 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); | 99 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); |
93 | 100 | ||
@@ -171,7 +178,7 @@ void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) | |||
171 | EXPORT_SYMBOL_GPL(ieee80211_key_removed); | 178 | EXPORT_SYMBOL_GPL(ieee80211_key_removed); |
172 | 179 | ||
173 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | 180 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, |
174 | int idx) | 181 | int idx, bool uni, bool multi) |
175 | { | 182 | { |
176 | struct ieee80211_key *key = NULL; | 183 | struct ieee80211_key *key = NULL; |
177 | 184 | ||
@@ -180,18 +187,19 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | |||
180 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 187 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) |
181 | key = sdata->keys[idx]; | 188 | key = sdata->keys[idx]; |
182 | 189 | ||
183 | rcu_assign_pointer(sdata->default_key, key); | 190 | if (uni) |
191 | rcu_assign_pointer(sdata->default_unicast_key, key); | ||
192 | if (multi) | ||
193 | rcu_assign_pointer(sdata->default_multicast_key, key); | ||
184 | 194 | ||
185 | if (key) { | 195 | ieee80211_debugfs_key_update_default(sdata); |
186 | ieee80211_debugfs_key_remove_default(key->sdata); | ||
187 | ieee80211_debugfs_key_add_default(key->sdata); | ||
188 | } | ||
189 | } | 196 | } |
190 | 197 | ||
191 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | 198 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
199 | bool uni, bool multi) | ||
192 | { | 200 | { |
193 | mutex_lock(&sdata->local->key_mtx); | 201 | mutex_lock(&sdata->local->key_mtx); |
194 | __ieee80211_set_default_key(sdata, idx); | 202 | __ieee80211_set_default_key(sdata, idx, uni, multi); |
195 | mutex_unlock(&sdata->local->key_mtx); | 203 | mutex_unlock(&sdata->local->key_mtx); |
196 | } | 204 | } |
197 | 205 | ||
@@ -208,10 +216,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
208 | 216 | ||
209 | rcu_assign_pointer(sdata->default_mgmt_key, key); | 217 | rcu_assign_pointer(sdata->default_mgmt_key, key); |
210 | 218 | ||
211 | if (key) { | 219 | ieee80211_debugfs_key_update_default(sdata); |
212 | ieee80211_debugfs_key_remove_mgmt_default(key->sdata); | ||
213 | ieee80211_debugfs_key_add_mgmt_default(key->sdata); | ||
214 | } | ||
215 | } | 220 | } |
216 | 221 | ||
217 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 222 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
@@ -229,7 +234,8 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
229 | struct ieee80211_key *old, | 234 | struct ieee80211_key *old, |
230 | struct ieee80211_key *new) | 235 | struct ieee80211_key *new) |
231 | { | 236 | { |
232 | int idx, defkey, defmgmtkey; | 237 | int idx; |
238 | bool defunikey, defmultikey, defmgmtkey; | ||
233 | 239 | ||
234 | if (new) | 240 | if (new) |
235 | list_add(&new->list, &sdata->key_list); | 241 | list_add(&new->list, &sdata->key_list); |
@@ -250,17 +256,24 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
250 | else | 256 | else |
251 | idx = new->conf.keyidx; | 257 | idx = new->conf.keyidx; |
252 | 258 | ||
253 | defkey = old && sdata->default_key == old; | 259 | defunikey = old && sdata->default_unicast_key == old; |
260 | defmultikey = old && sdata->default_multicast_key == old; | ||
254 | defmgmtkey = old && sdata->default_mgmt_key == old; | 261 | defmgmtkey = old && sdata->default_mgmt_key == old; |
255 | 262 | ||
256 | if (defkey && !new) | 263 | if (defunikey && !new) |
257 | __ieee80211_set_default_key(sdata, -1); | 264 | __ieee80211_set_default_key(sdata, -1, true, false); |
265 | if (defmultikey && !new) | ||
266 | __ieee80211_set_default_key(sdata, -1, false, true); | ||
258 | if (defmgmtkey && !new) | 267 | if (defmgmtkey && !new) |
259 | __ieee80211_set_default_mgmt_key(sdata, -1); | 268 | __ieee80211_set_default_mgmt_key(sdata, -1); |
260 | 269 | ||
261 | rcu_assign_pointer(sdata->keys[idx], new); | 270 | rcu_assign_pointer(sdata->keys[idx], new); |
262 | if (defkey && new) | 271 | if (defunikey && new) |
263 | __ieee80211_set_default_key(sdata, new->conf.keyidx); | 272 | __ieee80211_set_default_key(sdata, new->conf.keyidx, |
273 | true, false); | ||
274 | if (defmultikey && new) | ||
275 | __ieee80211_set_default_key(sdata, new->conf.keyidx, | ||
276 | false, true); | ||
264 | if (defmgmtkey && new) | 277 | if (defmgmtkey && new) |
265 | __ieee80211_set_default_mgmt_key(sdata, | 278 | __ieee80211_set_default_mgmt_key(sdata, |
266 | new->conf.keyidx); | 279 | new->conf.keyidx); |
@@ -502,11 +515,12 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
502 | 515 | ||
503 | mutex_lock(&sdata->local->key_mtx); | 516 | mutex_lock(&sdata->local->key_mtx); |
504 | 517 | ||
505 | ieee80211_debugfs_key_remove_default(sdata); | ||
506 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | 518 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
507 | 519 | ||
508 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 520 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
509 | __ieee80211_key_free(key); | 521 | __ieee80211_key_free(key); |
510 | 522 | ||
523 | ieee80211_debugfs_key_update_default(sdata); | ||
524 | |||
511 | mutex_unlock(&sdata->local->key_mtx); | 525 | mutex_unlock(&sdata->local->key_mtx); |
512 | } | 526 | } |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 0db1c0f5f697..8106aa1b7466 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -138,7 +138,8 @@ int __must_check ieee80211_key_link(struct ieee80211_key *key, | |||
138 | struct sta_info *sta); | 138 | struct sta_info *sta); |
139 | void ieee80211_key_free(struct ieee80211_local *local, | 139 | void ieee80211_key_free(struct ieee80211_local *local, |
140 | struct ieee80211_key *key); | 140 | struct ieee80211_key *key); |
141 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); | 141 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
142 | bool uni, bool multi); | ||
142 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 143 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
143 | int idx); | 144 | int idx); |
144 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 145 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/led.c b/net/mac80211/led.c index 063aad944246..4905eb8af572 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c | |||
@@ -54,12 +54,22 @@ void ieee80211_led_radio(struct ieee80211_local *local, bool enabled) | |||
54 | led_trigger_event(local->radio_led, LED_OFF); | 54 | led_trigger_event(local->radio_led, LED_OFF); |
55 | } | 55 | } |
56 | 56 | ||
57 | void ieee80211_led_names(struct ieee80211_local *local) | ||
58 | { | ||
59 | snprintf(local->rx_led_name, sizeof(local->rx_led_name), | ||
60 | "%srx", wiphy_name(local->hw.wiphy)); | ||
61 | snprintf(local->tx_led_name, sizeof(local->tx_led_name), | ||
62 | "%stx", wiphy_name(local->hw.wiphy)); | ||
63 | snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), | ||
64 | "%sassoc", wiphy_name(local->hw.wiphy)); | ||
65 | snprintf(local->radio_led_name, sizeof(local->radio_led_name), | ||
66 | "%sradio", wiphy_name(local->hw.wiphy)); | ||
67 | } | ||
68 | |||
57 | void ieee80211_led_init(struct ieee80211_local *local) | 69 | void ieee80211_led_init(struct ieee80211_local *local) |
58 | { | 70 | { |
59 | local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 71 | local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
60 | if (local->rx_led) { | 72 | if (local->rx_led) { |
61 | snprintf(local->rx_led_name, sizeof(local->rx_led_name), | ||
62 | "%srx", wiphy_name(local->hw.wiphy)); | ||
63 | local->rx_led->name = local->rx_led_name; | 73 | local->rx_led->name = local->rx_led_name; |
64 | if (led_trigger_register(local->rx_led)) { | 74 | if (led_trigger_register(local->rx_led)) { |
65 | kfree(local->rx_led); | 75 | kfree(local->rx_led); |
@@ -69,8 +79,6 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
69 | 79 | ||
70 | local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 80 | local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
71 | if (local->tx_led) { | 81 | if (local->tx_led) { |
72 | snprintf(local->tx_led_name, sizeof(local->tx_led_name), | ||
73 | "%stx", wiphy_name(local->hw.wiphy)); | ||
74 | local->tx_led->name = local->tx_led_name; | 82 | local->tx_led->name = local->tx_led_name; |
75 | if (led_trigger_register(local->tx_led)) { | 83 | if (led_trigger_register(local->tx_led)) { |
76 | kfree(local->tx_led); | 84 | kfree(local->tx_led); |
@@ -80,8 +88,6 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
80 | 88 | ||
81 | local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 89 | local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
82 | if (local->assoc_led) { | 90 | if (local->assoc_led) { |
83 | snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), | ||
84 | "%sassoc", wiphy_name(local->hw.wiphy)); | ||
85 | local->assoc_led->name = local->assoc_led_name; | 91 | local->assoc_led->name = local->assoc_led_name; |
86 | if (led_trigger_register(local->assoc_led)) { | 92 | if (led_trigger_register(local->assoc_led)) { |
87 | kfree(local->assoc_led); | 93 | kfree(local->assoc_led); |
@@ -91,14 +97,19 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
91 | 97 | ||
92 | local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 98 | local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
93 | if (local->radio_led) { | 99 | if (local->radio_led) { |
94 | snprintf(local->radio_led_name, sizeof(local->radio_led_name), | ||
95 | "%sradio", wiphy_name(local->hw.wiphy)); | ||
96 | local->radio_led->name = local->radio_led_name; | 100 | local->radio_led->name = local->radio_led_name; |
97 | if (led_trigger_register(local->radio_led)) { | 101 | if (led_trigger_register(local->radio_led)) { |
98 | kfree(local->radio_led); | 102 | kfree(local->radio_led); |
99 | local->radio_led = NULL; | 103 | local->radio_led = NULL; |
100 | } | 104 | } |
101 | } | 105 | } |
106 | |||
107 | if (local->tpt_led_trigger) { | ||
108 | if (led_trigger_register(&local->tpt_led_trigger->trig)) { | ||
109 | kfree(local->tpt_led_trigger); | ||
110 | local->tpt_led_trigger = NULL; | ||
111 | } | ||
112 | } | ||
102 | } | 113 | } |
103 | 114 | ||
104 | void ieee80211_led_exit(struct ieee80211_local *local) | 115 | void ieee80211_led_exit(struct ieee80211_local *local) |
@@ -119,15 +130,18 @@ void ieee80211_led_exit(struct ieee80211_local *local) | |||
119 | led_trigger_unregister(local->rx_led); | 130 | led_trigger_unregister(local->rx_led); |
120 | kfree(local->rx_led); | 131 | kfree(local->rx_led); |
121 | } | 132 | } |
133 | |||
134 | if (local->tpt_led_trigger) { | ||
135 | led_trigger_unregister(&local->tpt_led_trigger->trig); | ||
136 | kfree(local->tpt_led_trigger); | ||
137 | } | ||
122 | } | 138 | } |
123 | 139 | ||
124 | char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) | 140 | char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) |
125 | { | 141 | { |
126 | struct ieee80211_local *local = hw_to_local(hw); | 142 | struct ieee80211_local *local = hw_to_local(hw); |
127 | 143 | ||
128 | if (local->radio_led) | 144 | return local->radio_led_name; |
129 | return local->radio_led_name; | ||
130 | return NULL; | ||
131 | } | 145 | } |
132 | EXPORT_SYMBOL(__ieee80211_get_radio_led_name); | 146 | EXPORT_SYMBOL(__ieee80211_get_radio_led_name); |
133 | 147 | ||
@@ -135,9 +149,7 @@ char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) | |||
135 | { | 149 | { |
136 | struct ieee80211_local *local = hw_to_local(hw); | 150 | struct ieee80211_local *local = hw_to_local(hw); |
137 | 151 | ||
138 | if (local->assoc_led) | 152 | return local->assoc_led_name; |
139 | return local->assoc_led_name; | ||
140 | return NULL; | ||
141 | } | 153 | } |
142 | EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); | 154 | EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); |
143 | 155 | ||
@@ -145,9 +157,7 @@ char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw) | |||
145 | { | 157 | { |
146 | struct ieee80211_local *local = hw_to_local(hw); | 158 | struct ieee80211_local *local = hw_to_local(hw); |
147 | 159 | ||
148 | if (local->tx_led) | 160 | return local->tx_led_name; |
149 | return local->tx_led_name; | ||
150 | return NULL; | ||
151 | } | 161 | } |
152 | EXPORT_SYMBOL(__ieee80211_get_tx_led_name); | 162 | EXPORT_SYMBOL(__ieee80211_get_tx_led_name); |
153 | 163 | ||
@@ -155,8 +165,144 @@ char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw) | |||
155 | { | 165 | { |
156 | struct ieee80211_local *local = hw_to_local(hw); | 166 | struct ieee80211_local *local = hw_to_local(hw); |
157 | 167 | ||
158 | if (local->rx_led) | 168 | return local->rx_led_name; |
159 | return local->rx_led_name; | ||
160 | return NULL; | ||
161 | } | 169 | } |
162 | EXPORT_SYMBOL(__ieee80211_get_rx_led_name); | 170 | EXPORT_SYMBOL(__ieee80211_get_rx_led_name); |
171 | |||
172 | static unsigned long tpt_trig_traffic(struct ieee80211_local *local, | ||
173 | struct tpt_led_trigger *tpt_trig) | ||
174 | { | ||
175 | unsigned long traffic, delta; | ||
176 | |||
177 | traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes; | ||
178 | |||
179 | delta = traffic - tpt_trig->prev_traffic; | ||
180 | tpt_trig->prev_traffic = traffic; | ||
181 | return DIV_ROUND_UP(delta, 1024 / 8); | ||
182 | } | ||
183 | |||
184 | static void tpt_trig_timer(unsigned long data) | ||
185 | { | ||
186 | struct ieee80211_local *local = (void *)data; | ||
187 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
188 | struct led_classdev *led_cdev; | ||
189 | unsigned long on, off, tpt; | ||
190 | int i; | ||
191 | |||
192 | if (!tpt_trig->running) | ||
193 | return; | ||
194 | |||
195 | mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ)); | ||
196 | |||
197 | tpt = tpt_trig_traffic(local, tpt_trig); | ||
198 | |||
199 | /* default to just solid on */ | ||
200 | on = 1; | ||
201 | off = 0; | ||
202 | |||
203 | for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) { | ||
204 | if (tpt_trig->blink_table[i].throughput < 0 || | ||
205 | tpt > tpt_trig->blink_table[i].throughput) { | ||
206 | off = tpt_trig->blink_table[i].blink_time / 2; | ||
207 | on = tpt_trig->blink_table[i].blink_time - off; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | read_lock(&tpt_trig->trig.leddev_list_lock); | ||
213 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) | ||
214 | led_blink_set(led_cdev, &on, &off); | ||
215 | read_unlock(&tpt_trig->trig.leddev_list_lock); | ||
216 | } | ||
217 | |||
218 | extern char *__ieee80211_create_tpt_led_trigger( | ||
219 | struct ieee80211_hw *hw, unsigned int flags, | ||
220 | const struct ieee80211_tpt_blink *blink_table, | ||
221 | unsigned int blink_table_len) | ||
222 | { | ||
223 | struct ieee80211_local *local = hw_to_local(hw); | ||
224 | struct tpt_led_trigger *tpt_trig; | ||
225 | |||
226 | if (WARN_ON(local->tpt_led_trigger)) | ||
227 | return NULL; | ||
228 | |||
229 | tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL); | ||
230 | if (!tpt_trig) | ||
231 | return NULL; | ||
232 | |||
233 | snprintf(tpt_trig->name, sizeof(tpt_trig->name), | ||
234 | "%stpt", wiphy_name(local->hw.wiphy)); | ||
235 | |||
236 | tpt_trig->trig.name = tpt_trig->name; | ||
237 | |||
238 | tpt_trig->blink_table = blink_table; | ||
239 | tpt_trig->blink_table_len = blink_table_len; | ||
240 | tpt_trig->want = flags; | ||
241 | |||
242 | setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local); | ||
243 | |||
244 | local->tpt_led_trigger = tpt_trig; | ||
245 | |||
246 | return tpt_trig->name; | ||
247 | } | ||
248 | EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger); | ||
249 | |||
250 | static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local) | ||
251 | { | ||
252 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
253 | |||
254 | if (tpt_trig->running) | ||
255 | return; | ||
256 | |||
257 | /* reset traffic */ | ||
258 | tpt_trig_traffic(local, tpt_trig); | ||
259 | tpt_trig->running = true; | ||
260 | |||
261 | tpt_trig_timer((unsigned long)local); | ||
262 | mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ)); | ||
263 | } | ||
264 | |||
265 | static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) | ||
266 | { | ||
267 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
268 | struct led_classdev *led_cdev; | ||
269 | |||
270 | if (!tpt_trig->running) | ||
271 | return; | ||
272 | |||
273 | tpt_trig->running = false; | ||
274 | del_timer_sync(&tpt_trig->timer); | ||
275 | |||
276 | read_lock(&tpt_trig->trig.leddev_list_lock); | ||
277 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) | ||
278 | led_brightness_set(led_cdev, LED_OFF); | ||
279 | read_unlock(&tpt_trig->trig.leddev_list_lock); | ||
280 | } | ||
281 | |||
282 | void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local, | ||
283 | unsigned int types_on, unsigned int types_off) | ||
284 | { | ||
285 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
286 | bool allowed; | ||
287 | |||
288 | WARN_ON(types_on & types_off); | ||
289 | |||
290 | if (!tpt_trig) | ||
291 | return; | ||
292 | |||
293 | tpt_trig->active &= ~types_off; | ||
294 | tpt_trig->active |= types_on; | ||
295 | |||
296 | /* | ||
297 | * Regardless of wanted state, we shouldn't blink when | ||
298 | * the radio is disabled -- this can happen due to some | ||
299 | * code ordering issues with __ieee80211_recalc_idle() | ||
300 | * being called before the radio is started. | ||
301 | */ | ||
302 | allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO; | ||
303 | |||
304 | if (!allowed || !(tpt_trig->active & tpt_trig->want)) | ||
305 | ieee80211_stop_tpt_led_trig(local); | ||
306 | else | ||
307 | ieee80211_start_tpt_led_trig(local); | ||
308 | } | ||
diff --git a/net/mac80211/led.h b/net/mac80211/led.h index 77b1e1ba6039..e0275d9befa8 100644 --- a/net/mac80211/led.h +++ b/net/mac80211/led.h | |||
@@ -12,14 +12,17 @@ | |||
12 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
13 | 13 | ||
14 | #ifdef CONFIG_MAC80211_LEDS | 14 | #ifdef CONFIG_MAC80211_LEDS |
15 | extern void ieee80211_led_rx(struct ieee80211_local *local); | 15 | void ieee80211_led_rx(struct ieee80211_local *local); |
16 | extern void ieee80211_led_tx(struct ieee80211_local *local, int q); | 16 | void ieee80211_led_tx(struct ieee80211_local *local, int q); |
17 | extern void ieee80211_led_assoc(struct ieee80211_local *local, | 17 | void ieee80211_led_assoc(struct ieee80211_local *local, |
18 | bool associated); | 18 | bool associated); |
19 | extern void ieee80211_led_radio(struct ieee80211_local *local, | 19 | void ieee80211_led_radio(struct ieee80211_local *local, |
20 | bool enabled); | 20 | bool enabled); |
21 | extern void ieee80211_led_init(struct ieee80211_local *local); | 21 | void ieee80211_led_names(struct ieee80211_local *local); |
22 | extern void ieee80211_led_exit(struct ieee80211_local *local); | 22 | void ieee80211_led_init(struct ieee80211_local *local); |
23 | void ieee80211_led_exit(struct ieee80211_local *local); | ||
24 | void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local, | ||
25 | unsigned int types_on, unsigned int types_off); | ||
23 | #else | 26 | #else |
24 | static inline void ieee80211_led_rx(struct ieee80211_local *local) | 27 | static inline void ieee80211_led_rx(struct ieee80211_local *local) |
25 | { | 28 | { |
@@ -35,10 +38,36 @@ static inline void ieee80211_led_radio(struct ieee80211_local *local, | |||
35 | bool enabled) | 38 | bool enabled) |
36 | { | 39 | { |
37 | } | 40 | } |
41 | static inline void ieee80211_led_names(struct ieee80211_local *local) | ||
42 | { | ||
43 | } | ||
38 | static inline void ieee80211_led_init(struct ieee80211_local *local) | 44 | static inline void ieee80211_led_init(struct ieee80211_local *local) |
39 | { | 45 | { |
40 | } | 46 | } |
41 | static inline void ieee80211_led_exit(struct ieee80211_local *local) | 47 | static inline void ieee80211_led_exit(struct ieee80211_local *local) |
42 | { | 48 | { |
43 | } | 49 | } |
50 | static inline void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local, | ||
51 | unsigned int types_on, | ||
52 | unsigned int types_off) | ||
53 | { | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | static inline void | ||
58 | ieee80211_tpt_led_trig_tx(struct ieee80211_local *local, __le16 fc, int bytes) | ||
59 | { | ||
60 | #ifdef CONFIG_MAC80211_LEDS | ||
61 | if (local->tpt_led_trigger && ieee80211_is_data(fc)) | ||
62 | local->tpt_led_trigger->tx_bytes += bytes; | ||
63 | #endif | ||
64 | } | ||
65 | |||
66 | static inline void | ||
67 | ieee80211_tpt_led_trig_rx(struct ieee80211_local *local, __le16 fc, int bytes) | ||
68 | { | ||
69 | #ifdef CONFIG_MAC80211_LEDS | ||
70 | if (local->tpt_led_trigger && ieee80211_is_data(fc)) | ||
71 | local->tpt_led_trigger->rx_bytes += bytes; | ||
44 | #endif | 72 | #endif |
73 | } | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 107a0cbe52ac..bbe8e0ac6e52 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -245,9 +245,12 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
245 | sdata->vif.bss_conf.enable_beacon = | 245 | sdata->vif.bss_conf.enable_beacon = |
246 | !!sdata->u.ibss.presp; | 246 | !!sdata->u.ibss.presp; |
247 | break; | 247 | break; |
248 | #ifdef CONFIG_MAC80211_MESH | ||
248 | case NL80211_IFTYPE_MESH_POINT: | 249 | case NL80211_IFTYPE_MESH_POINT: |
249 | sdata->vif.bss_conf.enable_beacon = true; | 250 | sdata->vif.bss_conf.enable_beacon = |
251 | !!sdata->u.mesh.mesh_id_len; | ||
250 | break; | 252 | break; |
253 | #endif | ||
251 | default: | 254 | default: |
252 | /* not reached */ | 255 | /* not reached */ |
253 | WARN_ON(1); | 256 | WARN_ON(1); |
@@ -481,6 +484,10 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
481 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | 484 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | |
482 | BIT(IEEE80211_STYPE_ACTION >> 4), | 485 | BIT(IEEE80211_STYPE_ACTION >> 4), |
483 | }, | 486 | }, |
487 | [NL80211_IFTYPE_MESH_POINT] = { | ||
488 | .tx = 0xffff, | ||
489 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4), | ||
490 | }, | ||
484 | }; | 491 | }; |
485 | 492 | ||
486 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 493 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
@@ -514,10 +521,15 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
514 | 521 | ||
515 | wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; | 522 | wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; |
516 | 523 | ||
524 | wiphy->privid = mac80211_wiphy_privid; | ||
525 | |||
517 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | | 526 | wiphy->flags |= WIPHY_FLAG_NETNS_OK | |
518 | WIPHY_FLAG_4ADDR_AP | | 527 | WIPHY_FLAG_4ADDR_AP | |
519 | WIPHY_FLAG_4ADDR_STATION; | 528 | WIPHY_FLAG_4ADDR_STATION | |
520 | wiphy->privid = mac80211_wiphy_privid; | 529 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; |
530 | |||
531 | if (!ops->set_key) | ||
532 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | ||
521 | 533 | ||
522 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss); | 534 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss); |
523 | 535 | ||
@@ -593,6 +605,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
593 | /* init dummy netdev for use w/ NAPI */ | 605 | /* init dummy netdev for use w/ NAPI */ |
594 | init_dummy_netdev(&local->napi_dev); | 606 | init_dummy_netdev(&local->napi_dev); |
595 | 607 | ||
608 | ieee80211_led_names(local); | ||
609 | |||
596 | return local_to_hw(local); | 610 | return local_to_hw(local); |
597 | } | 611 | } |
598 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 612 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
@@ -737,6 +751,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
737 | } | 751 | } |
738 | } | 752 | } |
739 | 753 | ||
754 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | ||
755 | |||
740 | result = wiphy_register(local->hw.wiphy); | 756 | result = wiphy_register(local->hw.wiphy); |
741 | if (result < 0) | 757 | if (result < 0) |
742 | goto fail_wiphy_register; | 758 | goto fail_wiphy_register; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c8a4f19ed13b..ca3af4685b0a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -124,15 +124,6 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
124 | ieee80211_mesh_housekeeping_timer((unsigned long) sdata); | 124 | ieee80211_mesh_housekeeping_timer((unsigned long) sdata); |
125 | } | 125 | } |
126 | 126 | ||
127 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) | ||
128 | { | ||
129 | sta->mesh_pp_id = 0; /* HWMP */ | ||
130 | sta->mesh_pm_id = 0; /* Airtime */ | ||
131 | sta->mesh_cc_id = 0; /* Disabled */ | ||
132 | sta->mesh_sp_id = 0; /* Neighbor Offset */ | ||
133 | sta->mesh_auth_id = 0; /* Disabled */ | ||
134 | } | ||
135 | |||
136 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 127 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
137 | { | 128 | { |
138 | int i; | 129 | int i; |
@@ -287,6 +278,13 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
287 | *pos++ |= sdata->u.mesh.accepting_plinks ? | 278 | *pos++ |= sdata->u.mesh.accepting_plinks ? |
288 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 279 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
289 | *pos++ = 0x00; | 280 | *pos++ = 0x00; |
281 | |||
282 | if (sdata->u.mesh.vendor_ie) { | ||
283 | int len = sdata->u.mesh.vendor_ie_len; | ||
284 | const u8 *data = sdata->u.mesh.vendor_ie; | ||
285 | if (skb_tailroom(skb) > len) | ||
286 | memcpy(skb_put(skb, len), data, len); | ||
287 | } | ||
290 | } | 288 | } |
291 | 289 | ||
292 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) | 290 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) |
@@ -412,39 +410,33 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | |||
412 | * ieee80211_new_mesh_header - create a new mesh header | 410 | * ieee80211_new_mesh_header - create a new mesh header |
413 | * @meshhdr: uninitialized mesh header | 411 | * @meshhdr: uninitialized mesh header |
414 | * @sdata: mesh interface to be used | 412 | * @sdata: mesh interface to be used |
415 | * @addr4: addr4 of the mesh frame (1st in ae header) | 413 | * @addr4or5: 1st address in the ae header, which may correspond to address 4 |
416 | * may be NULL | 414 | * (if addr6 is NULL) or address 5 (if addr6 is present). It may |
417 | * @addr5: addr5 of the mesh frame (1st or 2nd in ae header) | 415 | * be NULL. |
418 | * may be NULL unless addr6 is present | 416 | * @addr6: 2nd address in the ae header, which corresponds to addr6 of the |
419 | * @addr6: addr6 of the mesh frame (2nd or 3rd in ae header) | 417 | * mesh frame |
420 | * may be NULL unless addr5 is present | ||
421 | * | 418 | * |
422 | * Return the header length. | 419 | * Return the header length. |
423 | */ | 420 | */ |
424 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 421 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
425 | struct ieee80211_sub_if_data *sdata, char *addr4, | 422 | struct ieee80211_sub_if_data *sdata, char *addr4or5, |
426 | char *addr5, char *addr6) | 423 | char *addr6) |
427 | { | 424 | { |
428 | int aelen = 0; | 425 | int aelen = 0; |
426 | BUG_ON(!addr4or5 && addr6); | ||
429 | memset(meshhdr, 0, sizeof(*meshhdr)); | 427 | memset(meshhdr, 0, sizeof(*meshhdr)); |
430 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 428 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
431 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); | 429 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); |
432 | sdata->u.mesh.mesh_seqnum++; | 430 | sdata->u.mesh.mesh_seqnum++; |
433 | if (addr4) { | 431 | if (addr4or5 && !addr6) { |
434 | meshhdr->flags |= MESH_FLAGS_AE_A4; | 432 | meshhdr->flags |= MESH_FLAGS_AE_A4; |
435 | aelen += ETH_ALEN; | 433 | aelen += ETH_ALEN; |
436 | memcpy(meshhdr->eaddr1, addr4, ETH_ALEN); | 434 | memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); |
437 | } | 435 | } else if (addr4or5 && addr6) { |
438 | if (addr5 && addr6) { | ||
439 | meshhdr->flags |= MESH_FLAGS_AE_A5_A6; | 436 | meshhdr->flags |= MESH_FLAGS_AE_A5_A6; |
440 | aelen += 2 * ETH_ALEN; | 437 | aelen += 2 * ETH_ALEN; |
441 | if (!addr4) { | 438 | memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); |
442 | memcpy(meshhdr->eaddr1, addr5, ETH_ALEN); | 439 | memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); |
443 | memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); | ||
444 | } else { | ||
445 | memcpy(meshhdr->eaddr2, addr5, ETH_ALEN); | ||
446 | memcpy(meshhdr->eaddr3, addr6, ETH_ALEN); | ||
447 | } | ||
448 | } | 440 | } |
449 | return 6 + aelen; | 441 | return 6 + aelen; |
450 | } | 442 | } |
@@ -513,6 +505,14 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
513 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 505 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
514 | struct ieee80211_local *local = sdata->local; | 506 | struct ieee80211_local *local = sdata->local; |
515 | 507 | ||
508 | local->fif_other_bss++; | ||
509 | /* mesh ifaces must set allmulti to forward mcast traffic */ | ||
510 | atomic_inc(&local->iff_allmultis); | ||
511 | ieee80211_configure_filter(local); | ||
512 | |||
513 | ifmsh->mesh_cc_id = 0; /* Disabled */ | ||
514 | ifmsh->mesh_sp_id = 0; /* Neighbor Offset */ | ||
515 | ifmsh->mesh_auth_id = 0; /* Disabled */ | ||
516 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 516 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
517 | ieee80211_mesh_root_setup(ifmsh); | 517 | ieee80211_mesh_root_setup(ifmsh); |
518 | ieee80211_queue_work(&local->hw, &sdata->work); | 518 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -524,6 +524,13 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
524 | 524 | ||
525 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 525 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
526 | { | 526 | { |
527 | struct ieee80211_local *local = sdata->local; | ||
528 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
529 | |||
530 | ifmsh->mesh_id_len = 0; | ||
531 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | ||
532 | sta_info_flush(local, NULL); | ||
533 | |||
527 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 534 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
528 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 535 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
529 | /* | 536 | /* |
@@ -534,6 +541,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
534 | * it no longer is. | 541 | * it no longer is. |
535 | */ | 542 | */ |
536 | cancel_work_sync(&sdata->work); | 543 | cancel_work_sync(&sdata->work); |
544 | |||
545 | local->fif_other_bss--; | ||
546 | atomic_dec(&local->iff_allmultis); | ||
547 | ieee80211_configure_filter(local); | ||
537 | } | 548 | } |
538 | 549 | ||
539 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | 550 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, |
@@ -663,26 +674,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
663 | ieee80211_mesh_housekeeping_timer, | 674 | ieee80211_mesh_housekeeping_timer, |
664 | (unsigned long) sdata); | 675 | (unsigned long) sdata); |
665 | 676 | ||
666 | ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; | ||
667 | ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | ||
668 | ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | ||
669 | ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | ||
670 | ifmsh->mshcfg.dot11MeshTTL = MESH_TTL; | ||
671 | ifmsh->mshcfg.auto_open_plinks = true; | ||
672 | ifmsh->mshcfg.dot11MeshMaxPeerLinks = | ||
673 | MESH_MAX_ESTAB_PLINKS; | ||
674 | ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout = | ||
675 | MESH_PATH_TIMEOUT; | ||
676 | ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval = | ||
677 | MESH_PREQ_MIN_INT; | ||
678 | ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = | ||
679 | MESH_DIAM_TRAVERSAL_TIME; | ||
680 | ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries = | ||
681 | MESH_MAX_PREQ_RETRIES; | ||
682 | ifmsh->mshcfg.path_refresh_time = | ||
683 | MESH_PATH_REFRESH_TIME; | ||
684 | ifmsh->mshcfg.min_discovery_timeout = | ||
685 | MESH_MIN_DISCOVERY_TIMEOUT; | ||
686 | ifmsh->accepting_plinks = true; | 677 | ifmsh->accepting_plinks = true; |
687 | ifmsh->preq_id = 0; | 678 | ifmsh->preq_id = 0; |
688 | ifmsh->sn = 0; | 679 | ifmsh->sn = 0; |
@@ -692,7 +683,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
692 | /* Allocate all mesh structures when creating the first mesh interface. */ | 683 | /* Allocate all mesh structures when creating the first mesh interface. */ |
693 | if (!mesh_allocated) | 684 | if (!mesh_allocated) |
694 | ieee80211s_init(); | 685 | ieee80211s_init(); |
695 | mesh_ids_set_default(ifmsh); | ||
696 | setup_timer(&ifmsh->mesh_path_timer, | 686 | setup_timer(&ifmsh->mesh_path_timer, |
697 | ieee80211_mesh_path_timer, | 687 | ieee80211_mesh_path_timer, |
698 | (unsigned long) sdata); | 688 | (unsigned long) sdata); |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 58e741128968..b99e230fe31c 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -164,44 +164,10 @@ struct mesh_rmc { | |||
164 | }; | 164 | }; |
165 | 165 | ||
166 | 166 | ||
167 | /* | ||
168 | * MESH_CFG_COMP_LEN Includes: | ||
169 | * - Active path selection protocol ID. | ||
170 | * - Active path selection metric ID. | ||
171 | * - Congestion control mode identifier. | ||
172 | * - Channel precedence. | ||
173 | * Does not include mesh capabilities, which may vary across nodes in the same | ||
174 | * mesh | ||
175 | */ | ||
176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) | ||
177 | |||
178 | /* Default values, timeouts in ms */ | ||
179 | #define MESH_TTL 31 | ||
180 | #define MESH_MAX_RETR 3 | ||
181 | #define MESH_RET_T 100 | ||
182 | #define MESH_CONF_T 100 | ||
183 | #define MESH_HOLD_T 100 | ||
184 | |||
185 | #define MESH_PATH_TIMEOUT 5000 | ||
186 | /* Minimum interval between two consecutive PREQs originated by the same | ||
187 | * interface | ||
188 | */ | ||
189 | #define MESH_PREQ_MIN_INT 10 | ||
190 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
191 | /* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before | ||
192 | * timing out. This way it will remain ACTIVE and no data frames will be | ||
193 | * unnecesarily held in the pending queue. | ||
194 | */ | ||
195 | #define MESH_PATH_REFRESH_TIME 1000 | ||
196 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
197 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ | 167 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ |
198 | 168 | ||
199 | #define MESH_MAX_PREQ_RETRIES 4 | ||
200 | #define MESH_PATH_EXPIRE (600 * HZ) | 169 | #define MESH_PATH_EXPIRE (600 * HZ) |
201 | 170 | ||
202 | /* Default maximum number of established plinks per interface */ | ||
203 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
204 | |||
205 | /* Default maximum number of plinks per interface */ | 171 | /* Default maximum number of plinks per interface */ |
206 | #define MESH_MAX_PLINKS 256 | 172 | #define MESH_MAX_PLINKS 256 |
207 | 173 | ||
@@ -221,8 +187,8 @@ struct mesh_rmc { | |||
221 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | 187 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, |
222 | const u8 *da, const u8 *sa); | 188 | const u8 *da, const u8 *sa); |
223 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 189 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
224 | struct ieee80211_sub_if_data *sdata, char *addr4, | 190 | struct ieee80211_sub_if_data *sdata, char *addr4or5, |
225 | char *addr5, char *addr6); | 191 | char *addr6); |
226 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 192 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
227 | struct ieee80211_sub_if_data *sdata); | 193 | struct ieee80211_sub_if_data *sdata); |
228 | bool mesh_matches_local(struct ieee802_11_elems *ie, | 194 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
@@ -318,6 +284,11 @@ static inline void mesh_path_activate(struct mesh_path *mpath) | |||
318 | mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED; | 284 | mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED; |
319 | } | 285 | } |
320 | 286 | ||
287 | static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | ||
288 | { | ||
289 | return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP; | ||
290 | } | ||
291 | |||
321 | #define for_each_mesh_entry(x, p, node, i) \ | 292 | #define for_each_mesh_entry(x, p, node, i) \ |
322 | for (i = 0; i <= x->hash_mask; i++) \ | 293 | for (i = 0; i <= x->hash_mask; i++) \ |
323 | hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) | 294 | hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) |
@@ -338,6 +309,8 @@ static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
338 | {} | 309 | {} |
339 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} | 310 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} |
340 | static inline void mesh_plink_restart(struct sta_info *sta) {} | 311 | static inline void mesh_plink_restart(struct sta_info *sta) {} |
312 | static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | ||
313 | { return false; } | ||
341 | #endif | 314 | #endif |
342 | 315 | ||
343 | #endif /* IEEE80211S_H */ | 316 | #endif /* IEEE80211S_H */ |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 829e08a657d0..5bf64d7112b3 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -232,7 +232,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, | |||
232 | *pos++ = WLAN_EID_PERR; | 232 | *pos++ = WLAN_EID_PERR; |
233 | *pos++ = ie_len; | 233 | *pos++ = ie_len; |
234 | /* ttl */ | 234 | /* ttl */ |
235 | *pos++ = MESH_TTL; | 235 | *pos++ = ttl; |
236 | /* number of destinations */ | 236 | /* number of destinations */ |
237 | *pos++ = 1; | 237 | *pos++ = 1; |
238 | /* | 238 | /* |
@@ -522,7 +522,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
522 | 522 | ||
523 | if (reply) { | 523 | if (reply) { |
524 | lifetime = PREQ_IE_LIFETIME(preq_elem); | 524 | lifetime = PREQ_IE_LIFETIME(preq_elem); |
525 | ttl = ifmsh->mshcfg.dot11MeshTTL; | 525 | ttl = ifmsh->mshcfg.element_ttl; |
526 | if (ttl != 0) { | 526 | if (ttl != 0) { |
527 | mhwmp_dbg("replying to the PREQ\n"); | 527 | mhwmp_dbg("replying to the PREQ\n"); |
528 | mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, | 528 | mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, |
@@ -877,7 +877,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
877 | sdata->u.mesh.last_sn_update = jiffies; | 877 | sdata->u.mesh.last_sn_update = jiffies; |
878 | } | 878 | } |
879 | lifetime = default_lifetime(sdata); | 879 | lifetime = default_lifetime(sdata); |
880 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 880 | ttl = sdata->u.mesh.mshcfg.element_ttl; |
881 | if (ttl == 0) { | 881 | if (ttl == 0) { |
882 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 882 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
883 | spin_unlock_bh(&mpath->state_lock); | 883 | spin_unlock_bh(&mpath->state_lock); |
@@ -1013,5 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
1013 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, | 1013 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, |
1014 | cpu_to_le32(++ifmsh->sn), | 1014 | cpu_to_le32(++ifmsh->sn), |
1015 | 0, NULL, 0, broadcast_addr, | 1015 | 0, NULL, 0, broadcast_addr, |
1016 | 0, MESH_TTL, 0, 0, 0, sdata); | 1016 | 0, sdata->u.mesh.mshcfg.element_ttl, |
1017 | 0, 0, 0, sdata); | ||
1017 | } | 1018 | } |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 349e466cf08b..8d65b47d9837 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -467,8 +467,8 @@ void mesh_plink_broken(struct sta_info *sta) | |||
467 | mpath->flags &= ~MESH_PATH_ACTIVE; | 467 | mpath->flags &= ~MESH_PATH_ACTIVE; |
468 | ++mpath->sn; | 468 | ++mpath->sn; |
469 | spin_unlock_bh(&mpath->state_lock); | 469 | spin_unlock_bh(&mpath->state_lock); |
470 | mesh_path_error_tx(MESH_TTL, mpath->dst, | 470 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, |
471 | cpu_to_le32(mpath->sn), | 471 | mpath->dst, cpu_to_le32(mpath->sn), |
472 | cpu_to_le16(PERR_RCODE_DEST_UNREACH), | 472 | cpu_to_le16(PERR_RCODE_DEST_UNREACH), |
473 | bcast, sdata); | 473 | bcast, sdata); |
474 | } else | 474 | } else |
@@ -614,7 +614,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
614 | mpath = mesh_path_lookup(da, sdata); | 614 | mpath = mesh_path_lookup(da, sdata); |
615 | if (mpath) | 615 | if (mpath) |
616 | sn = ++mpath->sn; | 616 | sn = ++mpath->sn; |
617 | mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), | 617 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, |
618 | cpu_to_le32(sn), | ||
618 | cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata); | 619 | cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata); |
619 | } | 620 | } |
620 | 621 | ||
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 1c91f0f3c307..44b53931ba5e 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -160,7 +160,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
160 | enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid, | 160 | enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid, |
161 | __le16 reason) { | 161 | __le16 reason) { |
162 | struct ieee80211_local *local = sdata->local; | 162 | struct ieee80211_local *local = sdata->local; |
163 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 163 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + |
164 | sdata->u.mesh.vendor_ie_len); | ||
164 | struct ieee80211_mgmt *mgmt; | 165 | struct ieee80211_mgmt *mgmt; |
165 | bool include_plid = false; | 166 | bool include_plid = false; |
166 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; | 167 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a3a9421555af..45fbb9e33746 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -28,13 +28,19 @@ | |||
28 | #include "rate.h" | 28 | #include "rate.h" |
29 | #include "led.h" | 29 | #include "led.h" |
30 | 30 | ||
31 | #define IEEE80211_MAX_NULLFUNC_TRIES 2 | ||
31 | #define IEEE80211_MAX_PROBE_TRIES 5 | 32 | #define IEEE80211_MAX_PROBE_TRIES 5 |
32 | 33 | ||
33 | /* | 34 | /* |
34 | * beacon loss detection timeout | 35 | * Beacon loss timeout is calculated as N frames times the |
35 | * XXX: should depend on beacon interval | 36 | * advertised beacon interval. This may need to be somewhat |
37 | * higher than what hardware might detect to account for | ||
38 | * delays in the host processing frames. But since we also | ||
39 | * probe on beacon miss before declaring the connection lost | ||
40 | * default to what we want. | ||
36 | */ | 41 | */ |
37 | #define IEEE80211_BEACON_LOSS_TIME (2 * HZ) | 42 | #define IEEE80211_BEACON_LOSS_COUNT 7 |
43 | |||
38 | /* | 44 | /* |
39 | * Time the connection can be idle before we probe | 45 | * Time the connection can be idle before we probe |
40 | * it to see if we can still talk to the AP. | 46 | * it to see if we can still talk to the AP. |
@@ -121,7 +127,7 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) | |||
121 | return; | 127 | return; |
122 | 128 | ||
123 | mod_timer(&sdata->u.mgd.bcn_mon_timer, | 129 | mod_timer(&sdata->u.mgd.bcn_mon_timer, |
124 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); | 130 | round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); |
125 | } | 131 | } |
126 | 132 | ||
127 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | 133 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) |
@@ -619,11 +625,12 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
619 | /* | 625 | /* |
620 | * Go to full PSM if the user configures a very low | 626 | * Go to full PSM if the user configures a very low |
621 | * latency requirement. | 627 | * latency requirement. |
622 | * The 2 second value is there for compatibility until | 628 | * The 2000 second value is there for compatibility |
623 | * the PM_QOS_NETWORK_LATENCY is configured with real | 629 | * until the PM_QOS_NETWORK_LATENCY is configured |
624 | * values. | 630 | * with real values. |
625 | */ | 631 | */ |
626 | if (latency > 1900000000 && latency != 2000000000) | 632 | if (latency > (1900 * USEC_PER_MSEC) && |
633 | latency != (2000 * USEC_PER_SEC)) | ||
627 | timeout = 0; | 634 | timeout = 0; |
628 | else | 635 | else |
629 | timeout = 100; | 636 | timeout = 100; |
@@ -871,6 +878,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
871 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 878 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
872 | cbss->capability, bss->has_erp_value, bss->erp_value); | 879 | cbss->capability, bss->has_erp_value, bss->erp_value); |
873 | 880 | ||
881 | sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( | ||
882 | IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); | ||
883 | |||
874 | sdata->u.mgd.associated = cbss; | 884 | sdata->u.mgd.associated = cbss; |
875 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); | 885 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
876 | 886 | ||
@@ -1026,6 +1036,54 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1026 | ieee80211_sta_reset_conn_monitor(sdata); | 1036 | ieee80211_sta_reset_conn_monitor(sdata); |
1027 | } | 1037 | } |
1028 | 1038 | ||
1039 | static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) | ||
1040 | { | ||
1041 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1042 | |||
1043 | if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
1044 | IEEE80211_STA_CONNECTION_POLL))) | ||
1045 | return; | ||
1046 | |||
1047 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1048 | IEEE80211_STA_BEACON_POLL); | ||
1049 | mutex_lock(&sdata->local->iflist_mtx); | ||
1050 | ieee80211_recalc_ps(sdata->local, -1); | ||
1051 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1052 | |||
1053 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
1054 | return; | ||
1055 | |||
1056 | /* | ||
1057 | * We've received a probe response, but are not sure whether | ||
1058 | * we have or will be receiving any beacons or data, so let's | ||
1059 | * schedule the timers again, just in case. | ||
1060 | */ | ||
1061 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
1062 | |||
1063 | mod_timer(&ifmgd->conn_mon_timer, | ||
1064 | round_jiffies_up(jiffies + | ||
1065 | IEEE80211_CONNECTION_IDLE_TIME)); | ||
1066 | } | ||
1067 | |||
1068 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | ||
1069 | struct ieee80211_hdr *hdr, bool ack) | ||
1070 | { | ||
1071 | if (!ieee80211_is_data(hdr->frame_control)) | ||
1072 | return; | ||
1073 | |||
1074 | if (ack) | ||
1075 | ieee80211_sta_reset_conn_monitor(sdata); | ||
1076 | |||
1077 | if (ieee80211_is_nullfunc(hdr->frame_control) && | ||
1078 | sdata->u.mgd.probe_send_count > 0) { | ||
1079 | if (ack) | ||
1080 | sdata->u.mgd.probe_send_count = 0; | ||
1081 | else | ||
1082 | sdata->u.mgd.nullfunc_failed = true; | ||
1083 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1029 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1087 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
1030 | { | 1088 | { |
1031 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1089 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1041,8 +1099,20 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1041 | if (ifmgd->probe_send_count >= unicast_limit) | 1099 | if (ifmgd->probe_send_count >= unicast_limit) |
1042 | dst = NULL; | 1100 | dst = NULL; |
1043 | 1101 | ||
1044 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1102 | /* |
1045 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | 1103 | * When the hardware reports an accurate Tx ACK status, it's |
1104 | * better to send a nullfunc frame instead of a probe request, | ||
1105 | * as it will kick us off the AP quickly if we aren't associated | ||
1106 | * anymore. The timeout will be reset if the frame is ACKed by | ||
1107 | * the AP. | ||
1108 | */ | ||
1109 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
1110 | ifmgd->nullfunc_failed = false; | ||
1111 | ieee80211_send_nullfunc(sdata->local, sdata, 0); | ||
1112 | } else { | ||
1113 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | ||
1114 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | ||
1115 | } | ||
1046 | 1116 | ||
1047 | ifmgd->probe_send_count++; | 1117 | ifmgd->probe_send_count++; |
1048 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1118 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; |
@@ -1108,6 +1178,30 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
1108 | mutex_unlock(&ifmgd->mtx); | 1178 | mutex_unlock(&ifmgd->mtx); |
1109 | } | 1179 | } |
1110 | 1180 | ||
1181 | struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | ||
1182 | struct ieee80211_vif *vif) | ||
1183 | { | ||
1184 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1185 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1186 | struct sk_buff *skb; | ||
1187 | const u8 *ssid; | ||
1188 | |||
1189 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
1190 | return NULL; | ||
1191 | |||
1192 | ASSERT_MGD_MTX(ifmgd); | ||
1193 | |||
1194 | if (!ifmgd->associated) | ||
1195 | return NULL; | ||
1196 | |||
1197 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | ||
1198 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | ||
1199 | ssid + 2, ssid[1], NULL, 0); | ||
1200 | |||
1201 | return skb; | ||
1202 | } | ||
1203 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | ||
1204 | |||
1111 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1205 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) |
1112 | { | 1206 | { |
1113 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1207 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1485,29 +1579,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1485 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1579 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1486 | 1580 | ||
1487 | if (ifmgd->associated && | 1581 | if (ifmgd->associated && |
1488 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && | 1582 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) |
1489 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1583 | ieee80211_reset_ap_probe(sdata); |
1490 | IEEE80211_STA_CONNECTION_POLL)) { | ||
1491 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1492 | IEEE80211_STA_BEACON_POLL); | ||
1493 | mutex_lock(&sdata->local->iflist_mtx); | ||
1494 | ieee80211_recalc_ps(sdata->local, -1); | ||
1495 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1496 | |||
1497 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
1498 | return; | ||
1499 | |||
1500 | /* | ||
1501 | * We've received a probe response, but are not sure whether | ||
1502 | * we have or will be receiving any beacons or data, so let's | ||
1503 | * schedule the timers again, just in case. | ||
1504 | */ | ||
1505 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
1506 | |||
1507 | mod_timer(&ifmgd->conn_mon_timer, | ||
1508 | round_jiffies_up(jiffies + | ||
1509 | IEEE80211_CONNECTION_IDLE_TIME)); | ||
1510 | } | ||
1511 | } | 1584 | } |
1512 | 1585 | ||
1513 | /* | 1586 | /* |
@@ -1845,6 +1918,31 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1845 | ieee80211_queue_work(&local->hw, &sdata->work); | 1918 | ieee80211_queue_work(&local->hw, &sdata->work); |
1846 | } | 1919 | } |
1847 | 1920 | ||
1921 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | ||
1922 | u8 *bssid) | ||
1923 | { | ||
1924 | struct ieee80211_local *local = sdata->local; | ||
1925 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1926 | |||
1927 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1928 | IEEE80211_STA_BEACON_POLL); | ||
1929 | |||
1930 | ieee80211_set_disassoc(sdata, true, true); | ||
1931 | mutex_unlock(&ifmgd->mtx); | ||
1932 | mutex_lock(&local->mtx); | ||
1933 | ieee80211_recalc_idle(local); | ||
1934 | mutex_unlock(&local->mtx); | ||
1935 | /* | ||
1936 | * must be outside lock due to cfg80211, | ||
1937 | * but that's not a problem. | ||
1938 | */ | ||
1939 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
1940 | IEEE80211_STYPE_DEAUTH, | ||
1941 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
1942 | NULL, true); | ||
1943 | mutex_lock(&ifmgd->mtx); | ||
1944 | } | ||
1945 | |||
1848 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | 1946 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
1849 | { | 1947 | { |
1850 | struct ieee80211_local *local = sdata->local; | 1948 | struct ieee80211_local *local = sdata->local; |
@@ -1857,12 +1955,49 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1857 | IEEE80211_STA_CONNECTION_POLL) && | 1955 | IEEE80211_STA_CONNECTION_POLL) && |
1858 | ifmgd->associated) { | 1956 | ifmgd->associated) { |
1859 | u8 bssid[ETH_ALEN]; | 1957 | u8 bssid[ETH_ALEN]; |
1958 | int max_tries; | ||
1860 | 1959 | ||
1861 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 1960 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1862 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
1863 | run_again(ifmgd, ifmgd->probe_timeout); | ||
1864 | 1961 | ||
1865 | else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { | 1962 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
1963 | max_tries = IEEE80211_MAX_NULLFUNC_TRIES; | ||
1964 | else | ||
1965 | max_tries = IEEE80211_MAX_PROBE_TRIES; | ||
1966 | |||
1967 | /* ACK received for nullfunc probing frame */ | ||
1968 | if (!ifmgd->probe_send_count) | ||
1969 | ieee80211_reset_ap_probe(sdata); | ||
1970 | else if (ifmgd->nullfunc_failed) { | ||
1971 | if (ifmgd->probe_send_count < max_tries) { | ||
1972 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1973 | wiphy_debug(local->hw.wiphy, | ||
1974 | "%s: No ack for nullfunc frame to" | ||
1975 | " AP %pM, try %d\n", | ||
1976 | sdata->name, bssid, | ||
1977 | ifmgd->probe_send_count); | ||
1978 | #endif | ||
1979 | ieee80211_mgd_probe_ap_send(sdata); | ||
1980 | } else { | ||
1981 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1982 | wiphy_debug(local->hw.wiphy, | ||
1983 | "%s: No ack for nullfunc frame to" | ||
1984 | " AP %pM, disconnecting.\n", | ||
1985 | sdata->name, bssid); | ||
1986 | #endif | ||
1987 | ieee80211_sta_connection_lost(sdata, bssid); | ||
1988 | } | ||
1989 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
1990 | run_again(ifmgd, ifmgd->probe_timeout); | ||
1991 | else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
1992 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1993 | wiphy_debug(local->hw.wiphy, | ||
1994 | "%s: Failed to send nullfunc to AP %pM" | ||
1995 | " after %dms, disconnecting.\n", | ||
1996 | sdata->name, | ||
1997 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | ||
1998 | #endif | ||
1999 | ieee80211_sta_connection_lost(sdata, bssid); | ||
2000 | } else if (ifmgd->probe_send_count < max_tries) { | ||
1866 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2001 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1867 | wiphy_debug(local->hw.wiphy, | 2002 | wiphy_debug(local->hw.wiphy, |
1868 | "%s: No probe response from AP %pM" | 2003 | "%s: No probe response from AP %pM" |
@@ -1877,27 +2012,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1877 | * We actually lost the connection ... or did we? | 2012 | * We actually lost the connection ... or did we? |
1878 | * Let's make sure! | 2013 | * Let's make sure! |
1879 | */ | 2014 | */ |
1880 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1881 | IEEE80211_STA_BEACON_POLL); | ||
1882 | wiphy_debug(local->hw.wiphy, | 2015 | wiphy_debug(local->hw.wiphy, |
1883 | "%s: No probe response from AP %pM" | 2016 | "%s: No probe response from AP %pM" |
1884 | " after %dms, disconnecting.\n", | 2017 | " after %dms, disconnecting.\n", |
1885 | sdata->name, | 2018 | sdata->name, |
1886 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2019 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
1887 | ieee80211_set_disassoc(sdata, true, true); | 2020 | |
1888 | mutex_unlock(&ifmgd->mtx); | 2021 | ieee80211_sta_connection_lost(sdata, bssid); |
1889 | mutex_lock(&local->mtx); | ||
1890 | ieee80211_recalc_idle(local); | ||
1891 | mutex_unlock(&local->mtx); | ||
1892 | /* | ||
1893 | * must be outside lock due to cfg80211, | ||
1894 | * but that's not a problem. | ||
1895 | */ | ||
1896 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
1897 | IEEE80211_STYPE_DEAUTH, | ||
1898 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
1899 | NULL, true); | ||
1900 | mutex_lock(&ifmgd->mtx); | ||
1901 | } | 2022 | } |
1902 | } | 2023 | } |
1903 | 2024 | ||
@@ -1988,6 +2109,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
1988 | add_timer(&ifmgd->timer); | 2109 | add_timer(&ifmgd->timer); |
1989 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | 2110 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) |
1990 | add_timer(&ifmgd->chswitch_timer); | 2111 | add_timer(&ifmgd->chswitch_timer); |
2112 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
2113 | ieee80211_restart_sta_timer(sdata); | ||
1991 | } | 2114 | } |
1992 | #endif | 2115 | #endif |
1993 | 2116 | ||
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 33f76993da08..3d5a2cb835c4 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -211,7 +211,8 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) | |||
211 | return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc); | 211 | return (info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc); |
212 | } | 212 | } |
213 | 213 | ||
214 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) | 214 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, |
215 | struct ieee80211_supported_band *sband) | ||
215 | { | 216 | { |
216 | u8 i; | 217 | u8 i; |
217 | 218 | ||
@@ -222,7 +223,7 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) | |||
222 | if (basic_rates & (1 << *idx)) | 223 | if (basic_rates & (1 << *idx)) |
223 | return; /* selected rate is a basic rate */ | 224 | return; /* selected rate is a basic rate */ |
224 | 225 | ||
225 | for (i = *idx + 1; i <= max_rate_idx; i++) { | 226 | for (i = *idx + 1; i <= sband->n_bitrates; i++) { |
226 | if (basic_rates & (1 << i)) { | 227 | if (basic_rates & (1 << i)) { |
227 | *idx = i; | 228 | *idx = i; |
228 | return; | 229 | return; |
@@ -237,16 +238,25 @@ bool rate_control_send_low(struct ieee80211_sta *sta, | |||
237 | struct ieee80211_tx_rate_control *txrc) | 238 | struct ieee80211_tx_rate_control *txrc) |
238 | { | 239 | { |
239 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); | 240 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
241 | struct ieee80211_supported_band *sband = txrc->sband; | ||
242 | int mcast_rate; | ||
240 | 243 | ||
241 | if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) { | 244 | if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) { |
242 | info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta); | 245 | info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta); |
243 | info->control.rates[0].count = | 246 | info->control.rates[0].count = |
244 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | 247 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? |
245 | 1 : txrc->hw->max_rate_tries; | 248 | 1 : txrc->hw->max_rate_tries; |
246 | if (!sta && txrc->ap) | 249 | if (!sta && txrc->bss) { |
250 | mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; | ||
251 | if (mcast_rate > 0) { | ||
252 | info->control.rates[0].idx = mcast_rate - 1; | ||
253 | return true; | ||
254 | } | ||
255 | |||
247 | rc_send_low_broadcast(&info->control.rates[0].idx, | 256 | rc_send_low_broadcast(&info->control.rates[0].idx, |
248 | txrc->bss_conf->basic_rates, | 257 | txrc->bss_conf->basic_rates, |
249 | txrc->sband->n_bitrates); | 258 | sband); |
259 | } | ||
250 | return true; | 260 | return true; |
251 | } | 261 | } |
252 | return false; | 262 | return false; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 2a18d6602d4a..165a4518bb48 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -371,7 +371,10 @@ minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, stru | |||
371 | if (likely(sta->ampdu_mlme.tid_tx[tid])) | 371 | if (likely(sta->ampdu_mlme.tid_tx[tid])) |
372 | return; | 372 | return; |
373 | 373 | ||
374 | ieee80211_start_tx_ba_session(pubsta, tid); | 374 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) |
375 | return; | ||
376 | |||
377 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); | ||
375 | } | 378 | } |
376 | 379 | ||
377 | static void | 380 | static void |
@@ -407,8 +410,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
407 | mi->ampdu_len += info->status.ampdu_len; | 410 | mi->ampdu_len += info->status.ampdu_len; |
408 | 411 | ||
409 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { | 412 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { |
410 | mi->sample_wait = 4 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); | 413 | mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); |
411 | mi->sample_tries = 3; | 414 | mi->sample_tries = 2; |
412 | mi->sample_count--; | 415 | mi->sample_count--; |
413 | } | 416 | } |
414 | 417 | ||
@@ -506,7 +509,9 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
506 | if (!mr->retry_updated) | 509 | if (!mr->retry_updated) |
507 | minstrel_calc_retransmit(mp, mi, index); | 510 | minstrel_calc_retransmit(mp, mi, index); |
508 | 511 | ||
509 | if (mr->probability < MINSTREL_FRAC(20, 100)) | 512 | if (sample) |
513 | rate->count = 1; | ||
514 | else if (mr->probability < MINSTREL_FRAC(20, 100)) | ||
510 | rate->count = 2; | 515 | rate->count = 2; |
511 | else if (rtscts) | 516 | else if (rtscts) |
512 | rate->count = mr->retry_count_rtscts; | 517 | rate->count = mr->retry_count_rtscts; |
@@ -562,7 +567,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
562 | */ | 567 | */ |
563 | if (minstrel_get_duration(sample_idx) > | 568 | if (minstrel_get_duration(sample_idx) > |
564 | minstrel_get_duration(mi->max_tp_rate)) { | 569 | minstrel_get_duration(mi->max_tp_rate)) { |
565 | if (mr->sample_skipped < 10) | 570 | if (mr->sample_skipped < 20) |
566 | goto next; | 571 | goto next; |
567 | 572 | ||
568 | if (mi->sample_slow++ > 2) | 573 | if (mi->sample_slow++ > 2) |
@@ -586,6 +591,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
586 | struct minstrel_ht_sta *mi = &msp->ht; | 591 | struct minstrel_ht_sta *mi = &msp->ht; |
587 | struct minstrel_priv *mp = priv; | 592 | struct minstrel_priv *mp = priv; |
588 | int sample_idx; | 593 | int sample_idx; |
594 | bool sample = false; | ||
589 | 595 | ||
590 | if (rate_control_send_low(sta, priv_sta, txrc)) | 596 | if (rate_control_send_low(sta, priv_sta, txrc)) |
591 | return; | 597 | return; |
@@ -596,10 +602,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
596 | info->flags |= mi->tx_flags; | 602 | info->flags |= mi->tx_flags; |
597 | sample_idx = minstrel_get_sample_rate(mp, mi); | 603 | sample_idx = minstrel_get_sample_rate(mp, mi); |
598 | if (sample_idx >= 0) { | 604 | if (sample_idx >= 0) { |
605 | sample = true; | ||
599 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, | 606 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, |
600 | txrc, true, false); | 607 | txrc, true, false); |
601 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, | 608 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, |
602 | txrc, false, true); | 609 | txrc, false, false); |
603 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 610 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
604 | } else { | 611 | } else { |
605 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, | 612 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, |
@@ -607,7 +614,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
607 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, | 614 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, |
608 | txrc, false, true); | 615 | txrc, false, true); |
609 | } | 616 | } |
610 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true); | 617 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, !sample); |
611 | 618 | ||
612 | ar[3].count = 0; | 619 | ar[3].count = 0; |
613 | ar[3].idx = -1; | 620 | ar[3].idx = -1; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b01e467b76c6..5e9d3bc6a2d9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -538,6 +538,8 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, | |||
538 | { | 538 | { |
539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; | 539 | struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; |
540 | 540 | ||
541 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | ||
542 | |||
541 | if (!skb) | 543 | if (!skb) |
542 | goto no_frame; | 544 | goto no_frame; |
543 | 545 | ||
@@ -557,6 +559,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, | |||
557 | { | 559 | { |
558 | int index; | 560 | int index; |
559 | 561 | ||
562 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | ||
563 | |||
560 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 564 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
561 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 565 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
562 | tid_agg_rx->buf_size; | 566 | tid_agg_rx->buf_size; |
@@ -581,6 +585,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, | |||
581 | { | 585 | { |
582 | int index, j; | 586 | int index, j; |
583 | 587 | ||
588 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | ||
589 | |||
584 | /* release the buffer until next missing frame */ | 590 | /* release the buffer until next missing frame */ |
585 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 591 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % |
586 | tid_agg_rx->buf_size; | 592 | tid_agg_rx->buf_size; |
@@ -683,10 +689,11 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, | |||
683 | int index; | 689 | int index; |
684 | bool ret = true; | 690 | bool ret = true; |
685 | 691 | ||
692 | spin_lock(&tid_agg_rx->reorder_lock); | ||
693 | |||
686 | buf_size = tid_agg_rx->buf_size; | 694 | buf_size = tid_agg_rx->buf_size; |
687 | head_seq_num = tid_agg_rx->head_seq_num; | 695 | head_seq_num = tid_agg_rx->head_seq_num; |
688 | 696 | ||
689 | spin_lock(&tid_agg_rx->reorder_lock); | ||
690 | /* frame with out of date sequence number */ | 697 | /* frame with out of date sequence number */ |
691 | if (seq_less(mpdu_seq_num, head_seq_num)) { | 698 | if (seq_less(mpdu_seq_num, head_seq_num)) { |
692 | dev_kfree_skb(skb); | 699 | dev_kfree_skb(skb); |
@@ -948,12 +955,31 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
948 | * have been expected. | 955 | * have been expected. |
949 | */ | 956 | */ |
950 | struct ieee80211_key *key = NULL; | 957 | struct ieee80211_key *key = NULL; |
958 | struct ieee80211_sub_if_data *sdata = rx->sdata; | ||
959 | int i; | ||
960 | |||
951 | if (ieee80211_is_mgmt(fc) && | 961 | if (ieee80211_is_mgmt(fc) && |
952 | is_multicast_ether_addr(hdr->addr1) && | 962 | is_multicast_ether_addr(hdr->addr1) && |
953 | (key = rcu_dereference(rx->sdata->default_mgmt_key))) | 963 | (key = rcu_dereference(rx->sdata->default_mgmt_key))) |
954 | rx->key = key; | 964 | rx->key = key; |
955 | else if ((key = rcu_dereference(rx->sdata->default_key))) | 965 | else { |
956 | rx->key = key; | 966 | if (rx->sta) { |
967 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
968 | key = rcu_dereference(rx->sta->gtk[i]); | ||
969 | if (key) | ||
970 | break; | ||
971 | } | ||
972 | } | ||
973 | if (!key) { | ||
974 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { | ||
975 | key = rcu_dereference(sdata->keys[i]); | ||
976 | if (key) | ||
977 | break; | ||
978 | } | ||
979 | } | ||
980 | if (key) | ||
981 | rx->key = key; | ||
982 | } | ||
957 | return RX_CONTINUE; | 983 | return RX_CONTINUE; |
958 | } else { | 984 | } else { |
959 | u8 keyid; | 985 | u8 keyid; |
@@ -1102,8 +1128,6 @@ static void ap_sta_ps_end(struct sta_info *sta) | |||
1102 | 1128 | ||
1103 | atomic_dec(&sdata->bss->num_sta_ps); | 1129 | atomic_dec(&sdata->bss->num_sta_ps); |
1104 | 1130 | ||
1105 | clear_sta_flags(sta, WLAN_STA_PS_STA); | ||
1106 | |||
1107 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1131 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1108 | printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", | 1132 | printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", |
1109 | sdata->name, sta->sta.addr, sta->sta.aid); | 1133 | sdata->name, sta->sta.addr, sta->sta.aid); |
@@ -1158,6 +1182,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1158 | sta->rx_fragments++; | 1182 | sta->rx_fragments++; |
1159 | sta->rx_bytes += rx->skb->len; | 1183 | sta->rx_bytes += rx->skb->len; |
1160 | sta->last_signal = status->signal; | 1184 | sta->last_signal = status->signal; |
1185 | ewma_add(&sta->avg_signal, -status->signal); | ||
1161 | 1186 | ||
1162 | /* | 1187 | /* |
1163 | * Change STA power saving mode only at the end of a frame | 1188 | * Change STA power saving mode only at the end of a frame |
@@ -1515,12 +1540,30 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | |||
1515 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { | 1540 | if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { |
1516 | if (unlikely(!ieee80211_has_protected(fc) && | 1541 | if (unlikely(!ieee80211_has_protected(fc) && |
1517 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | 1542 | ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && |
1518 | rx->key)) | 1543 | rx->key)) { |
1544 | if (ieee80211_is_deauth(fc)) | ||
1545 | cfg80211_send_unprot_deauth(rx->sdata->dev, | ||
1546 | rx->skb->data, | ||
1547 | rx->skb->len); | ||
1548 | else if (ieee80211_is_disassoc(fc)) | ||
1549 | cfg80211_send_unprot_disassoc(rx->sdata->dev, | ||
1550 | rx->skb->data, | ||
1551 | rx->skb->len); | ||
1519 | return -EACCES; | 1552 | return -EACCES; |
1553 | } | ||
1520 | /* BIP does not use Protected field, so need to check MMIE */ | 1554 | /* BIP does not use Protected field, so need to check MMIE */ |
1521 | if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && | 1555 | if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && |
1522 | ieee80211_get_mmie_keyidx(rx->skb) < 0)) | 1556 | ieee80211_get_mmie_keyidx(rx->skb) < 0)) { |
1557 | if (ieee80211_is_deauth(fc)) | ||
1558 | cfg80211_send_unprot_deauth(rx->sdata->dev, | ||
1559 | rx->skb->data, | ||
1560 | rx->skb->len); | ||
1561 | else if (ieee80211_is_disassoc(fc)) | ||
1562 | cfg80211_send_unprot_disassoc(rx->sdata->dev, | ||
1563 | rx->skb->data, | ||
1564 | rx->skb->len); | ||
1523 | return -EACCES; | 1565 | return -EACCES; |
1566 | } | ||
1524 | /* | 1567 | /* |
1525 | * When using MFP, Action frames are not allowed prior to | 1568 | * When using MFP, Action frames are not allowed prior to |
1526 | * having configured keys. | 1569 | * having configured keys. |
@@ -1875,9 +1918,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1875 | dev->stats.rx_packets++; | 1918 | dev->stats.rx_packets++; |
1876 | dev->stats.rx_bytes += rx->skb->len; | 1919 | dev->stats.rx_bytes += rx->skb->len; |
1877 | 1920 | ||
1878 | if (ieee80211_is_data(hdr->frame_control) && | 1921 | if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && |
1879 | !is_multicast_ether_addr(hdr->addr1) && | 1922 | !is_multicast_ether_addr(((struct ethhdr *)rx->skb->data)->h_dest)) { |
1880 | local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { | ||
1881 | mod_timer(&local->dynamic_ps_timer, jiffies + | 1923 | mod_timer(&local->dynamic_ps_timer, jiffies + |
1882 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | 1924 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); |
1883 | } | 1925 | } |
@@ -1926,9 +1968,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) | |||
1926 | mod_timer(&tid_agg_rx->session_timer, | 1968 | mod_timer(&tid_agg_rx->session_timer, |
1927 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); | 1969 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); |
1928 | 1970 | ||
1971 | spin_lock(&tid_agg_rx->reorder_lock); | ||
1929 | /* release stored frames up to start of BAR */ | 1972 | /* release stored frames up to start of BAR */ |
1930 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, | 1973 | ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num, |
1931 | frames); | 1974 | frames); |
1975 | spin_unlock(&tid_agg_rx->reorder_lock); | ||
1976 | |||
1932 | kfree_skb(skb); | 1977 | kfree_skb(skb); |
1933 | return RX_QUEUED; | 1978 | return RX_QUEUED; |
1934 | } | 1979 | } |
@@ -2119,10 +2164,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2119 | } | 2164 | } |
2120 | break; | 2165 | break; |
2121 | case WLAN_CATEGORY_MESH_PLINK: | 2166 | case WLAN_CATEGORY_MESH_PLINK: |
2122 | case WLAN_CATEGORY_MESH_PATH_SEL: | ||
2123 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2167 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2124 | break; | 2168 | break; |
2125 | goto queue; | 2169 | goto queue; |
2170 | case WLAN_CATEGORY_MESH_PATH_SEL: | ||
2171 | if (!mesh_path_sel_is_hwmp(sdata)) | ||
2172 | break; | ||
2173 | goto queue; | ||
2126 | } | 2174 | } |
2127 | 2175 | ||
2128 | return RX_CONTINUE; | 2176 | return RX_CONTINUE; |
@@ -2524,9 +2572,8 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
2524 | } | 2572 | } |
2525 | 2573 | ||
2526 | /* | 2574 | /* |
2527 | * This function makes calls into the RX path. Therefore the | 2575 | * This function makes calls into the RX path, therefore |
2528 | * caller must hold the sta_info->lock and everything has to | 2576 | * it has to be invoked under RCU read lock. |
2529 | * be under rcu_read_lock protection as well. | ||
2530 | */ | 2577 | */ |
2531 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) | 2578 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) |
2532 | { | 2579 | { |
@@ -2884,6 +2931,9 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2884 | return; | 2931 | return; |
2885 | } | 2932 | } |
2886 | 2933 | ||
2934 | ieee80211_tpt_led_trig_rx(local, | ||
2935 | ((struct ieee80211_hdr *)skb->data)->frame_control, | ||
2936 | skb->len); | ||
2887 | __ieee80211_rx_handle_packet(hw, skb); | 2937 | __ieee80211_rx_handle_packet(hw, skb); |
2888 | 2938 | ||
2889 | rcu_read_unlock(); | 2939 | rcu_read_unlock(); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 6d8f897d8763..c426504ed1cf 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -199,8 +199,11 @@ static void sta_unblock(struct work_struct *wk) | |||
199 | 199 | ||
200 | if (!test_sta_flags(sta, WLAN_STA_PS_STA)) | 200 | if (!test_sta_flags(sta, WLAN_STA_PS_STA)) |
201 | ieee80211_sta_ps_deliver_wakeup(sta); | 201 | ieee80211_sta_ps_deliver_wakeup(sta); |
202 | else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) | 202 | else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { |
203 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER); | ||
203 | ieee80211_sta_ps_deliver_poll_response(sta); | 204 | ieee80211_sta_ps_deliver_poll_response(sta); |
205 | } else | ||
206 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER); | ||
204 | } | 207 | } |
205 | 208 | ||
206 | static int sta_prepare_rate_control(struct ieee80211_local *local, | 209 | static int sta_prepare_rate_control(struct ieee80211_local *local, |
@@ -241,6 +244,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
241 | sta->local = local; | 244 | sta->local = local; |
242 | sta->sdata = sdata; | 245 | sta->sdata = sdata; |
243 | 246 | ||
247 | ewma_init(&sta->avg_signal, 1024, 8); | ||
248 | |||
244 | if (sta_prepare_rate_control(local, sta, gfp)) { | 249 | if (sta_prepare_rate_control(local, sta, gfp)) { |
245 | kfree(sta); | 250 | kfree(sta); |
246 | return NULL; | 251 | return NULL; |
@@ -880,6 +885,13 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, | |||
880 | } | 885 | } |
881 | EXPORT_SYMBOL(ieee80211_find_sta); | 886 | EXPORT_SYMBOL(ieee80211_find_sta); |
882 | 887 | ||
888 | static void clear_sta_ps_flags(void *_sta) | ||
889 | { | ||
890 | struct sta_info *sta = _sta; | ||
891 | |||
892 | clear_sta_flags(sta, WLAN_STA_PS_DRIVER | WLAN_STA_PS_STA); | ||
893 | } | ||
894 | |||
883 | /* powersave support code */ | 895 | /* powersave support code */ |
884 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | 896 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) |
885 | { | 897 | { |
@@ -894,7 +906,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
894 | 906 | ||
895 | /* Send all buffered frames to the station */ | 907 | /* Send all buffered frames to the station */ |
896 | sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); | 908 | sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered); |
897 | buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf); | 909 | buffered = ieee80211_add_pending_skbs_fn(local, &sta->ps_tx_buf, |
910 | clear_sta_ps_flags, sta); | ||
898 | sent += buffered; | 911 | sent += buffered; |
899 | local->total_ps_buffered -= buffered; | 912 | local->total_ps_buffered -= buffered; |
900 | 913 | ||
@@ -973,7 +986,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
973 | 986 | ||
974 | if (block) | 987 | if (block) |
975 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); | 988 | set_sta_flags(sta, WLAN_STA_PS_DRIVER); |
976 | else | 989 | else if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) |
977 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 990 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); |
978 | } | 991 | } |
979 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 992 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9265acadef32..bbdd2a86a94b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/if_ether.h> | 14 | #include <linux/if_ether.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/average.h> | ||
16 | #include "key.h" | 17 | #include "key.h" |
17 | 18 | ||
18 | /** | 19 | /** |
@@ -77,23 +78,26 @@ enum ieee80211_sta_info_flags { | |||
77 | * @addba_resp_timer: timer for peer's response to addba request | 78 | * @addba_resp_timer: timer for peer's response to addba request |
78 | * @pending: pending frames queue -- use sta's spinlock to protect | 79 | * @pending: pending frames queue -- use sta's spinlock to protect |
79 | * @dialog_token: dialog token for aggregation session | 80 | * @dialog_token: dialog token for aggregation session |
81 | * @timeout: session timeout value to be filled in ADDBA requests | ||
80 | * @state: session state (see above) | 82 | * @state: session state (see above) |
81 | * @stop_initiator: initiator of a session stop | 83 | * @stop_initiator: initiator of a session stop |
82 | * @tx_stop: TX DelBA frame when stopping | 84 | * @tx_stop: TX DelBA frame when stopping |
83 | * | 85 | * |
84 | * This structure is protected by RCU and the per-station | 86 | * This structure's lifetime is managed by RCU, assignments to |
85 | * spinlock. Assignments to the array holding it must hold | 87 | * the array holding it must hold the aggregation mutex. |
86 | * the spinlock, only the TX path can access it under RCU | 88 | * |
87 | * lock-free if, and only if, the state has the flag | 89 | * The TX path can access it under RCU lock-free if, and |
88 | * %HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path | 90 | * only if, the state has the flag %HT_AGG_STATE_OPERATIONAL |
89 | * must also acquire the spinlock and re-check the state, | 91 | * set. Otherwise, the TX path must also acquire the spinlock |
90 | * see comments in the tx code touching it. | 92 | * and re-check the state, see comments in the tx code |
93 | * touching it. | ||
91 | */ | 94 | */ |
92 | struct tid_ampdu_tx { | 95 | struct tid_ampdu_tx { |
93 | struct rcu_head rcu_head; | 96 | struct rcu_head rcu_head; |
94 | struct timer_list addba_resp_timer; | 97 | struct timer_list addba_resp_timer; |
95 | struct sk_buff_head pending; | 98 | struct sk_buff_head pending; |
96 | unsigned long state; | 99 | unsigned long state; |
100 | u16 timeout; | ||
97 | u8 dialog_token; | 101 | u8 dialog_token; |
98 | u8 stop_initiator; | 102 | u8 stop_initiator; |
99 | bool tx_stop; | 103 | bool tx_stop; |
@@ -115,15 +119,13 @@ struct tid_ampdu_tx { | |||
115 | * @rcu_head: RCU head used for freeing this struct | 119 | * @rcu_head: RCU head used for freeing this struct |
116 | * @reorder_lock: serializes access to reorder buffer, see below. | 120 | * @reorder_lock: serializes access to reorder buffer, see below. |
117 | * | 121 | * |
118 | * This structure is protected by RCU and the per-station | 122 | * This structure's lifetime is managed by RCU, assignments to |
119 | * spinlock. Assignments to the array holding it must hold | 123 | * the array holding it must hold the aggregation mutex. |
120 | * the spinlock. | ||
121 | * | 124 | * |
122 | * The @reorder_lock is used to protect the variables and | 125 | * The @reorder_lock is used to protect the members of this |
123 | * arrays such as @reorder_buf, @reorder_time, @head_seq_num, | 126 | * struct, except for @timeout, @buf_size and @dialog_token, |
124 | * @stored_mpdu_num and @reorder_time from being corrupted by | 127 | * which are constant across the lifetime of the struct (the |
125 | * concurrent access of the RX path and the expired frame | 128 | * dialog token being used only for debugging). |
126 | * release timer. | ||
127 | */ | 129 | */ |
128 | struct tid_ampdu_rx { | 130 | struct tid_ampdu_rx { |
129 | struct rcu_head rcu_head; | 131 | struct rcu_head rcu_head; |
@@ -224,6 +226,7 @@ enum plink_state { | |||
224 | * @rx_fragments: number of received MPDUs | 226 | * @rx_fragments: number of received MPDUs |
225 | * @rx_dropped: number of dropped MPDUs from this STA | 227 | * @rx_dropped: number of dropped MPDUs from this STA |
226 | * @last_signal: signal of last received frame from this STA | 228 | * @last_signal: signal of last received frame from this STA |
229 | * @avg_signal: moving average of signal of received frames from this STA | ||
227 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) | 230 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) |
228 | * @tx_filtered_count: number of frames the hardware filtered for this STA | 231 | * @tx_filtered_count: number of frames the hardware filtered for this STA |
229 | * @tx_retry_failed: number of frames that failed retry | 232 | * @tx_retry_failed: number of frames that failed retry |
@@ -248,6 +251,7 @@ enum plink_state { | |||
248 | * @sta: station information we share with the driver | 251 | * @sta: station information we share with the driver |
249 | * @dead: set to true when sta is unlinked | 252 | * @dead: set to true when sta is unlinked |
250 | * @uploaded: set to true when sta is uploaded to the driver | 253 | * @uploaded: set to true when sta is uploaded to the driver |
254 | * @lost_packets: number of consecutive lost packets | ||
251 | */ | 255 | */ |
252 | struct sta_info { | 256 | struct sta_info { |
253 | /* General information, mostly static */ | 257 | /* General information, mostly static */ |
@@ -291,6 +295,7 @@ struct sta_info { | |||
291 | unsigned long rx_fragments; | 295 | unsigned long rx_fragments; |
292 | unsigned long rx_dropped; | 296 | unsigned long rx_dropped; |
293 | int last_signal; | 297 | int last_signal; |
298 | struct ewma avg_signal; | ||
294 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; | 299 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; |
295 | 300 | ||
296 | /* Updated from TX status path only, no locking requirements */ | 301 | /* Updated from TX status path only, no locking requirements */ |
@@ -335,6 +340,8 @@ struct sta_info { | |||
335 | } debugfs; | 340 | } debugfs; |
336 | #endif | 341 | #endif |
337 | 342 | ||
343 | unsigned int lost_packets; | ||
344 | |||
338 | /* keep last! */ | 345 | /* keep last! */ |
339 | struct ieee80211_sta sta; | 346 | struct ieee80211_sta sta; |
340 | }; | 347 | }; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3153c19893b8..38a797217a91 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -157,6 +157,15 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) | |||
157 | } | 157 | } |
158 | } | 158 | } |
159 | 159 | ||
160 | /* | ||
161 | * Use a static threshold for now, best value to be determined | ||
162 | * by testing ... | ||
163 | * Should it depend on: | ||
164 | * - on # of retransmissions | ||
165 | * - current throughput (higher value for higher tpt)? | ||
166 | */ | ||
167 | #define STA_LOST_PKT_THRESHOLD 50 | ||
168 | |||
160 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | 169 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) |
161 | { | 170 | { |
162 | struct sk_buff *skb2; | 171 | struct sk_buff *skb2; |
@@ -173,6 +182,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
173 | int retry_count = -1, i; | 182 | int retry_count = -1, i; |
174 | int rates_idx = -1; | 183 | int rates_idx = -1; |
175 | bool send_to_cooked; | 184 | bool send_to_cooked; |
185 | bool acked; | ||
176 | 186 | ||
177 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 187 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
178 | /* the HW cannot have attempted that rate */ | 188 | /* the HW cannot have attempted that rate */ |
@@ -198,8 +208,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
198 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) | 208 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) |
199 | continue; | 209 | continue; |
200 | 210 | ||
201 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 211 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); |
202 | test_sta_flags(sta, WLAN_STA_PS_STA)) { | 212 | if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) { |
203 | /* | 213 | /* |
204 | * The STA is in power save mode, so assume | 214 | * The STA is in power save mode, so assume |
205 | * that this TX packet failed because of that. | 215 | * that this TX packet failed because of that. |
@@ -231,7 +241,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
231 | rcu_read_unlock(); | 241 | rcu_read_unlock(); |
232 | return; | 242 | return; |
233 | } else { | 243 | } else { |
234 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) | 244 | if (!acked) |
235 | sta->tx_retry_failed++; | 245 | sta->tx_retry_failed++; |
236 | sta->tx_retry_count += retry_count; | 246 | sta->tx_retry_count += retry_count; |
237 | } | 247 | } |
@@ -240,9 +250,25 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
240 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 250 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
241 | ieee80211s_update_metric(local, sta, skb); | 251 | ieee80211s_update_metric(local, sta, skb); |
242 | 252 | ||
243 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && | 253 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) |
244 | (info->flags & IEEE80211_TX_STAT_ACK)) | ||
245 | ieee80211_frame_acked(sta, skb); | 254 | ieee80211_frame_acked(sta, skb); |
255 | |||
256 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && | ||
257 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | ||
258 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); | ||
259 | |||
260 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
261 | if (info->flags & IEEE80211_TX_STAT_ACK) { | ||
262 | if (sta->lost_packets) | ||
263 | sta->lost_packets = 0; | ||
264 | } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) { | ||
265 | cfg80211_cqm_pktloss_notify(sta->sdata->dev, | ||
266 | sta->sta.addr, | ||
267 | sta->lost_packets, | ||
268 | GFP_ATOMIC); | ||
269 | sta->lost_packets = 0; | ||
270 | } | ||
271 | } | ||
246 | } | 272 | } |
247 | 273 | ||
248 | rcu_read_unlock(); | 274 | rcu_read_unlock(); |
@@ -295,10 +321,23 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
295 | msecs_to_jiffies(10)); | 321 | msecs_to_jiffies(10)); |
296 | } | 322 | } |
297 | 323 | ||
298 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) | 324 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { |
325 | struct ieee80211_work *wk; | ||
326 | |||
327 | rcu_read_lock(); | ||
328 | list_for_each_entry_rcu(wk, &local->work_list, list) { | ||
329 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) | ||
330 | continue; | ||
331 | if (wk->offchan_tx.frame != skb) | ||
332 | continue; | ||
333 | wk->offchan_tx.frame = NULL; | ||
334 | break; | ||
335 | } | ||
336 | rcu_read_unlock(); | ||
299 | cfg80211_mgmt_tx_status( | 337 | cfg80211_mgmt_tx_status( |
300 | skb->dev, (unsigned long) skb, skb->data, skb->len, | 338 | skb->dev, (unsigned long) skb, skb->data, skb->len, |
301 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); | 339 | !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); |
340 | } | ||
302 | 341 | ||
303 | /* this was a transmitted frame, but now we want to reuse it */ | 342 | /* this was a transmitted frame, but now we want to reuse it */ |
304 | skb_orphan(skb); | 343 | skb_orphan(skb); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7a637b80a62e..68c2fbd16ebb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -539,7 +539,11 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
539 | ieee80211_is_robust_mgmt_frame(hdr) && | 539 | ieee80211_is_robust_mgmt_frame(hdr) && |
540 | (key = rcu_dereference(tx->sdata->default_mgmt_key))) | 540 | (key = rcu_dereference(tx->sdata->default_mgmt_key))) |
541 | tx->key = key; | 541 | tx->key = key; |
542 | else if ((key = rcu_dereference(tx->sdata->default_key))) | 542 | else if (is_multicast_ether_addr(hdr->addr1) && |
543 | (key = rcu_dereference(tx->sdata->default_multicast_key))) | ||
544 | tx->key = key; | ||
545 | else if (!is_multicast_ether_addr(hdr->addr1) && | ||
546 | (key = rcu_dereference(tx->sdata->default_unicast_key))) | ||
543 | tx->key = key; | 547 | tx->key = key; |
544 | else if (tx->sdata->drop_unencrypted && | 548 | else if (tx->sdata->drop_unencrypted && |
545 | (tx->skb->protocol != tx->sdata->control_port_protocol) && | 549 | (tx->skb->protocol != tx->sdata->control_port_protocol) && |
@@ -622,7 +626,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
622 | txrc.max_rate_idx = -1; | 626 | txrc.max_rate_idx = -1; |
623 | else | 627 | else |
624 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | 628 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; |
625 | txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; | 629 | txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP || |
630 | tx->sdata->vif.type == NL80211_IFTYPE_ADHOC); | ||
626 | 631 | ||
627 | /* set up RTS protection if desired */ | 632 | /* set up RTS protection if desired */ |
628 | if (len > tx->local->hw.wiphy->rts_threshold) { | 633 | if (len > tx->local->hw.wiphy->rts_threshold) { |
@@ -665,10 +670,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
665 | if (unlikely(info->control.rates[0].idx < 0)) | 670 | if (unlikely(info->control.rates[0].idx < 0)) |
666 | return TX_DROP; | 671 | return TX_DROP; |
667 | 672 | ||
668 | if (txrc.reported_rate.idx < 0) | 673 | if (txrc.reported_rate.idx < 0) { |
669 | txrc.reported_rate = info->control.rates[0]; | 674 | txrc.reported_rate = info->control.rates[0]; |
670 | 675 | if (tx->sta && ieee80211_is_data(hdr->frame_control)) | |
671 | if (tx->sta) | 676 | tx->sta->last_tx_rate = txrc.reported_rate; |
677 | } else if (tx->sta) | ||
672 | tx->sta->last_tx_rate = txrc.reported_rate; | 678 | tx->sta->last_tx_rate = txrc.reported_rate; |
673 | 679 | ||
674 | if (unlikely(!info->control.rates[0].count)) | 680 | if (unlikely(!info->control.rates[0].count)) |
@@ -1033,6 +1039,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1033 | struct ieee80211_radiotap_header *rthdr = | 1039 | struct ieee80211_radiotap_header *rthdr = |
1034 | (struct ieee80211_radiotap_header *) skb->data; | 1040 | (struct ieee80211_radiotap_header *) skb->data; |
1035 | struct ieee80211_supported_band *sband; | 1041 | struct ieee80211_supported_band *sband; |
1042 | bool hw_frag; | ||
1036 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1043 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1037 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, | 1044 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1038 | NULL); | 1045 | NULL); |
@@ -1042,6 +1049,9 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1042 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1049 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1043 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; | 1050 | tx->flags &= ~IEEE80211_TX_FRAGMENTED; |
1044 | 1051 | ||
1052 | /* packet is fragmented in HW if we have a non-NULL driver callback */ | ||
1053 | hw_frag = (tx->local->ops->set_frag_threshold != NULL); | ||
1054 | |||
1045 | /* | 1055 | /* |
1046 | * for every radiotap entry that is present | 1056 | * for every radiotap entry that is present |
1047 | * (ieee80211_radiotap_iterator_next returns -ENOENT when no more | 1057 | * (ieee80211_radiotap_iterator_next returns -ENOENT when no more |
@@ -1078,7 +1088,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1078 | } | 1088 | } |
1079 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) | 1089 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) |
1080 | info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1090 | info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1081 | if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) | 1091 | if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) && |
1092 | !hw_frag) | ||
1082 | tx->flags |= IEEE80211_TX_FRAGMENTED; | 1093 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
1083 | break; | 1094 | break; |
1084 | 1095 | ||
@@ -1181,8 +1192,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1181 | /* | 1192 | /* |
1182 | * Set this flag (used below to indicate "automatic fragmentation"), | 1193 | * Set this flag (used below to indicate "automatic fragmentation"), |
1183 | * it will be cleared/left by radiotap as desired. | 1194 | * it will be cleared/left by radiotap as desired. |
1195 | * Only valid when fragmentation is done by the stack. | ||
1184 | */ | 1196 | */ |
1185 | tx->flags |= IEEE80211_TX_FRAGMENTED; | 1197 | if (!local->ops->set_frag_threshold) |
1198 | tx->flags |= IEEE80211_TX_FRAGMENTED; | ||
1186 | 1199 | ||
1187 | /* process and remove the injection radiotap header */ | 1200 | /* process and remove the injection radiotap header */ |
1188 | if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { | 1201 | if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { |
@@ -1284,6 +1297,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1284 | 1297 | ||
1285 | while (skb) { | 1298 | while (skb) { |
1286 | int q = skb_get_queue_mapping(skb); | 1299 | int q = skb_get_queue_mapping(skb); |
1300 | __le16 fc; | ||
1287 | 1301 | ||
1288 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1302 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1289 | ret = IEEE80211_TX_OK; | 1303 | ret = IEEE80211_TX_OK; |
@@ -1326,6 +1340,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1326 | else | 1340 | else |
1327 | info->control.sta = NULL; | 1341 | info->control.sta = NULL; |
1328 | 1342 | ||
1343 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | ||
1329 | ret = drv_tx(local, skb); | 1344 | ret = drv_tx(local, skb); |
1330 | if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { | 1345 | if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { |
1331 | dev_kfree_skb(skb); | 1346 | dev_kfree_skb(skb); |
@@ -1336,6 +1351,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1336 | return IEEE80211_TX_AGAIN; | 1351 | return IEEE80211_TX_AGAIN; |
1337 | } | 1352 | } |
1338 | 1353 | ||
1354 | ieee80211_tpt_led_trig_tx(local, fc, len); | ||
1339 | *skbp = skb = next; | 1355 | *skbp = skb = next; |
1340 | ieee80211_led_tx(local, 1); | 1356 | ieee80211_led_tx(local, 1); |
1341 | fragm = true; | 1357 | fragm = true; |
@@ -1533,8 +1549,10 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, | |||
1533 | 1549 | ||
1534 | if (skb_header_cloned(skb)) | 1550 | if (skb_header_cloned(skb)) |
1535 | I802_DEBUG_INC(local->tx_expand_skb_head_cloned); | 1551 | I802_DEBUG_INC(local->tx_expand_skb_head_cloned); |
1536 | else | 1552 | else if (head_need || tail_need) |
1537 | I802_DEBUG_INC(local->tx_expand_skb_head); | 1553 | I802_DEBUG_INC(local->tx_expand_skb_head); |
1554 | else | ||
1555 | return 0; | ||
1538 | 1556 | ||
1539 | if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { | 1557 | if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { |
1540 | wiphy_debug(local->hw.wiphy, | 1558 | wiphy_debug(local->hw.wiphy, |
@@ -1726,7 +1744,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1726 | { | 1744 | { |
1727 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1745 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1728 | struct ieee80211_local *local = sdata->local; | 1746 | struct ieee80211_local *local = sdata->local; |
1729 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1747 | struct ieee80211_tx_info *info; |
1730 | int ret = NETDEV_TX_BUSY, head_need; | 1748 | int ret = NETDEV_TX_BUSY, head_need; |
1731 | u16 ethertype, hdrlen, meshhdrlen = 0; | 1749 | u16 ethertype, hdrlen, meshhdrlen = 0; |
1732 | __le16 fc; | 1750 | __le16 fc; |
@@ -1798,7 +1816,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1798 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1816 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1799 | skb->data, skb->data + ETH_ALEN); | 1817 | skb->data, skb->data + ETH_ALEN); |
1800 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1818 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1801 | sdata, NULL, NULL, NULL); | 1819 | sdata, NULL, NULL); |
1802 | } else { | 1820 | } else { |
1803 | /* packet from other interface */ | 1821 | /* packet from other interface */ |
1804 | struct mesh_path *mppath; | 1822 | struct mesh_path *mppath; |
@@ -1831,13 +1849,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1831 | ieee80211_new_mesh_header(&mesh_hdr, | 1849 | ieee80211_new_mesh_header(&mesh_hdr, |
1832 | sdata, | 1850 | sdata, |
1833 | skb->data + ETH_ALEN, | 1851 | skb->data + ETH_ALEN, |
1834 | NULL, | ||
1835 | NULL); | 1852 | NULL); |
1836 | else | 1853 | else |
1837 | meshhdrlen = | 1854 | meshhdrlen = |
1838 | ieee80211_new_mesh_header(&mesh_hdr, | 1855 | ieee80211_new_mesh_header(&mesh_hdr, |
1839 | sdata, | 1856 | sdata, |
1840 | NULL, | ||
1841 | skb->data, | 1857 | skb->data, |
1842 | skb->data + ETH_ALEN); | 1858 | skb->data + ETH_ALEN); |
1843 | 1859 | ||
@@ -1921,7 +1937,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1921 | */ | 1937 | */ |
1922 | if (skb_shared(skb)) { | 1938 | if (skb_shared(skb)) { |
1923 | tmp_skb = skb; | 1939 | tmp_skb = skb; |
1924 | skb = skb_copy(skb, GFP_ATOMIC); | 1940 | skb = skb_clone(skb, GFP_ATOMIC); |
1925 | kfree_skb(tmp_skb); | 1941 | kfree_skb(tmp_skb); |
1926 | 1942 | ||
1927 | if (!skb) { | 1943 | if (!skb) { |
@@ -2017,6 +2033,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2017 | skb_set_network_header(skb, nh_pos); | 2033 | skb_set_network_header(skb, nh_pos); |
2018 | skb_set_transport_header(skb, h_pos); | 2034 | skb_set_transport_header(skb, h_pos); |
2019 | 2035 | ||
2036 | info = IEEE80211_SKB_CB(skb); | ||
2020 | memset(info, 0, sizeof(*info)); | 2037 | memset(info, 0, sizeof(*info)); |
2021 | 2038 | ||
2022 | dev->trans_start = jiffies; | 2039 | dev->trans_start = jiffies; |
@@ -2277,7 +2294,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2277 | u8 *pos; | 2294 | u8 *pos; |
2278 | 2295 | ||
2279 | /* headroom, head length, tail length and maximum TIM length */ | 2296 | /* headroom, head length, tail length and maximum TIM length */ |
2280 | skb = dev_alloc_skb(local->tx_headroom + 400); | 2297 | skb = dev_alloc_skb(local->tx_headroom + 400 + |
2298 | sdata->u.mesh.vendor_ie_len); | ||
2281 | if (!skb) | 2299 | if (!skb) |
2282 | goto out; | 2300 | goto out; |
2283 | 2301 | ||
@@ -2321,7 +2339,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2321 | txrc.max_rate_idx = -1; | 2339 | txrc.max_rate_idx = -1; |
2322 | else | 2340 | else |
2323 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | 2341 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; |
2324 | txrc.ap = true; | 2342 | txrc.bss = true; |
2325 | rate_control_get_rate(sdata, NULL, &txrc); | 2343 | rate_control_get_rate(sdata, NULL, &txrc); |
2326 | 2344 | ||
2327 | info->control.vif = vif; | 2345 | info->control.vif = vif; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0b6fc92bc0d7..cf68700abffa 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -368,8 +368,9 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
368 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 368 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
369 | } | 369 | } |
370 | 370 | ||
371 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | 371 | int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, |
372 | struct sk_buff_head *skbs) | 372 | struct sk_buff_head *skbs, |
373 | void (*fn)(void *data), void *data) | ||
373 | { | 374 | { |
374 | struct ieee80211_hw *hw = &local->hw; | 375 | struct ieee80211_hw *hw = &local->hw; |
375 | struct sk_buff *skb; | 376 | struct sk_buff *skb; |
@@ -394,6 +395,9 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
394 | __skb_queue_tail(&local->pending[queue], skb); | 395 | __skb_queue_tail(&local->pending[queue], skb); |
395 | } | 396 | } |
396 | 397 | ||
398 | if (fn) | ||
399 | fn(data); | ||
400 | |||
397 | for (i = 0; i < hw->queues; i++) | 401 | for (i = 0; i < hw->queues; i++) |
398 | __ieee80211_wake_queue(hw, i, | 402 | __ieee80211_wake_queue(hw, i, |
399 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 403 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
@@ -402,6 +406,12 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
402 | return ret; | 406 | return ret; |
403 | } | 407 | } |
404 | 408 | ||
409 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
410 | struct sk_buff_head *skbs) | ||
411 | { | ||
412 | return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | ||
413 | } | ||
414 | |||
405 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 415 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
406 | enum queue_stop_reason reason) | 416 | enum queue_stop_reason reason) |
407 | { | 417 | { |
@@ -1011,9 +1021,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1011 | return pos - buffer; | 1021 | return pos - buffer; |
1012 | } | 1022 | } |
1013 | 1023 | ||
1014 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1024 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1015 | const u8 *ssid, size_t ssid_len, | 1025 | u8 *dst, |
1016 | const u8 *ie, size_t ie_len) | 1026 | const u8 *ssid, size_t ssid_len, |
1027 | const u8 *ie, size_t ie_len) | ||
1017 | { | 1028 | { |
1018 | struct ieee80211_local *local = sdata->local; | 1029 | struct ieee80211_local *local = sdata->local; |
1019 | struct sk_buff *skb; | 1030 | struct sk_buff *skb; |
@@ -1027,7 +1038,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1027 | if (!buf) { | 1038 | if (!buf) { |
1028 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " | 1039 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " |
1029 | "buffer\n", sdata->name); | 1040 | "buffer\n", sdata->name); |
1030 | return; | 1041 | return NULL; |
1031 | } | 1042 | } |
1032 | 1043 | ||
1033 | chan = ieee80211_frequency_to_channel( | 1044 | chan = ieee80211_frequency_to_channel( |
@@ -1050,8 +1061,20 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1050 | } | 1061 | } |
1051 | 1062 | ||
1052 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1063 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1053 | ieee80211_tx_skb(sdata, skb); | ||
1054 | kfree(buf); | 1064 | kfree(buf); |
1065 | |||
1066 | return skb; | ||
1067 | } | ||
1068 | |||
1069 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
1070 | const u8 *ssid, size_t ssid_len, | ||
1071 | const u8 *ie, size_t ie_len) | ||
1072 | { | ||
1073 | struct sk_buff *skb; | ||
1074 | |||
1075 | skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len); | ||
1076 | if (skb) | ||
1077 | ieee80211_tx_skb(sdata, skb); | ||
1055 | } | 1078 | } |
1056 | 1079 | ||
1057 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1080 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
@@ -1093,6 +1116,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1093 | void ieee80211_stop_device(struct ieee80211_local *local) | 1116 | void ieee80211_stop_device(struct ieee80211_local *local) |
1094 | { | 1117 | { |
1095 | ieee80211_led_radio(local, false); | 1118 | ieee80211_led_radio(local, false); |
1119 | ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO); | ||
1096 | 1120 | ||
1097 | cancel_work_sync(&local->reconfig_filter); | 1121 | cancel_work_sync(&local->reconfig_filter); |
1098 | 1122 | ||
@@ -1127,6 +1151,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1127 | } | 1151 | } |
1128 | 1152 | ||
1129 | ieee80211_led_radio(local, true); | 1153 | ieee80211_led_radio(local, true); |
1154 | ieee80211_mod_tpt_led_trig(local, | ||
1155 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | ||
1130 | } | 1156 | } |
1131 | 1157 | ||
1132 | /* add interfaces */ | 1158 | /* add interfaces */ |
@@ -1152,6 +1178,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1152 | } | 1178 | } |
1153 | mutex_unlock(&local->sta_mtx); | 1179 | mutex_unlock(&local->sta_mtx); |
1154 | 1180 | ||
1181 | /* setup fragmentation threshold */ | ||
1182 | drv_set_frag_threshold(local, hw->wiphy->frag_threshold); | ||
1183 | |||
1155 | /* setup RTS threshold */ | 1184 | /* setup RTS threshold */ |
1156 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); | 1185 | drv_set_rts_threshold(local, hw->wiphy->rts_threshold); |
1157 | 1186 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 34e6d02da779..58e75bbc1f91 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -21,7 +21,16 @@ | |||
21 | /* Default mapping in classifier to work with default | 21 | /* Default mapping in classifier to work with default |
22 | * queue setup. | 22 | * queue setup. |
23 | */ | 23 | */ |
24 | const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; | 24 | const int ieee802_1d_to_ac[8] = { |
25 | IEEE80211_AC_BE, | ||
26 | IEEE80211_AC_BK, | ||
27 | IEEE80211_AC_BK, | ||
28 | IEEE80211_AC_BE, | ||
29 | IEEE80211_AC_VI, | ||
30 | IEEE80211_AC_VI, | ||
31 | IEEE80211_AC_VO, | ||
32 | IEEE80211_AC_VO | ||
33 | }; | ||
25 | 34 | ||
26 | static int wme_downgrade_ac(struct sk_buff *skb) | 35 | static int wme_downgrade_ac(struct sk_buff *skb) |
27 | { | 36 | { |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 146097cb43a7..36305e0d06ef 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -458,8 +458,9 @@ ieee80211_direct_probe(struct ieee80211_work *wk) | |||
458 | return WORK_ACT_TIMEOUT; | 458 | return WORK_ACT_TIMEOUT; |
459 | } | 459 | } |
460 | 460 | ||
461 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", | 461 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", |
462 | sdata->name, wk->filter_ta, wk->probe_auth.tries); | 462 | sdata->name, wk->filter_ta, wk->probe_auth.tries, |
463 | IEEE80211_AUTH_MAX_TRIES); | ||
463 | 464 | ||
464 | /* | 465 | /* |
465 | * Direct probe is sent to broadcast address as some APs | 466 | * Direct probe is sent to broadcast address as some APs |
@@ -561,6 +562,25 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | |||
561 | } | 562 | } |
562 | 563 | ||
563 | static enum work_action __must_check | 564 | static enum work_action __must_check |
565 | ieee80211_offchannel_tx(struct ieee80211_work *wk) | ||
566 | { | ||
567 | if (!wk->started) { | ||
568 | wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait); | ||
569 | |||
570 | /* | ||
571 | * After this, offchan_tx.frame remains but now is no | ||
572 | * longer a valid pointer -- we still need it as the | ||
573 | * cookie for canceling this work. | ||
574 | */ | ||
575 | ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame); | ||
576 | |||
577 | return WORK_ACT_NONE; | ||
578 | } | ||
579 | |||
580 | return WORK_ACT_TIMEOUT; | ||
581 | } | ||
582 | |||
583 | static enum work_action __must_check | ||
564 | ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) | 584 | ieee80211_assoc_beacon_wait(struct ieee80211_work *wk) |
565 | { | 585 | { |
566 | if (wk->started) | 586 | if (wk->started) |
@@ -955,6 +975,9 @@ static void ieee80211_work_work(struct work_struct *work) | |||
955 | case IEEE80211_WORK_REMAIN_ON_CHANNEL: | 975 | case IEEE80211_WORK_REMAIN_ON_CHANNEL: |
956 | rma = ieee80211_remain_on_channel_timeout(wk); | 976 | rma = ieee80211_remain_on_channel_timeout(wk); |
957 | break; | 977 | break; |
978 | case IEEE80211_WORK_OFFCHANNEL_TX: | ||
979 | rma = ieee80211_offchannel_tx(wk); | ||
980 | break; | ||
958 | case IEEE80211_WORK_ASSOC_BEACON_WAIT: | 981 | case IEEE80211_WORK_ASSOC_BEACON_WAIT: |
959 | rma = ieee80211_assoc_beacon_wait(wk); | 982 | rma = ieee80211_assoc_beacon_wait(wk); |
960 | break; | 983 | break; |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 85dabb86be6f..32fcbe290c04 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -173,9 +173,11 @@ next_hook: | |||
173 | outdev, &elem, okfn, hook_thresh); | 173 | outdev, &elem, okfn, hook_thresh); |
174 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { | 174 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { |
175 | ret = 1; | 175 | ret = 1; |
176 | } else if (verdict == NF_DROP) { | 176 | } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { |
177 | kfree_skb(skb); | 177 | kfree_skb(skb); |
178 | ret = -EPERM; | 178 | ret = -(verdict >> NF_VERDICT_BITS); |
179 | if (ret == 0) | ||
180 | ret = -EPERM; | ||
179 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { | 181 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { |
180 | if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn, | 182 | if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn, |
181 | verdict >> NF_VERDICT_BITS)) | 183 | verdict >> NF_VERDICT_BITS)) |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 5f5daa30b0af..c6f293639220 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -110,10 +110,8 @@ static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) | |||
110 | struct rt6_info *rt; | 110 | struct rt6_info *rt; |
111 | struct flowi fl = { | 111 | struct flowi fl = { |
112 | .oif = 0, | 112 | .oif = 0, |
113 | .nl_u = { | 113 | .fl6_dst = *addr, |
114 | .ip6_u = { | 114 | .fl6_src = { .s6_addr32 = {0, 0, 0, 0} }, |
115 | .daddr = *addr, | ||
116 | .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } }, | ||
117 | }; | 115 | }; |
118 | 116 | ||
119 | rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); | 117 | rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index de04ea39cde8..5325a3fbe4ac 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -96,12 +96,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
96 | if (!(rt = (struct rtable *) | 96 | if (!(rt = (struct rtable *) |
97 | __ip_vs_dst_check(dest, rtos))) { | 97 | __ip_vs_dst_check(dest, rtos))) { |
98 | struct flowi fl = { | 98 | struct flowi fl = { |
99 | .oif = 0, | 99 | .fl4_dst = dest->addr.ip, |
100 | .nl_u = { | 100 | .fl4_tos = rtos, |
101 | .ip4_u = { | ||
102 | .daddr = dest->addr.ip, | ||
103 | .saddr = 0, | ||
104 | .tos = rtos, } }, | ||
105 | }; | 101 | }; |
106 | 102 | ||
107 | if (ip_route_output_key(net, &rt, &fl)) { | 103 | if (ip_route_output_key(net, &rt, &fl)) { |
@@ -118,12 +114,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
118 | spin_unlock(&dest->dst_lock); | 114 | spin_unlock(&dest->dst_lock); |
119 | } else { | 115 | } else { |
120 | struct flowi fl = { | 116 | struct flowi fl = { |
121 | .oif = 0, | 117 | .fl4_dst = daddr, |
122 | .nl_u = { | 118 | .fl4_tos = rtos, |
123 | .ip4_u = { | ||
124 | .daddr = daddr, | ||
125 | .saddr = 0, | ||
126 | .tos = rtos, } }, | ||
127 | }; | 119 | }; |
128 | 120 | ||
129 | if (ip_route_output_key(net, &rt, &fl)) { | 121 | if (ip_route_output_key(net, &rt, &fl)) { |
@@ -169,7 +161,7 @@ __ip_vs_reroute_locally(struct sk_buff *skb) | |||
169 | struct net *net = dev_net(dev); | 161 | struct net *net = dev_net(dev); |
170 | struct iphdr *iph = ip_hdr(skb); | 162 | struct iphdr *iph = ip_hdr(skb); |
171 | 163 | ||
172 | if (rt->fl.iif) { | 164 | if (rt_is_input_route(rt)) { |
173 | unsigned long orefdst = skb->_skb_refdst; | 165 | unsigned long orefdst = skb->_skb_refdst; |
174 | 166 | ||
175 | if (ip_route_input(skb, iph->daddr, iph->saddr, | 167 | if (ip_route_input(skb, iph->daddr, iph->saddr, |
@@ -178,14 +170,9 @@ __ip_vs_reroute_locally(struct sk_buff *skb) | |||
178 | refdst_drop(orefdst); | 170 | refdst_drop(orefdst); |
179 | } else { | 171 | } else { |
180 | struct flowi fl = { | 172 | struct flowi fl = { |
181 | .oif = 0, | 173 | .fl4_dst = iph->daddr, |
182 | .nl_u = { | 174 | .fl4_src = iph->saddr, |
183 | .ip4_u = { | 175 | .fl4_tos = RT_TOS(iph->tos), |
184 | .daddr = iph->daddr, | ||
185 | .saddr = iph->saddr, | ||
186 | .tos = RT_TOS(iph->tos), | ||
187 | } | ||
188 | }, | ||
189 | .mark = skb->mark, | 176 | .mark = skb->mark, |
190 | }; | 177 | }; |
191 | struct rtable *rt; | 178 | struct rtable *rt; |
@@ -216,12 +203,7 @@ __ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr, | |||
216 | { | 203 | { |
217 | struct dst_entry *dst; | 204 | struct dst_entry *dst; |
218 | struct flowi fl = { | 205 | struct flowi fl = { |
219 | .oif = 0, | 206 | .fl6_dst = *daddr, |
220 | .nl_u = { | ||
221 | .ip6_u = { | ||
222 | .daddr = *daddr, | ||
223 | }, | ||
224 | }, | ||
225 | }; | 207 | }; |
226 | 208 | ||
227 | dst = ip6_route_output(net, NULL, &fl); | 209 | dst = ip6_route_output(net, NULL, &fl); |
@@ -552,7 +534,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
552 | #endif | 534 | #endif |
553 | 535 | ||
554 | /* From world but DNAT to loopback address? */ | 536 | /* From world but DNAT to loopback address? */ |
555 | if (local && ipv4_is_loopback(rt->rt_dst) && skb_rtable(skb)->fl.iif) { | 537 | if (local && ipv4_is_loopback(rt->rt_dst) && |
538 | rt_is_input_route(skb_rtable(skb))) { | ||
556 | IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " | 539 | IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " |
557 | "stopping DNAT to loopback address"); | 540 | "stopping DNAT to loopback address"); |
558 | goto tx_error_put; | 541 | goto tx_error_put; |
@@ -1165,7 +1148,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1165 | #endif | 1148 | #endif |
1166 | 1149 | ||
1167 | /* From world but DNAT to loopback address? */ | 1150 | /* From world but DNAT to loopback address? */ |
1168 | if (local && ipv4_is_loopback(rt->rt_dst) && skb_rtable(skb)->fl.iif) { | 1151 | if (local && ipv4_is_loopback(rt->rt_dst) && |
1152 | rt_is_input_route(skb_rtable(skb))) { | ||
1169 | IP_VS_DBG(1, "%s(): " | 1153 | IP_VS_DBG(1, "%s(): " |
1170 | "stopping DNAT to loopback %pI4\n", | 1154 | "stopping DNAT to loopback %pI4\n", |
1171 | __func__, &cp->daddr.ip); | 1155 | __func__, &cp->daddr.ip); |
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index 22a2d421e7eb..5128a6c4cb2c 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c | |||
@@ -70,9 +70,9 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info) | |||
70 | return false; | 70 | return false; |
71 | fl.oif = info->priv->oif; | 71 | fl.oif = info->priv->oif; |
72 | } | 72 | } |
73 | fl.nl_u.ip4_u.daddr = info->gw.ip; | 73 | fl.fl4_dst = info->gw.ip; |
74 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | 74 | fl.fl4_tos = RT_TOS(iph->tos); |
75 | fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE; | 75 | fl.fl4_scope = RT_SCOPE_UNIVERSE; |
76 | if (ip_route_output_key(net, &rt, &fl) != 0) | 76 | if (ip_route_output_key(net, &rt, &fl) != 0) |
77 | return false; | 77 | return false; |
78 | 78 | ||
@@ -150,9 +150,9 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info) | |||
150 | return false; | 150 | return false; |
151 | fl.oif = info->priv->oif; | 151 | fl.oif = info->priv->oif; |
152 | } | 152 | } |
153 | fl.nl_u.ip6_u.daddr = info->gw.in6; | 153 | fl.fl6_dst = info->gw.in6; |
154 | fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) | | 154 | fl.fl6_flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) | |
155 | (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]; | 155 | (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]; |
156 | dst = ip6_route_output(net, NULL, &fl); | 156 | dst = ip6_route_output(net, NULL, &fl); |
157 | if (dst == NULL) | 157 | if (dst == NULL) |
158 | return false; | 158 | return false; |
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h index c8a4079261f0..af7f3355103e 100644 --- a/net/netlabel/netlabel_cipso_v4.h +++ b/net/netlabel/netlabel_cipso_v4.h | |||
@@ -107,7 +107,6 @@ enum { | |||
107 | NLBL_CIPSOV4_C_LISTALL, | 107 | NLBL_CIPSOV4_C_LISTALL, |
108 | __NLBL_CIPSOV4_C_MAX, | 108 | __NLBL_CIPSOV4_C_MAX, |
109 | }; | 109 | }; |
110 | #define NLBL_CIPSOV4_C_MAX (__NLBL_CIPSOV4_C_MAX - 1) | ||
111 | 110 | ||
112 | /* NetLabel CIPSOv4 attributes */ | 111 | /* NetLabel CIPSOv4 attributes */ |
113 | enum { | 112 | enum { |
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h index 05d96431f819..0a25838bcf45 100644 --- a/net/netlabel/netlabel_mgmt.h +++ b/net/netlabel/netlabel_mgmt.h | |||
@@ -173,7 +173,6 @@ enum { | |||
173 | NLBL_MGMT_C_VERSION, | 173 | NLBL_MGMT_C_VERSION, |
174 | __NLBL_MGMT_C_MAX, | 174 | __NLBL_MGMT_C_MAX, |
175 | }; | 175 | }; |
176 | #define NLBL_MGMT_C_MAX (__NLBL_MGMT_C_MAX - 1) | ||
177 | 176 | ||
178 | /* NetLabel Management attributes */ | 177 | /* NetLabel Management attributes */ |
179 | enum { | 178 | enum { |
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h index 7aba63595137..0bc8dc3f9e3c 100644 --- a/net/netlabel/netlabel_unlabeled.h +++ b/net/netlabel/netlabel_unlabeled.h | |||
@@ -180,7 +180,6 @@ enum { | |||
180 | NLBL_UNLABEL_C_STATICLISTDEF, | 180 | NLBL_UNLABEL_C_STATICLISTDEF, |
181 | __NLBL_UNLABEL_C_MAX, | 181 | __NLBL_UNLABEL_C_MAX, |
182 | }; | 182 | }; |
183 | #define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1) | ||
184 | 183 | ||
185 | /* NetLabel Unlabeled attributes */ | 184 | /* NetLabel Unlabeled attributes */ |
186 | enum { | 185 | enum { |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8298e676f5a0..91cb1d71f018 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include <linux/kernel.h> | 61 | #include <linux/kernel.h> |
62 | #include <linux/kmod.h> | 62 | #include <linux/kmod.h> |
63 | #include <linux/slab.h> | 63 | #include <linux/slab.h> |
64 | #include <linux/vmalloc.h> | ||
64 | #include <net/net_namespace.h> | 65 | #include <net/net_namespace.h> |
65 | #include <net/ip.h> | 66 | #include <net/ip.h> |
66 | #include <net/protocol.h> | 67 | #include <net/protocol.h> |
@@ -163,8 +164,13 @@ struct packet_mreq_max { | |||
163 | static int packet_set_ring(struct sock *sk, struct tpacket_req *req, | 164 | static int packet_set_ring(struct sock *sk, struct tpacket_req *req, |
164 | int closing, int tx_ring); | 165 | int closing, int tx_ring); |
165 | 166 | ||
167 | #define PGV_FROM_VMALLOC 1 | ||
168 | struct pgv { | ||
169 | char *buffer; | ||
170 | }; | ||
171 | |||
166 | struct packet_ring_buffer { | 172 | struct packet_ring_buffer { |
167 | char **pg_vec; | 173 | struct pgv *pg_vec; |
168 | unsigned int head; | 174 | unsigned int head; |
169 | unsigned int frames_per_block; | 175 | unsigned int frames_per_block; |
170 | unsigned int frame_size; | 176 | unsigned int frame_size; |
@@ -217,6 +223,13 @@ struct packet_skb_cb { | |||
217 | 223 | ||
218 | #define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb)) | 224 | #define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb)) |
219 | 225 | ||
226 | static inline __pure struct page *pgv_to_page(void *addr) | ||
227 | { | ||
228 | if (is_vmalloc_addr(addr)) | ||
229 | return vmalloc_to_page(addr); | ||
230 | return virt_to_page(addr); | ||
231 | } | ||
232 | |||
220 | static void __packet_set_status(struct packet_sock *po, void *frame, int status) | 233 | static void __packet_set_status(struct packet_sock *po, void *frame, int status) |
221 | { | 234 | { |
222 | union { | 235 | union { |
@@ -229,11 +242,11 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status) | |||
229 | switch (po->tp_version) { | 242 | switch (po->tp_version) { |
230 | case TPACKET_V1: | 243 | case TPACKET_V1: |
231 | h.h1->tp_status = status; | 244 | h.h1->tp_status = status; |
232 | flush_dcache_page(virt_to_page(&h.h1->tp_status)); | 245 | flush_dcache_page(pgv_to_page(&h.h1->tp_status)); |
233 | break; | 246 | break; |
234 | case TPACKET_V2: | 247 | case TPACKET_V2: |
235 | h.h2->tp_status = status; | 248 | h.h2->tp_status = status; |
236 | flush_dcache_page(virt_to_page(&h.h2->tp_status)); | 249 | flush_dcache_page(pgv_to_page(&h.h2->tp_status)); |
237 | break; | 250 | break; |
238 | default: | 251 | default: |
239 | pr_err("TPACKET version not supported\n"); | 252 | pr_err("TPACKET version not supported\n"); |
@@ -256,10 +269,10 @@ static int __packet_get_status(struct packet_sock *po, void *frame) | |||
256 | h.raw = frame; | 269 | h.raw = frame; |
257 | switch (po->tp_version) { | 270 | switch (po->tp_version) { |
258 | case TPACKET_V1: | 271 | case TPACKET_V1: |
259 | flush_dcache_page(virt_to_page(&h.h1->tp_status)); | 272 | flush_dcache_page(pgv_to_page(&h.h1->tp_status)); |
260 | return h.h1->tp_status; | 273 | return h.h1->tp_status; |
261 | case TPACKET_V2: | 274 | case TPACKET_V2: |
262 | flush_dcache_page(virt_to_page(&h.h2->tp_status)); | 275 | flush_dcache_page(pgv_to_page(&h.h2->tp_status)); |
263 | return h.h2->tp_status; | 276 | return h.h2->tp_status; |
264 | default: | 277 | default: |
265 | pr_err("TPACKET version not supported\n"); | 278 | pr_err("TPACKET version not supported\n"); |
@@ -283,7 +296,8 @@ static void *packet_lookup_frame(struct packet_sock *po, | |||
283 | pg_vec_pos = position / rb->frames_per_block; | 296 | pg_vec_pos = position / rb->frames_per_block; |
284 | frame_offset = position % rb->frames_per_block; | 297 | frame_offset = position % rb->frames_per_block; |
285 | 298 | ||
286 | h.raw = rb->pg_vec[pg_vec_pos] + (frame_offset * rb->frame_size); | 299 | h.raw = rb->pg_vec[pg_vec_pos].buffer + |
300 | (frame_offset * rb->frame_size); | ||
287 | 301 | ||
288 | if (status != __packet_get_status(po, h.raw)) | 302 | if (status != __packet_get_status(po, h.raw)) |
289 | return NULL; | 303 | return NULL; |
@@ -503,7 +517,8 @@ out_free: | |||
503 | return err; | 517 | return err; |
504 | } | 518 | } |
505 | 519 | ||
506 | static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk, | 520 | static inline unsigned int run_filter(const struct sk_buff *skb, |
521 | const struct sock *sk, | ||
507 | unsigned int res) | 522 | unsigned int res) |
508 | { | 523 | { |
509 | struct sk_filter *filter; | 524 | struct sk_filter *filter; |
@@ -511,22 +526,22 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk, | |||
511 | rcu_read_lock_bh(); | 526 | rcu_read_lock_bh(); |
512 | filter = rcu_dereference_bh(sk->sk_filter); | 527 | filter = rcu_dereference_bh(sk->sk_filter); |
513 | if (filter != NULL) | 528 | if (filter != NULL) |
514 | res = sk_run_filter(skb, filter->insns, filter->len); | 529 | res = sk_run_filter(skb, filter->insns); |
515 | rcu_read_unlock_bh(); | 530 | rcu_read_unlock_bh(); |
516 | 531 | ||
517 | return res; | 532 | return res; |
518 | } | 533 | } |
519 | 534 | ||
520 | /* | 535 | /* |
521 | This function makes lazy skb cloning in hope that most of packets | 536 | * This function makes lazy skb cloning in hope that most of packets |
522 | are discarded by BPF. | 537 | * are discarded by BPF. |
523 | 538 | * | |
524 | Note tricky part: we DO mangle shared skb! skb->data, skb->len | 539 | * Note tricky part: we DO mangle shared skb! skb->data, skb->len |
525 | and skb->cb are mangled. It works because (and until) packets | 540 | * and skb->cb are mangled. It works because (and until) packets |
526 | falling here are owned by current CPU. Output packets are cloned | 541 | * falling here are owned by current CPU. Output packets are cloned |
527 | by dev_queue_xmit_nit(), input packets are processed by net_bh | 542 | * by dev_queue_xmit_nit(), input packets are processed by net_bh |
528 | sequencially, so that if we return skb to original state on exit, | 543 | * sequencially, so that if we return skb to original state on exit, |
529 | we will not harm anyone. | 544 | * we will not harm anyone. |
530 | */ | 545 | */ |
531 | 546 | ||
532 | static int packet_rcv(struct sk_buff *skb, struct net_device *dev, | 547 | static int packet_rcv(struct sk_buff *skb, struct net_device *dev, |
@@ -552,11 +567,11 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, | |||
552 | 567 | ||
553 | if (dev->header_ops) { | 568 | if (dev->header_ops) { |
554 | /* The device has an explicit notion of ll header, | 569 | /* The device has an explicit notion of ll header, |
555 | exported to higher levels. | 570 | * exported to higher levels. |
556 | 571 | * | |
557 | Otherwise, the device hides datails of it frame | 572 | * Otherwise, the device hides details of its frame |
558 | structure, so that corresponding packet head | 573 | * structure, so that corresponding packet head is |
559 | never delivered to user. | 574 | * never delivered to user. |
560 | */ | 575 | */ |
561 | if (sk->sk_type != SOCK_DGRAM) | 576 | if (sk->sk_type != SOCK_DGRAM) |
562 | skb_push(skb, skb->data - skb_mac_header(skb)); | 577 | skb_push(skb, skb->data - skb_mac_header(skb)); |
@@ -791,17 +806,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, | |||
791 | 806 | ||
792 | __packet_set_status(po, h.raw, status); | 807 | __packet_set_status(po, h.raw, status); |
793 | smp_mb(); | 808 | smp_mb(); |
809 | #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1 | ||
794 | { | 810 | { |
795 | struct page *p_start, *p_end; | 811 | u8 *start, *end; |
796 | u8 *h_end = h.raw + macoff + snaplen - 1; | 812 | |
797 | 813 | end = (u8 *)PAGE_ALIGN((unsigned long)h.raw + macoff + snaplen); | |
798 | p_start = virt_to_page(h.raw); | 814 | for (start = h.raw; start < end; start += PAGE_SIZE) |
799 | p_end = virt_to_page(h_end); | 815 | flush_dcache_page(pgv_to_page(start)); |
800 | while (p_start <= p_end) { | ||
801 | flush_dcache_page(p_start); | ||
802 | p_start++; | ||
803 | } | ||
804 | } | 816 | } |
817 | #endif | ||
805 | 818 | ||
806 | sk->sk_data_ready(sk, 0); | 819 | sk->sk_data_ready(sk, 0); |
807 | 820 | ||
@@ -907,7 +920,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
907 | } | 920 | } |
908 | 921 | ||
909 | err = -EFAULT; | 922 | err = -EFAULT; |
910 | page = virt_to_page(data); | ||
911 | offset = offset_in_page(data); | 923 | offset = offset_in_page(data); |
912 | len_max = PAGE_SIZE - offset; | 924 | len_max = PAGE_SIZE - offset; |
913 | len = ((to_write > len_max) ? len_max : to_write); | 925 | len = ((to_write > len_max) ? len_max : to_write); |
@@ -926,11 +938,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
926 | return -EFAULT; | 938 | return -EFAULT; |
927 | } | 939 | } |
928 | 940 | ||
941 | page = pgv_to_page(data); | ||
942 | data += len; | ||
929 | flush_dcache_page(page); | 943 | flush_dcache_page(page); |
930 | get_page(page); | 944 | get_page(page); |
931 | skb_fill_page_desc(skb, | 945 | skb_fill_page_desc(skb, nr_frags, page, offset, len); |
932 | nr_frags, | ||
933 | page++, offset, len); | ||
934 | to_write -= len; | 946 | to_write -= len; |
935 | offset = 0; | 947 | offset = 0; |
936 | len_max = PAGE_SIZE; | 948 | len_max = PAGE_SIZE; |
@@ -1638,8 +1650,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1638 | 1650 | ||
1639 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1651 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1640 | vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; | 1652 | vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; |
1641 | vnet_hdr.csum_start = skb->csum_start - | 1653 | vnet_hdr.csum_start = skb_checksum_start_offset(skb); |
1642 | skb_headroom(skb); | ||
1643 | vnet_hdr.csum_offset = skb->csum_offset; | 1654 | vnet_hdr.csum_offset = skb->csum_offset; |
1644 | } /* else everything is zero */ | 1655 | } /* else everything is zero */ |
1645 | 1656 | ||
@@ -2325,37 +2336,70 @@ static const struct vm_operations_struct packet_mmap_ops = { | |||
2325 | .close = packet_mm_close, | 2336 | .close = packet_mm_close, |
2326 | }; | 2337 | }; |
2327 | 2338 | ||
2328 | static void free_pg_vec(char **pg_vec, unsigned int order, unsigned int len) | 2339 | static void free_pg_vec(struct pgv *pg_vec, unsigned int order, |
2340 | unsigned int len) | ||
2329 | { | 2341 | { |
2330 | int i; | 2342 | int i; |
2331 | 2343 | ||
2332 | for (i = 0; i < len; i++) { | 2344 | for (i = 0; i < len; i++) { |
2333 | if (likely(pg_vec[i])) | 2345 | if (likely(pg_vec[i].buffer)) { |
2334 | free_pages((unsigned long) pg_vec[i], order); | 2346 | if (is_vmalloc_addr(pg_vec[i].buffer)) |
2347 | vfree(pg_vec[i].buffer); | ||
2348 | else | ||
2349 | free_pages((unsigned long)pg_vec[i].buffer, | ||
2350 | order); | ||
2351 | pg_vec[i].buffer = NULL; | ||
2352 | } | ||
2335 | } | 2353 | } |
2336 | kfree(pg_vec); | 2354 | kfree(pg_vec); |
2337 | } | 2355 | } |
2338 | 2356 | ||
2339 | static inline char *alloc_one_pg_vec_page(unsigned long order) | 2357 | static inline char *alloc_one_pg_vec_page(unsigned long order) |
2340 | { | 2358 | { |
2341 | gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN; | 2359 | char *buffer = NULL; |
2360 | gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | | ||
2361 | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY; | ||
2342 | 2362 | ||
2343 | return (char *) __get_free_pages(gfp_flags, order); | 2363 | buffer = (char *) __get_free_pages(gfp_flags, order); |
2364 | |||
2365 | if (buffer) | ||
2366 | return buffer; | ||
2367 | |||
2368 | /* | ||
2369 | * __get_free_pages failed, fall back to vmalloc | ||
2370 | */ | ||
2371 | buffer = vzalloc((1 << order) * PAGE_SIZE); | ||
2372 | |||
2373 | if (buffer) | ||
2374 | return buffer; | ||
2375 | |||
2376 | /* | ||
2377 | * vmalloc failed, lets dig into swap here | ||
2378 | */ | ||
2379 | gfp_flags &= ~__GFP_NORETRY; | ||
2380 | buffer = (char *)__get_free_pages(gfp_flags, order); | ||
2381 | if (buffer) | ||
2382 | return buffer; | ||
2383 | |||
2384 | /* | ||
2385 | * complete and utter failure | ||
2386 | */ | ||
2387 | return NULL; | ||
2344 | } | 2388 | } |
2345 | 2389 | ||
2346 | static char **alloc_pg_vec(struct tpacket_req *req, int order) | 2390 | static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order) |
2347 | { | 2391 | { |
2348 | unsigned int block_nr = req->tp_block_nr; | 2392 | unsigned int block_nr = req->tp_block_nr; |
2349 | char **pg_vec; | 2393 | struct pgv *pg_vec; |
2350 | int i; | 2394 | int i; |
2351 | 2395 | ||
2352 | pg_vec = kzalloc(block_nr * sizeof(char *), GFP_KERNEL); | 2396 | pg_vec = kcalloc(block_nr, sizeof(struct pgv), GFP_KERNEL); |
2353 | if (unlikely(!pg_vec)) | 2397 | if (unlikely(!pg_vec)) |
2354 | goto out; | 2398 | goto out; |
2355 | 2399 | ||
2356 | for (i = 0; i < block_nr; i++) { | 2400 | for (i = 0; i < block_nr; i++) { |
2357 | pg_vec[i] = alloc_one_pg_vec_page(order); | 2401 | pg_vec[i].buffer = alloc_one_pg_vec_page(order); |
2358 | if (unlikely(!pg_vec[i])) | 2402 | if (unlikely(!pg_vec[i].buffer)) |
2359 | goto out_free_pgvec; | 2403 | goto out_free_pgvec; |
2360 | } | 2404 | } |
2361 | 2405 | ||
@@ -2371,7 +2415,7 @@ out_free_pgvec: | |||
2371 | static int packet_set_ring(struct sock *sk, struct tpacket_req *req, | 2415 | static int packet_set_ring(struct sock *sk, struct tpacket_req *req, |
2372 | int closing, int tx_ring) | 2416 | int closing, int tx_ring) |
2373 | { | 2417 | { |
2374 | char **pg_vec = NULL; | 2418 | struct pgv *pg_vec = NULL; |
2375 | struct packet_sock *po = pkt_sk(sk); | 2419 | struct packet_sock *po = pkt_sk(sk); |
2376 | int was_running, order = 0; | 2420 | int was_running, order = 0; |
2377 | struct packet_ring_buffer *rb; | 2421 | struct packet_ring_buffer *rb; |
@@ -2456,22 +2500,20 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, | |||
2456 | mutex_lock(&po->pg_vec_lock); | 2500 | mutex_lock(&po->pg_vec_lock); |
2457 | if (closing || atomic_read(&po->mapped) == 0) { | 2501 | if (closing || atomic_read(&po->mapped) == 0) { |
2458 | err = 0; | 2502 | err = 0; |
2459 | #define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) | ||
2460 | spin_lock_bh(&rb_queue->lock); | 2503 | spin_lock_bh(&rb_queue->lock); |
2461 | pg_vec = XC(rb->pg_vec, pg_vec); | 2504 | swap(rb->pg_vec, pg_vec); |
2462 | rb->frame_max = (req->tp_frame_nr - 1); | 2505 | rb->frame_max = (req->tp_frame_nr - 1); |
2463 | rb->head = 0; | 2506 | rb->head = 0; |
2464 | rb->frame_size = req->tp_frame_size; | 2507 | rb->frame_size = req->tp_frame_size; |
2465 | spin_unlock_bh(&rb_queue->lock); | 2508 | spin_unlock_bh(&rb_queue->lock); |
2466 | 2509 | ||
2467 | order = XC(rb->pg_vec_order, order); | 2510 | swap(rb->pg_vec_order, order); |
2468 | req->tp_block_nr = XC(rb->pg_vec_len, req->tp_block_nr); | 2511 | swap(rb->pg_vec_len, req->tp_block_nr); |
2469 | 2512 | ||
2470 | rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE; | 2513 | rb->pg_vec_pages = req->tp_block_size/PAGE_SIZE; |
2471 | po->prot_hook.func = (po->rx_ring.pg_vec) ? | 2514 | po->prot_hook.func = (po->rx_ring.pg_vec) ? |
2472 | tpacket_rcv : packet_rcv; | 2515 | tpacket_rcv : packet_rcv; |
2473 | skb_queue_purge(rb_queue); | 2516 | skb_queue_purge(rb_queue); |
2474 | #undef XC | ||
2475 | if (atomic_read(&po->mapped)) | 2517 | if (atomic_read(&po->mapped)) |
2476 | pr_err("packet_mmap: vma is busy: %d\n", | 2518 | pr_err("packet_mmap: vma is busy: %d\n", |
2477 | atomic_read(&po->mapped)); | 2519 | atomic_read(&po->mapped)); |
@@ -2533,15 +2575,17 @@ static int packet_mmap(struct file *file, struct socket *sock, | |||
2533 | continue; | 2575 | continue; |
2534 | 2576 | ||
2535 | for (i = 0; i < rb->pg_vec_len; i++) { | 2577 | for (i = 0; i < rb->pg_vec_len; i++) { |
2536 | struct page *page = virt_to_page(rb->pg_vec[i]); | 2578 | struct page *page; |
2579 | void *kaddr = rb->pg_vec[i].buffer; | ||
2537 | int pg_num; | 2580 | int pg_num; |
2538 | 2581 | ||
2539 | for (pg_num = 0; pg_num < rb->pg_vec_pages; | 2582 | for (pg_num = 0; pg_num < rb->pg_vec_pages; pg_num++) { |
2540 | pg_num++, page++) { | 2583 | page = pgv_to_page(kaddr); |
2541 | err = vm_insert_page(vma, start, page); | 2584 | err = vm_insert_page(vma, start, page); |
2542 | if (unlikely(err)) | 2585 | if (unlikely(err)) |
2543 | goto out; | 2586 | goto out; |
2544 | start += PAGE_SIZE; | 2587 | start += PAGE_SIZE; |
2588 | kaddr += PAGE_SIZE; | ||
2545 | } | 2589 | } |
2546 | } | 2590 | } |
2547 | } | 2591 | } |
diff --git a/net/phonet/Makefile b/net/phonet/Makefile index d62bbba649b3..e10b1b182ce3 100644 --- a/net/phonet/Makefile +++ b/net/phonet/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | obj-$(CONFIG_PHONET) += phonet.o pn_pep.o | 1 | obj-$(CONFIG_PHONET) += phonet.o pn_pep.o |
2 | 2 | ||
3 | phonet-objs := \ | 3 | phonet-y := \ |
4 | pn_dev.o \ | 4 | pn_dev.o \ |
5 | pn_netlink.o \ | 5 | pn_netlink.o \ |
6 | socket.o \ | 6 | socket.o \ |
@@ -8,4 +8,4 @@ phonet-objs := \ | |||
8 | sysctl.o \ | 8 | sysctl.o \ |
9 | af_phonet.o | 9 | af_phonet.o |
10 | 10 | ||
11 | pn_pep-objs := pep.o pep-gprs.o | 11 | pn_pep-y := pep.o pep-gprs.o |
diff --git a/net/rds/Makefile b/net/rds/Makefile index b46eca109688..56d3f6023ced 100644 --- a/net/rds/Makefile +++ b/net/rds/Makefile | |||
@@ -4,7 +4,7 @@ rds-y := af_rds.o bind.o cong.o connection.o info.o message.o \ | |||
4 | loop.o page.o rdma.o | 4 | loop.o page.o rdma.o |
5 | 5 | ||
6 | obj-$(CONFIG_RDS_RDMA) += rds_rdma.o | 6 | obj-$(CONFIG_RDS_RDMA) += rds_rdma.o |
7 | rds_rdma-objs := rdma_transport.o \ | 7 | rds_rdma-y := rdma_transport.o \ |
8 | ib.o ib_cm.o ib_recv.o ib_ring.o ib_send.o ib_stats.o \ | 8 | ib.o ib_cm.o ib_recv.o ib_ring.o ib_send.o ib_stats.o \ |
9 | ib_sysctl.o ib_rdma.o \ | 9 | ib_sysctl.o ib_rdma.o \ |
10 | iw.o iw_cm.o iw_recv.o iw_ring.o iw_send.o iw_stats.o \ | 10 | iw.o iw_cm.o iw_recv.o iw_ring.o iw_send.o iw_stats.o \ |
@@ -12,10 +12,8 @@ rds_rdma-objs := rdma_transport.o \ | |||
12 | 12 | ||
13 | 13 | ||
14 | obj-$(CONFIG_RDS_TCP) += rds_tcp.o | 14 | obj-$(CONFIG_RDS_TCP) += rds_tcp.o |
15 | rds_tcp-objs := tcp.o tcp_connect.o tcp_listen.o tcp_recv.o \ | 15 | rds_tcp-y := tcp.o tcp_connect.o tcp_listen.o tcp_recv.o \ |
16 | tcp_send.o tcp_stats.o | 16 | tcp_send.o tcp_stats.o |
17 | 17 | ||
18 | ifeq ($(CONFIG_RDS_DEBUG), y) | 18 | ccflags-$(CONFIG_RDS_DEBUG) := -DDEBUG |
19 | EXTRA_CFLAGS += -DDEBUG | ||
20 | endif | ||
21 | 19 | ||
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 04f599089e6d..0198191b756d 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -149,20 +149,6 @@ static void rfkill_led_trigger_activate(struct led_classdev *led) | |||
149 | rfkill_led_trigger_event(rfkill); | 149 | rfkill_led_trigger_event(rfkill); |
150 | } | 150 | } |
151 | 151 | ||
152 | const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) | ||
153 | { | ||
154 | return rfkill->led_trigger.name; | ||
155 | } | ||
156 | EXPORT_SYMBOL(rfkill_get_led_trigger_name); | ||
157 | |||
158 | void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) | ||
159 | { | ||
160 | BUG_ON(!rfkill); | ||
161 | |||
162 | rfkill->ledtrigname = name; | ||
163 | } | ||
164 | EXPORT_SYMBOL(rfkill_set_led_trigger_name); | ||
165 | |||
166 | static int rfkill_led_trigger_register(struct rfkill *rfkill) | 152 | static int rfkill_led_trigger_register(struct rfkill *rfkill) |
167 | { | 153 | { |
168 | rfkill->led_trigger.name = rfkill->ledtrigname | 154 | rfkill->led_trigger.name = rfkill->ledtrigname |
diff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile index c46867c61c98..d1c3429b69ed 100644 --- a/net/rxrpc/Makefile +++ b/net/rxrpc/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for Linux kernel RxRPC | 2 | # Makefile for Linux kernel RxRPC |
3 | # | 3 | # |
4 | 4 | ||
5 | af-rxrpc-objs := \ | 5 | af-rxrpc-y := \ |
6 | af_rxrpc.o \ | 6 | af_rxrpc.o \ |
7 | ar-accept.o \ | 7 | ar-accept.o \ |
8 | ar-ack.o \ | 8 | ar-ack.o \ |
@@ -21,7 +21,7 @@ af-rxrpc-objs := \ | |||
21 | ar-transport.o | 21 | ar-transport.o |
22 | 22 | ||
23 | ifeq ($(CONFIG_PROC_FS),y) | 23 | ifeq ($(CONFIG_PROC_FS),y) |
24 | af-rxrpc-objs += ar-proc.o | 24 | af-rxrpc-y += ar-proc.o |
25 | endif | 25 | endif |
26 | 26 | ||
27 | obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o | 27 | obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o |
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index 9f1729bd60de..a53fb25a64ed 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c | |||
@@ -47,12 +47,12 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer) | |||
47 | case AF_INET: | 47 | case AF_INET: |
48 | fl.oif = 0; | 48 | fl.oif = 0; |
49 | fl.proto = IPPROTO_UDP, | 49 | fl.proto = IPPROTO_UDP, |
50 | fl.nl_u.ip4_u.saddr = 0; | 50 | fl.fl4_dst = peer->srx.transport.sin.sin_addr.s_addr; |
51 | fl.nl_u.ip4_u.daddr = peer->srx.transport.sin.sin_addr.s_addr; | 51 | fl.fl4_src = 0; |
52 | fl.nl_u.ip4_u.tos = 0; | 52 | fl.fl4_tos = 0; |
53 | /* assume AFS.CM talking to AFS.FS */ | 53 | /* assume AFS.CM talking to AFS.FS */ |
54 | fl.uli_u.ports.sport = htons(7001); | 54 | fl.fl_ip_sport = htons(7001); |
55 | fl.uli_u.ports.dport = htons(7000); | 55 | fl.fl_ip_dport = htons(7000); |
56 | break; | 56 | break; |
57 | default: | 57 | default: |
58 | BUG(); | 58 | BUG(); |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 5dbb3cd96e59..34dc598440a2 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -60,8 +60,7 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q) | |||
60 | 60 | ||
61 | /* check the reason of requeuing without tx lock first */ | 61 | /* check the reason of requeuing without tx lock first */ |
62 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); | 62 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); |
63 | if (!netif_tx_queue_stopped(txq) && | 63 | if (!netif_tx_queue_frozen_or_stopped(txq)) { |
64 | !netif_tx_queue_frozen(txq)) { | ||
65 | q->gso_skb = NULL; | 64 | q->gso_skb = NULL; |
66 | q->q.qlen--; | 65 | q->q.qlen--; |
67 | } else | 66 | } else |
@@ -122,7 +121,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, | |||
122 | spin_unlock(root_lock); | 121 | spin_unlock(root_lock); |
123 | 122 | ||
124 | HARD_TX_LOCK(dev, txq, smp_processor_id()); | 123 | HARD_TX_LOCK(dev, txq, smp_processor_id()); |
125 | if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq)) | 124 | if (!netif_tx_queue_frozen_or_stopped(txq)) |
126 | ret = dev_hard_start_xmit(skb, dev, txq); | 125 | ret = dev_hard_start_xmit(skb, dev, txq); |
127 | 126 | ||
128 | HARD_TX_UNLOCK(dev, txq); | 127 | HARD_TX_UNLOCK(dev, txq); |
@@ -144,8 +143,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, | |||
144 | ret = dev_requeue_skb(skb, q); | 143 | ret = dev_requeue_skb(skb, q); |
145 | } | 144 | } |
146 | 145 | ||
147 | if (ret && (netif_tx_queue_stopped(txq) || | 146 | if (ret && netif_tx_queue_frozen_or_stopped(txq)) |
148 | netif_tx_queue_frozen(txq))) | ||
149 | ret = 0; | 147 | ret = 0; |
150 | 148 | ||
151 | return ret; | 149 | return ret; |
@@ -555,7 +553,9 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, | |||
555 | size = QDISC_ALIGN(sizeof(*sch)); | 553 | size = QDISC_ALIGN(sizeof(*sch)); |
556 | size += ops->priv_size + (QDISC_ALIGNTO - 1); | 554 | size += ops->priv_size + (QDISC_ALIGNTO - 1); |
557 | 555 | ||
558 | p = kzalloc(size, GFP_KERNEL); | 556 | p = kzalloc_node(size, GFP_KERNEL, |
557 | netdev_queue_numa_node_read(dev_queue)); | ||
558 | |||
559 | if (!p) | 559 | if (!p) |
560 | goto errout; | 560 | goto errout; |
561 | sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); | 561 | sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); |
@@ -810,20 +810,35 @@ static bool some_qdisc_is_busy(struct net_device *dev) | |||
810 | return false; | 810 | return false; |
811 | } | 811 | } |
812 | 812 | ||
813 | void dev_deactivate(struct net_device *dev) | 813 | void dev_deactivate_many(struct list_head *head) |
814 | { | 814 | { |
815 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); | 815 | struct net_device *dev; |
816 | if (dev_ingress_queue(dev)) | 816 | |
817 | dev_deactivate_queue(dev, dev_ingress_queue(dev), &noop_qdisc); | 817 | list_for_each_entry(dev, head, unreg_list) { |
818 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, | ||
819 | &noop_qdisc); | ||
820 | if (dev_ingress_queue(dev)) | ||
821 | dev_deactivate_queue(dev, dev_ingress_queue(dev), | ||
822 | &noop_qdisc); | ||
818 | 823 | ||
819 | dev_watchdog_down(dev); | 824 | dev_watchdog_down(dev); |
825 | } | ||
820 | 826 | ||
821 | /* Wait for outstanding qdisc-less dev_queue_xmit calls. */ | 827 | /* Wait for outstanding qdisc-less dev_queue_xmit calls. */ |
822 | synchronize_rcu(); | 828 | synchronize_rcu(); |
823 | 829 | ||
824 | /* Wait for outstanding qdisc_run calls. */ | 830 | /* Wait for outstanding qdisc_run calls. */ |
825 | while (some_qdisc_is_busy(dev)) | 831 | list_for_each_entry(dev, head, unreg_list) |
826 | yield(); | 832 | while (some_qdisc_is_busy(dev)) |
833 | yield(); | ||
834 | } | ||
835 | |||
836 | void dev_deactivate(struct net_device *dev) | ||
837 | { | ||
838 | LIST_HEAD(single); | ||
839 | |||
840 | list_add(&dev->unreg_list, &single); | ||
841 | dev_deactivate_many(&single); | ||
827 | } | 842 | } |
828 | 843 | ||
829 | static void dev_init_scheduler_queue(struct net_device *dev, | 844 | static void dev_init_scheduler_queue(struct net_device *dev, |
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 8d42bb3ba540..a67ba3c5a0cc 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c | |||
@@ -239,6 +239,7 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb) | |||
239 | .Scell_log = q->parms.Scell_log, | 239 | .Scell_log = q->parms.Scell_log, |
240 | }; | 240 | }; |
241 | 241 | ||
242 | sch->qstats.backlog = q->qdisc->qstats.backlog; | ||
242 | opts = nla_nest_start(skb, TCA_OPTIONS); | 243 | opts = nla_nest_start(skb, TCA_OPTIONS); |
243 | if (opts == NULL) | 244 | if (opts == NULL) |
244 | goto nla_put_failure; | 245 | goto nla_put_failure; |
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 7150705f1d0b..d54ac94066c2 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c | |||
@@ -67,27 +67,47 @@ | |||
67 | 67 | ||
68 | IMPLEMENTATION: | 68 | IMPLEMENTATION: |
69 | This implementation limits maximal queue length to 128; | 69 | This implementation limits maximal queue length to 128; |
70 | maximal mtu to 2^15-1; number of hash buckets to 1024. | 70 | max mtu to 2^18-1; max 128 flows, number of hash buckets to 1024. |
71 | The only goal of this restrictions was that all data | 71 | The only goal of this restrictions was that all data |
72 | fit into one 4K page :-). Struct sfq_sched_data is | 72 | fit into one 4K page on 32bit arches. |
73 | organized in anti-cache manner: all the data for a bucket | ||
74 | are scattered over different locations. This is not good, | ||
75 | but it allowed me to put it into 4K. | ||
76 | 73 | ||
77 | It is easy to increase these values, but not in flight. */ | 74 | It is easy to increase these values, but not in flight. */ |
78 | 75 | ||
79 | #define SFQ_DEPTH 128 | 76 | #define SFQ_DEPTH 128 /* max number of packets per flow */ |
77 | #define SFQ_SLOTS 128 /* max number of flows */ | ||
78 | #define SFQ_EMPTY_SLOT 255 | ||
80 | #define SFQ_HASH_DIVISOR 1024 | 79 | #define SFQ_HASH_DIVISOR 1024 |
80 | /* We use 16 bits to store allot, and want to handle packets up to 64K | ||
81 | * Scale allot by 8 (1<<3) so that no overflow occurs. | ||
82 | */ | ||
83 | #define SFQ_ALLOT_SHIFT 3 | ||
84 | #define SFQ_ALLOT_SIZE(X) DIV_ROUND_UP(X, 1 << SFQ_ALLOT_SHIFT) | ||
81 | 85 | ||
82 | /* This type should contain at least SFQ_DEPTH*2 values */ | 86 | /* This type should contain at least SFQ_DEPTH + SFQ_SLOTS values */ |
83 | typedef unsigned char sfq_index; | 87 | typedef unsigned char sfq_index; |
84 | 88 | ||
89 | /* | ||
90 | * We dont use pointers to save space. | ||
91 | * Small indexes [0 ... SFQ_SLOTS - 1] are 'pointers' to slots[] array | ||
92 | * while following values [SFQ_SLOTS ... SFQ_SLOTS + SFQ_DEPTH - 1] | ||
93 | * are 'pointers' to dep[] array | ||
94 | */ | ||
85 | struct sfq_head | 95 | struct sfq_head |
86 | { | 96 | { |
87 | sfq_index next; | 97 | sfq_index next; |
88 | sfq_index prev; | 98 | sfq_index prev; |
89 | }; | 99 | }; |
90 | 100 | ||
101 | struct sfq_slot { | ||
102 | struct sk_buff *skblist_next; | ||
103 | struct sk_buff *skblist_prev; | ||
104 | sfq_index qlen; /* number of skbs in skblist */ | ||
105 | sfq_index next; /* next slot in sfq chain */ | ||
106 | struct sfq_head dep; /* anchor in dep[] chains */ | ||
107 | unsigned short hash; /* hash value (index in ht[]) */ | ||
108 | short allot; /* credit for this slot */ | ||
109 | }; | ||
110 | |||
91 | struct sfq_sched_data | 111 | struct sfq_sched_data |
92 | { | 112 | { |
93 | /* Parameters */ | 113 | /* Parameters */ |
@@ -99,17 +119,24 @@ struct sfq_sched_data | |||
99 | struct tcf_proto *filter_list; | 119 | struct tcf_proto *filter_list; |
100 | struct timer_list perturb_timer; | 120 | struct timer_list perturb_timer; |
101 | u32 perturbation; | 121 | u32 perturbation; |
102 | sfq_index tail; /* Index of current slot in round */ | 122 | sfq_index cur_depth; /* depth of longest slot */ |
103 | sfq_index max_depth; /* Maximal depth */ | 123 | unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */ |
104 | 124 | struct sfq_slot *tail; /* current slot in round */ | |
105 | sfq_index ht[SFQ_HASH_DIVISOR]; /* Hash table */ | 125 | sfq_index ht[SFQ_HASH_DIVISOR]; /* Hash table */ |
106 | sfq_index next[SFQ_DEPTH]; /* Active slots link */ | 126 | struct sfq_slot slots[SFQ_SLOTS]; |
107 | short allot[SFQ_DEPTH]; /* Current allotment per slot */ | 127 | struct sfq_head dep[SFQ_DEPTH]; /* Linked list of slots, indexed by depth */ |
108 | unsigned short hash[SFQ_DEPTH]; /* Hash value indexed by slots */ | ||
109 | struct sk_buff_head qs[SFQ_DEPTH]; /* Slot queue */ | ||
110 | struct sfq_head dep[SFQ_DEPTH*2]; /* Linked list of slots, indexed by depth */ | ||
111 | }; | 128 | }; |
112 | 129 | ||
130 | /* | ||
131 | * sfq_head are either in a sfq_slot or in dep[] array | ||
132 | */ | ||
133 | static inline struct sfq_head *sfq_dep_head(struct sfq_sched_data *q, sfq_index val) | ||
134 | { | ||
135 | if (val < SFQ_SLOTS) | ||
136 | return &q->slots[val].dep; | ||
137 | return &q->dep[val - SFQ_SLOTS]; | ||
138 | } | ||
139 | |||
113 | static __inline__ unsigned sfq_fold_hash(struct sfq_sched_data *q, u32 h, u32 h1) | 140 | static __inline__ unsigned sfq_fold_hash(struct sfq_sched_data *q, u32 h, u32 h1) |
114 | { | 141 | { |
115 | return jhash_2words(h, h1, q->perturbation) & (SFQ_HASH_DIVISOR - 1); | 142 | return jhash_2words(h, h1, q->perturbation) & (SFQ_HASH_DIVISOR - 1); |
@@ -200,30 +227,41 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch, | |||
200 | return 0; | 227 | return 0; |
201 | } | 228 | } |
202 | 229 | ||
230 | /* | ||
231 | * x : slot number [0 .. SFQ_SLOTS - 1] | ||
232 | */ | ||
203 | static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) | 233 | static inline void sfq_link(struct sfq_sched_data *q, sfq_index x) |
204 | { | 234 | { |
205 | sfq_index p, n; | 235 | sfq_index p, n; |
206 | int d = q->qs[x].qlen + SFQ_DEPTH; | 236 | int qlen = q->slots[x].qlen; |
237 | |||
238 | p = qlen + SFQ_SLOTS; | ||
239 | n = q->dep[qlen].next; | ||
207 | 240 | ||
208 | p = d; | 241 | q->slots[x].dep.next = n; |
209 | n = q->dep[d].next; | 242 | q->slots[x].dep.prev = p; |
210 | q->dep[x].next = n; | 243 | |
211 | q->dep[x].prev = p; | 244 | q->dep[qlen].next = x; /* sfq_dep_head(q, p)->next = x */ |
212 | q->dep[p].next = q->dep[n].prev = x; | 245 | sfq_dep_head(q, n)->prev = x; |
213 | } | 246 | } |
214 | 247 | ||
248 | #define sfq_unlink(q, x, n, p) \ | ||
249 | n = q->slots[x].dep.next; \ | ||
250 | p = q->slots[x].dep.prev; \ | ||
251 | sfq_dep_head(q, p)->next = n; \ | ||
252 | sfq_dep_head(q, n)->prev = p | ||
253 | |||
254 | |||
215 | static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x) | 255 | static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x) |
216 | { | 256 | { |
217 | sfq_index p, n; | 257 | sfq_index p, n; |
258 | int d; | ||
218 | 259 | ||
219 | n = q->dep[x].next; | 260 | sfq_unlink(q, x, n, p); |
220 | p = q->dep[x].prev; | ||
221 | q->dep[p].next = n; | ||
222 | q->dep[n].prev = p; | ||
223 | |||
224 | if (n == p && q->max_depth == q->qs[x].qlen + 1) | ||
225 | q->max_depth--; | ||
226 | 261 | ||
262 | d = q->slots[x].qlen--; | ||
263 | if (n == p && q->cur_depth == d) | ||
264 | q->cur_depth--; | ||
227 | sfq_link(q, x); | 265 | sfq_link(q, x); |
228 | } | 266 | } |
229 | 267 | ||
@@ -232,34 +270,74 @@ static inline void sfq_inc(struct sfq_sched_data *q, sfq_index x) | |||
232 | sfq_index p, n; | 270 | sfq_index p, n; |
233 | int d; | 271 | int d; |
234 | 272 | ||
235 | n = q->dep[x].next; | 273 | sfq_unlink(q, x, n, p); |
236 | p = q->dep[x].prev; | ||
237 | q->dep[p].next = n; | ||
238 | q->dep[n].prev = p; | ||
239 | d = q->qs[x].qlen; | ||
240 | if (q->max_depth < d) | ||
241 | q->max_depth = d; | ||
242 | 274 | ||
275 | d = ++q->slots[x].qlen; | ||
276 | if (q->cur_depth < d) | ||
277 | q->cur_depth = d; | ||
243 | sfq_link(q, x); | 278 | sfq_link(q, x); |
244 | } | 279 | } |
245 | 280 | ||
281 | /* helper functions : might be changed when/if skb use a standard list_head */ | ||
282 | |||
283 | /* remove one skb from tail of slot queue */ | ||
284 | static inline struct sk_buff *slot_dequeue_tail(struct sfq_slot *slot) | ||
285 | { | ||
286 | struct sk_buff *skb = slot->skblist_prev; | ||
287 | |||
288 | slot->skblist_prev = skb->prev; | ||
289 | skb->prev->next = (struct sk_buff *)slot; | ||
290 | skb->next = skb->prev = NULL; | ||
291 | return skb; | ||
292 | } | ||
293 | |||
294 | /* remove one skb from head of slot queue */ | ||
295 | static inline struct sk_buff *slot_dequeue_head(struct sfq_slot *slot) | ||
296 | { | ||
297 | struct sk_buff *skb = slot->skblist_next; | ||
298 | |||
299 | slot->skblist_next = skb->next; | ||
300 | skb->next->prev = (struct sk_buff *)slot; | ||
301 | skb->next = skb->prev = NULL; | ||
302 | return skb; | ||
303 | } | ||
304 | |||
305 | static inline void slot_queue_init(struct sfq_slot *slot) | ||
306 | { | ||
307 | slot->skblist_prev = slot->skblist_next = (struct sk_buff *)slot; | ||
308 | } | ||
309 | |||
310 | /* add skb to slot queue (tail add) */ | ||
311 | static inline void slot_queue_add(struct sfq_slot *slot, struct sk_buff *skb) | ||
312 | { | ||
313 | skb->prev = slot->skblist_prev; | ||
314 | skb->next = (struct sk_buff *)slot; | ||
315 | slot->skblist_prev->next = skb; | ||
316 | slot->skblist_prev = skb; | ||
317 | } | ||
318 | |||
319 | #define slot_queue_walk(slot, skb) \ | ||
320 | for (skb = slot->skblist_next; \ | ||
321 | skb != (struct sk_buff *)slot; \ | ||
322 | skb = skb->next) | ||
323 | |||
246 | static unsigned int sfq_drop(struct Qdisc *sch) | 324 | static unsigned int sfq_drop(struct Qdisc *sch) |
247 | { | 325 | { |
248 | struct sfq_sched_data *q = qdisc_priv(sch); | 326 | struct sfq_sched_data *q = qdisc_priv(sch); |
249 | sfq_index d = q->max_depth; | 327 | sfq_index x, d = q->cur_depth; |
250 | struct sk_buff *skb; | 328 | struct sk_buff *skb; |
251 | unsigned int len; | 329 | unsigned int len; |
330 | struct sfq_slot *slot; | ||
252 | 331 | ||
253 | /* Queue is full! Find the longest slot and | 332 | /* Queue is full! Find the longest slot and drop tail packet from it */ |
254 | drop a packet from it */ | ||
255 | |||
256 | if (d > 1) { | 333 | if (d > 1) { |
257 | sfq_index x = q->dep[d + SFQ_DEPTH].next; | 334 | x = q->dep[d].next; |
258 | skb = q->qs[x].prev; | 335 | slot = &q->slots[x]; |
336 | drop: | ||
337 | skb = slot_dequeue_tail(slot); | ||
259 | len = qdisc_pkt_len(skb); | 338 | len = qdisc_pkt_len(skb); |
260 | __skb_unlink(skb, &q->qs[x]); | ||
261 | kfree_skb(skb); | ||
262 | sfq_dec(q, x); | 339 | sfq_dec(q, x); |
340 | kfree_skb(skb); | ||
263 | sch->q.qlen--; | 341 | sch->q.qlen--; |
264 | sch->qstats.drops++; | 342 | sch->qstats.drops++; |
265 | sch->qstats.backlog -= len; | 343 | sch->qstats.backlog -= len; |
@@ -268,18 +346,11 @@ static unsigned int sfq_drop(struct Qdisc *sch) | |||
268 | 346 | ||
269 | if (d == 1) { | 347 | if (d == 1) { |
270 | /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ | 348 | /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ |
271 | d = q->next[q->tail]; | 349 | x = q->tail->next; |
272 | q->next[q->tail] = q->next[d]; | 350 | slot = &q->slots[x]; |
273 | skb = q->qs[d].prev; | 351 | q->tail->next = slot->next; |
274 | len = qdisc_pkt_len(skb); | 352 | q->ht[slot->hash] = SFQ_EMPTY_SLOT; |
275 | __skb_unlink(skb, &q->qs[d]); | 353 | goto drop; |
276 | kfree_skb(skb); | ||
277 | sfq_dec(q, d); | ||
278 | sch->q.qlen--; | ||
279 | q->ht[q->hash[d]] = SFQ_DEPTH; | ||
280 | sch->qstats.drops++; | ||
281 | sch->qstats.backlog -= len; | ||
282 | return len; | ||
283 | } | 354 | } |
284 | 355 | ||
285 | return 0; | 356 | return 0; |
@@ -291,6 +362,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
291 | struct sfq_sched_data *q = qdisc_priv(sch); | 362 | struct sfq_sched_data *q = qdisc_priv(sch); |
292 | unsigned int hash; | 363 | unsigned int hash; |
293 | sfq_index x; | 364 | sfq_index x; |
365 | struct sfq_slot *slot; | ||
294 | int uninitialized_var(ret); | 366 | int uninitialized_var(ret); |
295 | 367 | ||
296 | hash = sfq_classify(skb, sch, &ret); | 368 | hash = sfq_classify(skb, sch, &ret); |
@@ -303,30 +375,32 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
303 | hash--; | 375 | hash--; |
304 | 376 | ||
305 | x = q->ht[hash]; | 377 | x = q->ht[hash]; |
306 | if (x == SFQ_DEPTH) { | 378 | slot = &q->slots[x]; |
307 | q->ht[hash] = x = q->dep[SFQ_DEPTH].next; | 379 | if (x == SFQ_EMPTY_SLOT) { |
308 | q->hash[x] = hash; | 380 | x = q->dep[0].next; /* get a free slot */ |
381 | q->ht[hash] = x; | ||
382 | slot = &q->slots[x]; | ||
383 | slot->hash = hash; | ||
309 | } | 384 | } |
310 | 385 | ||
311 | /* If selected queue has length q->limit, this means that | 386 | /* If selected queue has length q->limit, do simple tail drop, |
312 | * all another queues are empty and that we do simple tail drop, | ||
313 | * i.e. drop _this_ packet. | 387 | * i.e. drop _this_ packet. |
314 | */ | 388 | */ |
315 | if (q->qs[x].qlen >= q->limit) | 389 | if (slot->qlen >= q->limit) |
316 | return qdisc_drop(skb, sch); | 390 | return qdisc_drop(skb, sch); |
317 | 391 | ||
318 | sch->qstats.backlog += qdisc_pkt_len(skb); | 392 | sch->qstats.backlog += qdisc_pkt_len(skb); |
319 | __skb_queue_tail(&q->qs[x], skb); | 393 | slot_queue_add(slot, skb); |
320 | sfq_inc(q, x); | 394 | sfq_inc(q, x); |
321 | if (q->qs[x].qlen == 1) { /* The flow is new */ | 395 | if (slot->qlen == 1) { /* The flow is new */ |
322 | if (q->tail == SFQ_DEPTH) { /* It is the first flow */ | 396 | if (q->tail == NULL) { /* It is the first flow */ |
323 | q->next[x] = x; | 397 | slot->next = x; |
324 | } else { | 398 | } else { |
325 | q->next[x] = q->next[q->tail]; | 399 | slot->next = q->tail->next; |
326 | q->next[q->tail] = x; | 400 | q->tail->next = x; |
327 | } | 401 | } |
328 | q->tail = x; | 402 | q->tail = slot; |
329 | q->allot[x] = q->quantum; | 403 | slot->allot = q->scaled_quantum; |
330 | } | 404 | } |
331 | if (++sch->q.qlen <= q->limit) { | 405 | if (++sch->q.qlen <= q->limit) { |
332 | sch->bstats.bytes += qdisc_pkt_len(skb); | 406 | sch->bstats.bytes += qdisc_pkt_len(skb); |
@@ -342,14 +416,12 @@ static struct sk_buff * | |||
342 | sfq_peek(struct Qdisc *sch) | 416 | sfq_peek(struct Qdisc *sch) |
343 | { | 417 | { |
344 | struct sfq_sched_data *q = qdisc_priv(sch); | 418 | struct sfq_sched_data *q = qdisc_priv(sch); |
345 | sfq_index a; | ||
346 | 419 | ||
347 | /* No active slots */ | 420 | /* No active slots */ |
348 | if (q->tail == SFQ_DEPTH) | 421 | if (q->tail == NULL) |
349 | return NULL; | 422 | return NULL; |
350 | 423 | ||
351 | a = q->next[q->tail]; | 424 | return q->slots[q->tail->next].skblist_next; |
352 | return skb_peek(&q->qs[a]); | ||
353 | } | 425 | } |
354 | 426 | ||
355 | static struct sk_buff * | 427 | static struct sk_buff * |
@@ -358,31 +430,36 @@ sfq_dequeue(struct Qdisc *sch) | |||
358 | struct sfq_sched_data *q = qdisc_priv(sch); | 430 | struct sfq_sched_data *q = qdisc_priv(sch); |
359 | struct sk_buff *skb; | 431 | struct sk_buff *skb; |
360 | sfq_index a, next_a; | 432 | sfq_index a, next_a; |
433 | struct sfq_slot *slot; | ||
361 | 434 | ||
362 | /* No active slots */ | 435 | /* No active slots */ |
363 | if (q->tail == SFQ_DEPTH) | 436 | if (q->tail == NULL) |
364 | return NULL; | 437 | return NULL; |
365 | 438 | ||
366 | a = q->next[q->tail]; | 439 | next_slot: |
367 | 440 | a = q->tail->next; | |
368 | /* Grab packet */ | 441 | slot = &q->slots[a]; |
369 | skb = __skb_dequeue(&q->qs[a]); | 442 | if (slot->allot <= 0) { |
443 | q->tail = slot; | ||
444 | slot->allot += q->scaled_quantum; | ||
445 | goto next_slot; | ||
446 | } | ||
447 | skb = slot_dequeue_head(slot); | ||
370 | sfq_dec(q, a); | 448 | sfq_dec(q, a); |
371 | sch->q.qlen--; | 449 | sch->q.qlen--; |
372 | sch->qstats.backlog -= qdisc_pkt_len(skb); | 450 | sch->qstats.backlog -= qdisc_pkt_len(skb); |
373 | 451 | ||
374 | /* Is the slot empty? */ | 452 | /* Is the slot empty? */ |
375 | if (q->qs[a].qlen == 0) { | 453 | if (slot->qlen == 0) { |
376 | q->ht[q->hash[a]] = SFQ_DEPTH; | 454 | q->ht[slot->hash] = SFQ_EMPTY_SLOT; |
377 | next_a = q->next[a]; | 455 | next_a = slot->next; |
378 | if (a == next_a) { | 456 | if (a == next_a) { |
379 | q->tail = SFQ_DEPTH; | 457 | q->tail = NULL; /* no more active slots */ |
380 | return skb; | 458 | return skb; |
381 | } | 459 | } |
382 | q->next[q->tail] = next_a; | 460 | q->tail->next = next_a; |
383 | } else if ((q->allot[a] -= qdisc_pkt_len(skb)) <= 0) { | 461 | } else { |
384 | q->allot[a] += q->quantum; | 462 | slot->allot -= SFQ_ALLOT_SIZE(qdisc_pkt_len(skb)); |
385 | q->tail = a; | ||
386 | } | 463 | } |
387 | return skb; | 464 | return skb; |
388 | } | 465 | } |
@@ -418,6 +495,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) | |||
418 | 495 | ||
419 | sch_tree_lock(sch); | 496 | sch_tree_lock(sch); |
420 | q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch)); | 497 | q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch)); |
498 | q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); | ||
421 | q->perturb_period = ctl->perturb_period * HZ; | 499 | q->perturb_period = ctl->perturb_period * HZ; |
422 | if (ctl->limit) | 500 | if (ctl->limit) |
423 | q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1); | 501 | q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1); |
@@ -446,19 +524,19 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt) | |||
446 | init_timer_deferrable(&q->perturb_timer); | 524 | init_timer_deferrable(&q->perturb_timer); |
447 | 525 | ||
448 | for (i = 0; i < SFQ_HASH_DIVISOR; i++) | 526 | for (i = 0; i < SFQ_HASH_DIVISOR; i++) |
449 | q->ht[i] = SFQ_DEPTH; | 527 | q->ht[i] = SFQ_EMPTY_SLOT; |
450 | 528 | ||
451 | for (i = 0; i < SFQ_DEPTH; i++) { | 529 | for (i = 0; i < SFQ_DEPTH; i++) { |
452 | skb_queue_head_init(&q->qs[i]); | 530 | q->dep[i].next = i + SFQ_SLOTS; |
453 | q->dep[i + SFQ_DEPTH].next = i + SFQ_DEPTH; | 531 | q->dep[i].prev = i + SFQ_SLOTS; |
454 | q->dep[i + SFQ_DEPTH].prev = i + SFQ_DEPTH; | ||
455 | } | 532 | } |
456 | 533 | ||
457 | q->limit = SFQ_DEPTH - 1; | 534 | q->limit = SFQ_DEPTH - 1; |
458 | q->max_depth = 0; | 535 | q->cur_depth = 0; |
459 | q->tail = SFQ_DEPTH; | 536 | q->tail = NULL; |
460 | if (opt == NULL) { | 537 | if (opt == NULL) { |
461 | q->quantum = psched_mtu(qdisc_dev(sch)); | 538 | q->quantum = psched_mtu(qdisc_dev(sch)); |
539 | q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); | ||
462 | q->perturb_period = 0; | 540 | q->perturb_period = 0; |
463 | q->perturbation = net_random(); | 541 | q->perturbation = net_random(); |
464 | } else { | 542 | } else { |
@@ -467,8 +545,10 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt) | |||
467 | return err; | 545 | return err; |
468 | } | 546 | } |
469 | 547 | ||
470 | for (i = 0; i < SFQ_DEPTH; i++) | 548 | for (i = 0; i < SFQ_SLOTS; i++) { |
549 | slot_queue_init(&q->slots[i]); | ||
471 | sfq_link(q, i); | 550 | sfq_link(q, i); |
551 | } | ||
472 | return 0; | 552 | return 0; |
473 | } | 553 | } |
474 | 554 | ||
@@ -543,10 +623,19 @@ static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl, | |||
543 | struct gnet_dump *d) | 623 | struct gnet_dump *d) |
544 | { | 624 | { |
545 | struct sfq_sched_data *q = qdisc_priv(sch); | 625 | struct sfq_sched_data *q = qdisc_priv(sch); |
546 | sfq_index idx = q->ht[cl-1]; | 626 | sfq_index idx = q->ht[cl - 1]; |
547 | struct gnet_stats_queue qs = { .qlen = q->qs[idx].qlen }; | 627 | struct gnet_stats_queue qs = { 0 }; |
548 | struct tc_sfq_xstats xstats = { .allot = q->allot[idx] }; | 628 | struct tc_sfq_xstats xstats = { 0 }; |
629 | struct sk_buff *skb; | ||
630 | |||
631 | if (idx != SFQ_EMPTY_SLOT) { | ||
632 | const struct sfq_slot *slot = &q->slots[idx]; | ||
549 | 633 | ||
634 | xstats.allot = slot->allot << SFQ_ALLOT_SHIFT; | ||
635 | qs.qlen = slot->qlen; | ||
636 | slot_queue_walk(slot, skb) | ||
637 | qs.backlog += qdisc_pkt_len(skb); | ||
638 | } | ||
550 | if (gnet_stats_copy_queue(d, &qs) < 0) | 639 | if (gnet_stats_copy_queue(d, &qs) < 0) |
551 | return -1; | 640 | return -1; |
552 | return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); | 641 | return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); |
@@ -561,7 +650,7 @@ static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) | |||
561 | return; | 650 | return; |
562 | 651 | ||
563 | for (i = 0; i < SFQ_HASH_DIVISOR; i++) { | 652 | for (i = 0; i < SFQ_HASH_DIVISOR; i++) { |
564 | if (q->ht[i] == SFQ_DEPTH || | 653 | if (q->ht[i] == SFQ_EMPTY_SLOT || |
565 | arg->count < arg->skip) { | 654 | arg->count < arg->skip) { |
566 | arg->count++; | 655 | arg->count++; |
567 | continue; | 656 | continue; |
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 401af9596709..106479a7c94a 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c | |||
@@ -309,8 +309,7 @@ restart: | |||
309 | if (__netif_tx_trylock(slave_txq)) { | 309 | if (__netif_tx_trylock(slave_txq)) { |
310 | unsigned int length = qdisc_pkt_len(skb); | 310 | unsigned int length = qdisc_pkt_len(skb); |
311 | 311 | ||
312 | if (!netif_tx_queue_stopped(slave_txq) && | 312 | if (!netif_tx_queue_frozen_or_stopped(slave_txq) && |
313 | !netif_tx_queue_frozen(slave_txq) && | ||
314 | slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) { | 313 | slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) { |
315 | txq_trans_update(slave_txq); | 314 | txq_trans_update(slave_txq); |
316 | __netif_tx_unlock(slave_txq); | 315 | __netif_tx_unlock(slave_txq); |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fff0926b1111..a09b0dd25f50 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -6055,7 +6055,7 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, | |||
6055 | * will suddenly eat the receive_queue. | 6055 | * will suddenly eat the receive_queue. |
6056 | * | 6056 | * |
6057 | * Look at current nfs client by the way... | 6057 | * Look at current nfs client by the way... |
6058 | * However, this function was corrent in any case. 8) | 6058 | * However, this function was correct in any case. 8) |
6059 | */ | 6059 | */ |
6060 | if (flags & MSG_PEEK) { | 6060 | if (flags & MSG_PEEK) { |
6061 | spin_lock_bh(&sk->sk_receive_queue.lock); | 6061 | spin_lock_bh(&sk->sk_receive_queue.lock); |
diff --git a/net/socket.c b/net/socket.c index 088fb3fd45e0..c1663c0ff3d3 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -156,7 +156,7 @@ static const struct file_operations socket_file_ops = { | |||
156 | */ | 156 | */ |
157 | 157 | ||
158 | static DEFINE_SPINLOCK(net_family_lock); | 158 | static DEFINE_SPINLOCK(net_family_lock); |
159 | static const struct net_proto_family *net_families[NPROTO] __read_mostly; | 159 | static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly; |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Statistics counters of the socket lists | 162 | * Statistics counters of the socket lists |
@@ -1215,7 +1215,7 @@ int __sock_create(struct net *net, int family, int type, int protocol, | |||
1215 | * requested real, full-featured networking support upon configuration. | 1215 | * requested real, full-featured networking support upon configuration. |
1216 | * Otherwise module support will break! | 1216 | * Otherwise module support will break! |
1217 | */ | 1217 | */ |
1218 | if (net_families[family] == NULL) | 1218 | if (rcu_access_pointer(net_families[family]) == NULL) |
1219 | request_module("net-pf-%d", family); | 1219 | request_module("net-pf-%d", family); |
1220 | #endif | 1220 | #endif |
1221 | 1221 | ||
@@ -2347,10 +2347,11 @@ int sock_register(const struct net_proto_family *ops) | |||
2347 | } | 2347 | } |
2348 | 2348 | ||
2349 | spin_lock(&net_family_lock); | 2349 | spin_lock(&net_family_lock); |
2350 | if (net_families[ops->family]) | 2350 | if (rcu_dereference_protected(net_families[ops->family], |
2351 | lockdep_is_held(&net_family_lock))) | ||
2351 | err = -EEXIST; | 2352 | err = -EEXIST; |
2352 | else { | 2353 | else { |
2353 | net_families[ops->family] = ops; | 2354 | rcu_assign_pointer(net_families[ops->family], ops); |
2354 | err = 0; | 2355 | err = 0; |
2355 | } | 2356 | } |
2356 | spin_unlock(&net_family_lock); | 2357 | spin_unlock(&net_family_lock); |
@@ -2378,7 +2379,7 @@ void sock_unregister(int family) | |||
2378 | BUG_ON(family < 0 || family >= NPROTO); | 2379 | BUG_ON(family < 0 || family >= NPROTO); |
2379 | 2380 | ||
2380 | spin_lock(&net_family_lock); | 2381 | spin_lock(&net_family_lock); |
2381 | net_families[family] = NULL; | 2382 | rcu_assign_pointer(net_families[family], NULL); |
2382 | spin_unlock(&net_family_lock); | 2383 | spin_unlock(&net_family_lock); |
2383 | 2384 | ||
2384 | synchronize_rcu(); | 2385 | synchronize_rcu(); |
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile index 7350d86a32ee..9e4cb59ef9f0 100644 --- a/net/sunrpc/auth_gss/Makefile +++ b/net/sunrpc/auth_gss/Makefile | |||
@@ -4,10 +4,10 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o | 5 | obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o |
6 | 6 | ||
7 | auth_rpcgss-objs := auth_gss.o gss_generic_token.o \ | 7 | auth_rpcgss-y := auth_gss.o gss_generic_token.o \ |
8 | gss_mech_switch.o svcauth_gss.o | 8 | gss_mech_switch.o svcauth_gss.o |
9 | 9 | ||
10 | obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o | 10 | obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o |
11 | 11 | ||
12 | rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ | 12 | rpcsec_gss_krb5-y := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ |
13 | gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o | 13 | gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o |
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index b74f78d0c033..0436927369f3 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig | |||
@@ -29,28 +29,6 @@ config TIPC_ADVANCED | |||
29 | Saying Y here will open some advanced configuration for TIPC. | 29 | Saying Y here will open some advanced configuration for TIPC. |
30 | Most users do not need to bother; if unsure, just say N. | 30 | Most users do not need to bother; if unsure, just say N. |
31 | 31 | ||
32 | config TIPC_ZONES | ||
33 | int "Maximum number of zones in a network" | ||
34 | depends on TIPC_ADVANCED | ||
35 | range 1 255 | ||
36 | default "3" | ||
37 | help | ||
38 | Specifies how many zones can be supported in a TIPC network. | ||
39 | Can range from 1 to 255 zones; default is 3. | ||
40 | |||
41 | Setting this to a smaller value saves some memory; | ||
42 | setting it to a higher value allows for more zones. | ||
43 | |||
44 | config TIPC_CLUSTERS | ||
45 | int "Maximum number of clusters in a zone" | ||
46 | depends on TIPC_ADVANCED | ||
47 | range 1 1 | ||
48 | default "1" | ||
49 | help | ||
50 | Specifies how many clusters can be supported in a TIPC zone. | ||
51 | |||
52 | *** Currently TIPC only supports a single cluster per zone. *** | ||
53 | |||
54 | config TIPC_NODES | 32 | config TIPC_NODES |
55 | int "Maximum number of nodes in a cluster" | 33 | int "Maximum number of nodes in a cluster" |
56 | depends on TIPC_ADVANCED | 34 | depends on TIPC_ADVANCED |
@@ -72,7 +50,7 @@ config TIPC_PORTS | |||
72 | Specifies how many ports can be supported by a node. | 50 | Specifies how many ports can be supported by a node. |
73 | Can range from 127 to 65535 ports; default is 8191. | 51 | Can range from 127 to 65535 ports; default is 8191. |
74 | 52 | ||
75 | Setting this to a smaller value saves some memory, | 53 | Setting this to a smaller value saves some memory, |
76 | setting it to higher allows for more ports. | 54 | setting it to higher allows for more ports. |
77 | 55 | ||
78 | config TIPC_LOG | 56 | config TIPC_LOG |
@@ -89,12 +67,15 @@ config TIPC_LOG | |||
89 | managed remotely via TIPC. | 67 | managed remotely via TIPC. |
90 | 68 | ||
91 | config TIPC_DEBUG | 69 | config TIPC_DEBUG |
92 | bool "Enable debug messages" | 70 | bool "Enable debugging support" |
93 | default n | 71 | default n |
94 | help | 72 | help |
95 | This enables debugging of TIPC. | 73 | Saying Y here enables TIPC debugging capabilities used by developers. |
74 | Most users do not need to bother; if unsure, just say N. | ||
96 | 75 | ||
97 | Only say Y here if you are having trouble with TIPC. It will | 76 | Enabling debugging support causes TIPC to display data about its |
98 | enable the display of detailed information about what is going on. | 77 | internal state when certain abnormal conditions occur. It also |
78 | makes it easy for developers to capture additional information of | ||
79 | interest using the dbg() or msg_dbg() macros. | ||
99 | 80 | ||
100 | endif # TIPC | 81 | endif # TIPC |
diff --git a/net/tipc/Makefile b/net/tipc/Makefile index dceb7027946c..521d24d04ab2 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile | |||
@@ -4,10 +4,10 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_TIPC) := tipc.o | 5 | obj-$(CONFIG_TIPC) := tipc.o |
6 | 6 | ||
7 | tipc-y += addr.o bcast.o bearer.o config.o cluster.o \ | 7 | tipc-y += addr.o bcast.o bearer.o config.o \ |
8 | core.o handler.o link.o discover.o msg.o \ | 8 | core.o handler.o link.o discover.o msg.o \ |
9 | name_distr.o subscr.o name_table.o net.o \ | 9 | name_distr.o subscr.o name_table.o net.o \ |
10 | netlink.o node.o node_subscr.o port.o ref.o \ | 10 | netlink.o node.o node_subscr.o port.o ref.o \ |
11 | socket.o user_reg.o zone.o dbg.o eth_media.o | 11 | socket.o log.o eth_media.o |
12 | 12 | ||
13 | # End of file | 13 | # End of file |
diff --git a/net/tipc/addr.c b/net/tipc/addr.c index 8a2e89bffde5..88463d9a6f12 100644 --- a/net/tipc/addr.c +++ b/net/tipc/addr.c | |||
@@ -35,11 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "dbg.h" | ||
39 | #include "addr.h" | 38 | #include "addr.h" |
40 | #include "zone.h" | ||
41 | #include "cluster.h" | ||
42 | #include "net.h" | ||
43 | 39 | ||
44 | /** | 40 | /** |
45 | * tipc_addr_domain_valid - validates a network domain address | 41 | * tipc_addr_domain_valid - validates a network domain address |
@@ -57,14 +53,8 @@ int tipc_addr_domain_valid(u32 addr) | |||
57 | u32 z = tipc_zone(addr); | 53 | u32 z = tipc_zone(addr); |
58 | u32 max_nodes = tipc_max_nodes; | 54 | u32 max_nodes = tipc_max_nodes; |
59 | 55 | ||
60 | if (is_slave(addr)) | ||
61 | max_nodes = LOWEST_SLAVE + tipc_max_slaves; | ||
62 | if (n > max_nodes) | 56 | if (n > max_nodes) |
63 | return 0; | 57 | return 0; |
64 | if (c > tipc_max_clusters) | ||
65 | return 0; | ||
66 | if (z > tipc_max_zones) | ||
67 | return 0; | ||
68 | 58 | ||
69 | if (n && (!z || !c)) | 59 | if (n && (!z || !c)) |
70 | return 0; | 60 | return 0; |
diff --git a/net/tipc/addr.h b/net/tipc/addr.h index c1cc5724d8cc..2490fadd0caf 100644 --- a/net/tipc/addr.h +++ b/net/tipc/addr.h | |||
@@ -37,36 +37,11 @@ | |||
37 | #ifndef _TIPC_ADDR_H | 37 | #ifndef _TIPC_ADDR_H |
38 | #define _TIPC_ADDR_H | 38 | #define _TIPC_ADDR_H |
39 | 39 | ||
40 | static inline u32 own_node(void) | ||
41 | { | ||
42 | return tipc_node(tipc_own_addr); | ||
43 | } | ||
44 | |||
45 | static inline u32 own_cluster(void) | ||
46 | { | ||
47 | return tipc_cluster(tipc_own_addr); | ||
48 | } | ||
49 | |||
50 | static inline u32 own_zone(void) | ||
51 | { | ||
52 | return tipc_zone(tipc_own_addr); | ||
53 | } | ||
54 | |||
55 | static inline int in_own_cluster(u32 addr) | 40 | static inline int in_own_cluster(u32 addr) |
56 | { | 41 | { |
57 | return !((addr ^ tipc_own_addr) >> 12); | 42 | return !((addr ^ tipc_own_addr) >> 12); |
58 | } | 43 | } |
59 | 44 | ||
60 | static inline int is_slave(u32 addr) | ||
61 | { | ||
62 | return addr & 0x800; | ||
63 | } | ||
64 | |||
65 | static inline int may_route(u32 addr) | ||
66 | { | ||
67 | return(addr ^ tipc_own_addr) >> 11; | ||
68 | } | ||
69 | |||
70 | /** | 45 | /** |
71 | * addr_domain - convert 2-bit scope value to equivalent message lookup domain | 46 | * addr_domain - convert 2-bit scope value to equivalent message lookup domain |
72 | * | 47 | * |
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 22a60fc98392..70ab5ef48766 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
@@ -36,25 +36,14 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include "core.h" | 38 | #include "core.h" |
39 | #include "msg.h" | ||
40 | #include "dbg.h" | ||
41 | #include "link.h" | 39 | #include "link.h" |
42 | #include "net.h" | ||
43 | #include "node.h" | ||
44 | #include "port.h" | 40 | #include "port.h" |
45 | #include "addr.h" | ||
46 | #include "node_subscr.h" | ||
47 | #include "name_distr.h" | ||
48 | #include "bearer.h" | ||
49 | #include "name_table.h" | ||
50 | #include "bcast.h" | 41 | #include "bcast.h" |
51 | 42 | ||
52 | #define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */ | 43 | #define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */ |
53 | 44 | ||
54 | #define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ | 45 | #define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ |
55 | 46 | ||
56 | #define BCLINK_LOG_BUF_SIZE 0 | ||
57 | |||
58 | /* | 47 | /* |
59 | * Loss rate for incoming broadcast frames; used to test retransmission code. | 48 | * Loss rate for incoming broadcast frames; used to test retransmission code. |
60 | * Set to N to cause every N'th frame to be discarded; 0 => don't discard any. | 49 | * Set to N to cause every N'th frame to be discarded; 0 => don't discard any. |
@@ -114,11 +103,14 @@ struct bclink { | |||
114 | }; | 103 | }; |
115 | 104 | ||
116 | 105 | ||
117 | static struct bcbearer *bcbearer = NULL; | 106 | static struct bcbearer *bcbearer; |
118 | static struct bclink *bclink = NULL; | 107 | static struct bclink *bclink; |
119 | static struct link *bcl = NULL; | 108 | static struct link *bcl; |
120 | static DEFINE_SPINLOCK(bc_lock); | 109 | static DEFINE_SPINLOCK(bc_lock); |
121 | 110 | ||
111 | /* broadcast-capable node map */ | ||
112 | struct tipc_node_map tipc_bcast_nmap; | ||
113 | |||
122 | const char tipc_bclink_name[] = "broadcast-link"; | 114 | const char tipc_bclink_name[] = "broadcast-link"; |
123 | 115 | ||
124 | static void tipc_nmap_diff(struct tipc_node_map *nm_a, | 116 | static void tipc_nmap_diff(struct tipc_node_map *nm_a, |
@@ -204,9 +196,8 @@ static void bclink_retransmit_pkt(u32 after, u32 to) | |||
204 | struct sk_buff *buf; | 196 | struct sk_buff *buf; |
205 | 197 | ||
206 | buf = bcl->first_out; | 198 | buf = bcl->first_out; |
207 | while (buf && less_eq(buf_seqno(buf), after)) { | 199 | while (buf && less_eq(buf_seqno(buf), after)) |
208 | buf = buf->next; | 200 | buf = buf->next; |
209 | } | ||
210 | tipc_link_retransmit(bcl, buf, mod(to - after)); | 201 | tipc_link_retransmit(bcl, buf, mod(to - after)); |
211 | } | 202 | } |
212 | 203 | ||
@@ -232,9 +223,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) | |||
232 | /* Skip over packets that node has previously acknowledged */ | 223 | /* Skip over packets that node has previously acknowledged */ |
233 | 224 | ||
234 | crs = bcl->first_out; | 225 | crs = bcl->first_out; |
235 | while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked)) { | 226 | while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked)) |
236 | crs = crs->next; | 227 | crs = crs->next; |
237 | } | ||
238 | 228 | ||
239 | /* Update packets that node is now acknowledging */ | 229 | /* Update packets that node is now acknowledging */ |
240 | 230 | ||
@@ -433,16 +423,14 @@ int tipc_bclink_send_msg(struct sk_buff *buf) | |||
433 | void tipc_bclink_recv_pkt(struct sk_buff *buf) | 423 | void tipc_bclink_recv_pkt(struct sk_buff *buf) |
434 | { | 424 | { |
435 | #if (TIPC_BCAST_LOSS_RATE) | 425 | #if (TIPC_BCAST_LOSS_RATE) |
436 | static int rx_count = 0; | 426 | static int rx_count; |
437 | #endif | 427 | #endif |
438 | struct tipc_msg *msg = buf_msg(buf); | 428 | struct tipc_msg *msg = buf_msg(buf); |
439 | struct tipc_node* node = tipc_node_find(msg_prevnode(msg)); | 429 | struct tipc_node *node = tipc_node_find(msg_prevnode(msg)); |
440 | u32 next_in; | 430 | u32 next_in; |
441 | u32 seqno; | 431 | u32 seqno; |
442 | struct sk_buff *deferred; | 432 | struct sk_buff *deferred; |
443 | 433 | ||
444 | msg_dbg(msg, "<BC<<<"); | ||
445 | |||
446 | if (unlikely(!node || !tipc_node_is_up(node) || !node->bclink.supported || | 434 | if (unlikely(!node || !tipc_node_is_up(node) || !node->bclink.supported || |
447 | (msg_mc_netid(msg) != tipc_net_id))) { | 435 | (msg_mc_netid(msg) != tipc_net_id))) { |
448 | buf_discard(buf); | 436 | buf_discard(buf); |
@@ -450,7 +438,6 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) | |||
450 | } | 438 | } |
451 | 439 | ||
452 | if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { | 440 | if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { |
453 | msg_dbg(msg, "<BCNACK<<<"); | ||
454 | if (msg_destnode(msg) == tipc_own_addr) { | 441 | if (msg_destnode(msg) == tipc_own_addr) { |
455 | tipc_node_lock(node); | 442 | tipc_node_lock(node); |
456 | tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); | 443 | tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); |
@@ -574,8 +561,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf, | |||
574 | if (likely(!msg_non_seq(buf_msg(buf)))) { | 561 | if (likely(!msg_non_seq(buf_msg(buf)))) { |
575 | struct tipc_msg *msg; | 562 | struct tipc_msg *msg; |
576 | 563 | ||
577 | assert(tipc_cltr_bcast_nodes.count != 0); | 564 | assert(tipc_bcast_nmap.count != 0); |
578 | bcbuf_set_acks(buf, tipc_cltr_bcast_nodes.count); | 565 | bcbuf_set_acks(buf, tipc_bcast_nmap.count); |
579 | msg = buf_msg(buf); | 566 | msg = buf_msg(buf); |
580 | msg_set_non_seq(msg, 1); | 567 | msg_set_non_seq(msg, 1); |
581 | msg_set_mc_netid(msg, tipc_net_id); | 568 | msg_set_mc_netid(msg, tipc_net_id); |
@@ -584,7 +571,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, | |||
584 | 571 | ||
585 | /* Send buffer over bearers until all targets reached */ | 572 | /* Send buffer over bearers until all targets reached */ |
586 | 573 | ||
587 | bcbearer->remains = tipc_cltr_bcast_nodes; | 574 | bcbearer->remains = tipc_bcast_nmap; |
588 | 575 | ||
589 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { | 576 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { |
590 | struct bearer *p = bcbearer->bpairs[bp_index].primary; | 577 | struct bearer *p = bcbearer->bpairs[bp_index].primary; |
@@ -782,7 +769,6 @@ int tipc_bclink_init(void) | |||
782 | bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC); | 769 | bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC); |
783 | bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC); | 770 | bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC); |
784 | if (!bcbearer || !bclink) { | 771 | if (!bcbearer || !bclink) { |
785 | nomem: | ||
786 | warn("Multicast link creation failed, no memory\n"); | 772 | warn("Multicast link creation failed, no memory\n"); |
787 | kfree(bcbearer); | 773 | kfree(bcbearer); |
788 | bcbearer = NULL; | 774 | bcbearer = NULL; |
@@ -807,14 +793,6 @@ int tipc_bclink_init(void) | |||
807 | bcl->state = WORKING_WORKING; | 793 | bcl->state = WORKING_WORKING; |
808 | strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME); | 794 | strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME); |
809 | 795 | ||
810 | if (BCLINK_LOG_BUF_SIZE) { | ||
811 | char *pb = kmalloc(BCLINK_LOG_BUF_SIZE, GFP_ATOMIC); | ||
812 | |||
813 | if (!pb) | ||
814 | goto nomem; | ||
815 | tipc_printbuf_init(&bcl->print_buf, pb, BCLINK_LOG_BUF_SIZE); | ||
816 | } | ||
817 | |||
818 | return 0; | 796 | return 0; |
819 | } | 797 | } |
820 | 798 | ||
@@ -823,8 +801,6 @@ void tipc_bclink_stop(void) | |||
823 | spin_lock_bh(&bc_lock); | 801 | spin_lock_bh(&bc_lock); |
824 | if (bcbearer) { | 802 | if (bcbearer) { |
825 | tipc_link_stop(bcl); | 803 | tipc_link_stop(bcl); |
826 | if (BCLINK_LOG_BUF_SIZE) | ||
827 | kfree(bcl->print_buf.buf); | ||
828 | bcl = NULL; | 804 | bcl = NULL; |
829 | kfree(bclink); | 805 | kfree(bclink); |
830 | bclink = NULL; | 806 | bclink = NULL; |
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 011c03f0a4ab..51f8c5326ce6 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h | |||
@@ -51,6 +51,7 @@ struct tipc_node_map { | |||
51 | u32 map[MAX_NODES / WSIZE]; | 51 | u32 map[MAX_NODES / WSIZE]; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | extern struct tipc_node_map tipc_bcast_nmap; | ||
54 | 55 | ||
55 | #define PLSIZE 32 | 56 | #define PLSIZE 32 |
56 | 57 | ||
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 9927d1d56c4f..837b7a467885 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c | |||
@@ -36,17 +36,13 @@ | |||
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "config.h" | 38 | #include "config.h" |
39 | #include "dbg.h" | ||
40 | #include "bearer.h" | 39 | #include "bearer.h" |
41 | #include "link.h" | ||
42 | #include "port.h" | ||
43 | #include "discover.h" | 40 | #include "discover.h" |
44 | #include "bcast.h" | ||
45 | 41 | ||
46 | #define MAX_ADDR_STR 32 | 42 | #define MAX_ADDR_STR 32 |
47 | 43 | ||
48 | static struct media media_list[MAX_MEDIA]; | 44 | static struct media media_list[MAX_MEDIA]; |
49 | static u32 media_count = 0; | 45 | static u32 media_count; |
50 | 46 | ||
51 | struct bearer tipc_bearers[MAX_BEARERS]; | 47 | struct bearer tipc_bearers[MAX_BEARERS]; |
52 | 48 | ||
@@ -167,7 +163,6 @@ int tipc_register_media(u32 media_type, | |||
167 | m_ptr->priority = bearer_priority; | 163 | m_ptr->priority = bearer_priority; |
168 | m_ptr->tolerance = link_tolerance; | 164 | m_ptr->tolerance = link_tolerance; |
169 | m_ptr->window = send_window_limit; | 165 | m_ptr->window = send_window_limit; |
170 | dbg("Media <%s> registered\n", name); | ||
171 | res = 0; | 166 | res = 0; |
172 | exit: | 167 | exit: |
173 | write_unlock_bh(&tipc_net_lock); | 168 | write_unlock_bh(&tipc_net_lock); |
@@ -199,9 +194,8 @@ void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a) | |||
199 | unchar *addr = (unchar *)&a->dev_addr; | 194 | unchar *addr = (unchar *)&a->dev_addr; |
200 | 195 | ||
201 | tipc_printf(pb, "UNKNOWN(%u)", media_type); | 196 | tipc_printf(pb, "UNKNOWN(%u)", media_type); |
202 | for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) { | 197 | for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) |
203 | tipc_printf(pb, "-%02x", addr[i]); | 198 | tipc_printf(pb, "-%02x", addr[i]); |
204 | } | ||
205 | } | 199 | } |
206 | } | 200 | } |
207 | 201 | ||
@@ -256,7 +250,8 @@ static int bearer_name_validate(const char *name, | |||
256 | /* ensure all component parts of bearer name are present */ | 250 | /* ensure all component parts of bearer name are present */ |
257 | 251 | ||
258 | media_name = name_copy; | 252 | media_name = name_copy; |
259 | if ((if_name = strchr(media_name, ':')) == NULL) | 253 | if_name = strchr(media_name, ':'); |
254 | if (if_name == NULL) | ||
260 | return 0; | 255 | return 0; |
261 | *(if_name++) = 0; | 256 | *(if_name++) = 0; |
262 | media_len = if_name - media_name; | 257 | media_len = if_name - media_name; |
@@ -625,7 +620,7 @@ int tipc_block_bearer(const char *name) | |||
625 | * Note: This routine assumes caller holds tipc_net_lock. | 620 | * Note: This routine assumes caller holds tipc_net_lock. |
626 | */ | 621 | */ |
627 | 622 | ||
628 | static int bearer_disable(struct bearer *b_ptr) | 623 | static void bearer_disable(struct bearer *b_ptr) |
629 | { | 624 | { |
630 | struct link *l_ptr; | 625 | struct link *l_ptr; |
631 | struct link *temp_l_ptr; | 626 | struct link *temp_l_ptr; |
@@ -641,7 +636,6 @@ static int bearer_disable(struct bearer *b_ptr) | |||
641 | } | 636 | } |
642 | spin_unlock_bh(&b_ptr->publ.lock); | 637 | spin_unlock_bh(&b_ptr->publ.lock); |
643 | memset(b_ptr, 0, sizeof(struct bearer)); | 638 | memset(b_ptr, 0, sizeof(struct bearer)); |
644 | return 0; | ||
645 | } | 639 | } |
646 | 640 | ||
647 | int tipc_disable_bearer(const char *name) | 641 | int tipc_disable_bearer(const char *name) |
@@ -654,8 +648,10 @@ int tipc_disable_bearer(const char *name) | |||
654 | if (b_ptr == NULL) { | 648 | if (b_ptr == NULL) { |
655 | warn("Attempt to disable unknown bearer <%s>\n", name); | 649 | warn("Attempt to disable unknown bearer <%s>\n", name); |
656 | res = -EINVAL; | 650 | res = -EINVAL; |
657 | } else | 651 | } else { |
658 | res = bearer_disable(b_ptr); | 652 | bearer_disable(b_ptr); |
653 | res = 0; | ||
654 | } | ||
659 | write_unlock_bh(&tipc_net_lock); | 655 | write_unlock_bh(&tipc_net_lock); |
660 | return res; | 656 | return res; |
661 | } | 657 | } |
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index a850b389663e..85f451d5aacf 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h | |||
@@ -37,12 +37,50 @@ | |||
37 | #ifndef _TIPC_BEARER_H | 37 | #ifndef _TIPC_BEARER_H |
38 | #define _TIPC_BEARER_H | 38 | #define _TIPC_BEARER_H |
39 | 39 | ||
40 | #include "core.h" | ||
41 | #include "bcast.h" | 40 | #include "bcast.h" |
42 | 41 | ||
43 | #define MAX_BEARERS 8 | 42 | #define MAX_BEARERS 8 |
44 | #define MAX_MEDIA 4 | 43 | #define MAX_MEDIA 4 |
45 | 44 | ||
45 | /* | ||
46 | * Identifiers of supported TIPC media types | ||
47 | */ | ||
48 | #define TIPC_MEDIA_TYPE_ETH 1 | ||
49 | |||
50 | /* | ||
51 | * Destination address structure used by TIPC bearers when sending messages | ||
52 | * | ||
53 | * IMPORTANT: The fields of this structure MUST be stored using the specified | ||
54 | * byte order indicated below, as the structure is exchanged between nodes | ||
55 | * as part of a link setup process. | ||
56 | */ | ||
57 | struct tipc_media_addr { | ||
58 | __be32 type; /* bearer type (network byte order) */ | ||
59 | union { | ||
60 | __u8 eth_addr[6]; /* 48 bit Ethernet addr (byte array) */ | ||
61 | } dev_addr; | ||
62 | }; | ||
63 | |||
64 | /** | ||
65 | * struct tipc_bearer - TIPC bearer info available to media code | ||
66 | * @usr_handle: pointer to additional media-specific information about bearer | ||
67 | * @mtu: max packet size bearer can support | ||
68 | * @blocked: non-zero if bearer is blocked | ||
69 | * @lock: spinlock for controlling access to bearer | ||
70 | * @addr: media-specific address associated with bearer | ||
71 | * @name: bearer name (format = media:interface) | ||
72 | * | ||
73 | * Note: TIPC initializes "name" and "lock" fields; media code is responsible | ||
74 | * for initialization all other fields when a bearer is enabled. | ||
75 | */ | ||
76 | struct tipc_bearer { | ||
77 | void *usr_handle; | ||
78 | u32 mtu; | ||
79 | int blocked; | ||
80 | spinlock_t lock; | ||
81 | struct tipc_media_addr addr; | ||
82 | char name[TIPC_MAX_BEARER_NAME]; | ||
83 | }; | ||
46 | 84 | ||
47 | /** | 85 | /** |
48 | * struct media - TIPC media information available to internal users | 86 | * struct media - TIPC media information available to internal users |
@@ -55,7 +93,7 @@ | |||
55 | * @priority: default link (and bearer) priority | 93 | * @priority: default link (and bearer) priority |
56 | * @tolerance: default time (in ms) before declaring link failure | 94 | * @tolerance: default time (in ms) before declaring link failure |
57 | * @window: default window (in packets) before declaring link congestion | 95 | * @window: default window (in packets) before declaring link congestion |
58 | * @type_id: TIPC media identifier [defined in tipc_bearer.h] | 96 | * @type_id: TIPC media identifier |
59 | * @name: media name | 97 | * @name: media name |
60 | */ | 98 | */ |
61 | 99 | ||
@@ -116,6 +154,34 @@ struct link; | |||
116 | 154 | ||
117 | extern struct bearer tipc_bearers[]; | 155 | extern struct bearer tipc_bearers[]; |
118 | 156 | ||
157 | /* | ||
158 | * TIPC routines available to supported media types | ||
159 | */ | ||
160 | int tipc_register_media(u32 media_type, | ||
161 | char *media_name, int (*enable)(struct tipc_bearer *), | ||
162 | void (*disable)(struct tipc_bearer *), | ||
163 | int (*send_msg)(struct sk_buff *, | ||
164 | struct tipc_bearer *, struct tipc_media_addr *), | ||
165 | char *(*addr2str)(struct tipc_media_addr *a, | ||
166 | char *str_buf, int str_size), | ||
167 | struct tipc_media_addr *bcast_addr, const u32 bearer_priority, | ||
168 | const u32 link_tolerance, /* [ms] */ | ||
169 | const u32 send_window_limit); | ||
170 | |||
171 | void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr); | ||
172 | |||
173 | int tipc_block_bearer(const char *name); | ||
174 | void tipc_continue(struct tipc_bearer *tb_ptr); | ||
175 | |||
176 | int tipc_enable_bearer(const char *bearer_name, u32 bcast_scope, u32 priority); | ||
177 | int tipc_disable_bearer(const char *name); | ||
178 | |||
179 | /* | ||
180 | * Routines made available to TIPC by supported media types | ||
181 | */ | ||
182 | int tipc_eth_media_start(void); | ||
183 | void tipc_eth_media_stop(void); | ||
184 | |||
119 | void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a); | 185 | void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a); |
120 | struct sk_buff *tipc_media_get_names(void); | 186 | struct sk_buff *tipc_media_get_names(void); |
121 | 187 | ||
@@ -126,7 +192,6 @@ void tipc_bearer_schedule(struct bearer *b_ptr, struct link *l_ptr); | |||
126 | struct bearer *tipc_bearer_find_interface(const char *if_name); | 192 | struct bearer *tipc_bearer_find_interface(const char *if_name); |
127 | int tipc_bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr); | 193 | int tipc_bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr); |
128 | int tipc_bearer_congested(struct bearer *b_ptr, struct link *l_ptr); | 194 | int tipc_bearer_congested(struct bearer *b_ptr, struct link *l_ptr); |
129 | int tipc_bearer_init(void); | ||
130 | void tipc_bearer_stop(void); | 195 | void tipc_bearer_stop(void); |
131 | void tipc_bearer_lock_push(struct bearer *b_ptr); | 196 | void tipc_bearer_lock_push(struct bearer *b_ptr); |
132 | 197 | ||
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c deleted file mode 100644 index 7fea14b98b97..000000000000 --- a/net/tipc/cluster.c +++ /dev/null | |||
@@ -1,557 +0,0 @@ | |||
1 | /* | ||
2 | * net/tipc/cluster.c: TIPC cluster management routines | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2005, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #include "core.h" | ||
38 | #include "cluster.h" | ||
39 | #include "addr.h" | ||
40 | #include "node_subscr.h" | ||
41 | #include "link.h" | ||
42 | #include "node.h" | ||
43 | #include "net.h" | ||
44 | #include "msg.h" | ||
45 | #include "bearer.h" | ||
46 | |||
47 | static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, | ||
48 | u32 lower, u32 upper); | ||
49 | static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest); | ||
50 | |||
51 | struct tipc_node **tipc_local_nodes = NULL; | ||
52 | struct tipc_node_map tipc_cltr_bcast_nodes = {0,{0,}}; | ||
53 | u32 tipc_highest_allowed_slave = 0; | ||
54 | |||
55 | struct cluster *tipc_cltr_create(u32 addr) | ||
56 | { | ||
57 | struct _zone *z_ptr; | ||
58 | struct cluster *c_ptr; | ||
59 | int max_nodes; | ||
60 | |||
61 | c_ptr = kzalloc(sizeof(*c_ptr), GFP_ATOMIC); | ||
62 | if (c_ptr == NULL) { | ||
63 | warn("Cluster creation failure, no memory\n"); | ||
64 | return NULL; | ||
65 | } | ||
66 | |||
67 | c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); | ||
68 | if (in_own_cluster(addr)) | ||
69 | max_nodes = LOWEST_SLAVE + tipc_max_slaves; | ||
70 | else | ||
71 | max_nodes = tipc_max_nodes + 1; | ||
72 | |||
73 | c_ptr->nodes = kcalloc(max_nodes + 1, sizeof(void*), GFP_ATOMIC); | ||
74 | if (c_ptr->nodes == NULL) { | ||
75 | warn("Cluster creation failure, no memory for node area\n"); | ||
76 | kfree(c_ptr); | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | if (in_own_cluster(addr)) | ||
81 | tipc_local_nodes = c_ptr->nodes; | ||
82 | c_ptr->highest_slave = LOWEST_SLAVE - 1; | ||
83 | c_ptr->highest_node = 0; | ||
84 | |||
85 | z_ptr = tipc_zone_find(tipc_zone(addr)); | ||
86 | if (!z_ptr) { | ||
87 | z_ptr = tipc_zone_create(addr); | ||
88 | } | ||
89 | if (!z_ptr) { | ||
90 | kfree(c_ptr->nodes); | ||
91 | kfree(c_ptr); | ||
92 | return NULL; | ||
93 | } | ||
94 | |||
95 | tipc_zone_attach_cluster(z_ptr, c_ptr); | ||
96 | c_ptr->owner = z_ptr; | ||
97 | return c_ptr; | ||
98 | } | ||
99 | |||
100 | void tipc_cltr_delete(struct cluster *c_ptr) | ||
101 | { | ||
102 | u32 n_num; | ||
103 | |||
104 | if (!c_ptr) | ||
105 | return; | ||
106 | for (n_num = 1; n_num <= c_ptr->highest_node; n_num++) { | ||
107 | tipc_node_delete(c_ptr->nodes[n_num]); | ||
108 | } | ||
109 | for (n_num = LOWEST_SLAVE; n_num <= c_ptr->highest_slave; n_num++) { | ||
110 | tipc_node_delete(c_ptr->nodes[n_num]); | ||
111 | } | ||
112 | kfree(c_ptr->nodes); | ||
113 | kfree(c_ptr); | ||
114 | } | ||
115 | |||
116 | |||
117 | void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr) | ||
118 | { | ||
119 | u32 n_num = tipc_node(n_ptr->addr); | ||
120 | u32 max_n_num = tipc_max_nodes; | ||
121 | |||
122 | if (in_own_cluster(n_ptr->addr)) | ||
123 | max_n_num = tipc_highest_allowed_slave; | ||
124 | assert(n_num > 0); | ||
125 | assert(n_num <= max_n_num); | ||
126 | assert(c_ptr->nodes[n_num] == NULL); | ||
127 | c_ptr->nodes[n_num] = n_ptr; | ||
128 | if (n_num > c_ptr->highest_node) | ||
129 | c_ptr->highest_node = n_num; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * tipc_cltr_select_router - select router to a cluster | ||
134 | * | ||
135 | * Uses deterministic and fair algorithm. | ||
136 | */ | ||
137 | |||
138 | u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref) | ||
139 | { | ||
140 | u32 n_num; | ||
141 | u32 ulim = c_ptr->highest_node; | ||
142 | u32 mask; | ||
143 | u32 tstart; | ||
144 | |||
145 | assert(!in_own_cluster(c_ptr->addr)); | ||
146 | if (!ulim) | ||
147 | return 0; | ||
148 | |||
149 | /* Start entry must be random */ | ||
150 | mask = tipc_max_nodes; | ||
151 | while (mask > ulim) | ||
152 | mask >>= 1; | ||
153 | tstart = ref & mask; | ||
154 | n_num = tstart; | ||
155 | |||
156 | /* Lookup upwards with wrap-around */ | ||
157 | do { | ||
158 | if (tipc_node_is_up(c_ptr->nodes[n_num])) | ||
159 | break; | ||
160 | } while (++n_num <= ulim); | ||
161 | if (n_num > ulim) { | ||
162 | n_num = 1; | ||
163 | do { | ||
164 | if (tipc_node_is_up(c_ptr->nodes[n_num])) | ||
165 | break; | ||
166 | } while (++n_num < tstart); | ||
167 | if (n_num == tstart) | ||
168 | return 0; | ||
169 | } | ||
170 | assert(n_num <= ulim); | ||
171 | return tipc_node_select_router(c_ptr->nodes[n_num], ref); | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * tipc_cltr_select_node - select destination node within a remote cluster | ||
176 | * | ||
177 | * Uses deterministic and fair algorithm. | ||
178 | */ | ||
179 | |||
180 | struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector) | ||
181 | { | ||
182 | u32 n_num; | ||
183 | u32 mask = tipc_max_nodes; | ||
184 | u32 start_entry; | ||
185 | |||
186 | assert(!in_own_cluster(c_ptr->addr)); | ||
187 | if (!c_ptr->highest_node) | ||
188 | return NULL; | ||
189 | |||
190 | /* Start entry must be random */ | ||
191 | while (mask > c_ptr->highest_node) { | ||
192 | mask >>= 1; | ||
193 | } | ||
194 | start_entry = (selector & mask) ? selector & mask : 1u; | ||
195 | assert(start_entry <= c_ptr->highest_node); | ||
196 | |||
197 | /* Lookup upwards with wrap-around */ | ||
198 | for (n_num = start_entry; n_num <= c_ptr->highest_node; n_num++) { | ||
199 | if (tipc_node_has_active_links(c_ptr->nodes[n_num])) | ||
200 | return c_ptr->nodes[n_num]; | ||
201 | } | ||
202 | for (n_num = 1; n_num < start_entry; n_num++) { | ||
203 | if (tipc_node_has_active_links(c_ptr->nodes[n_num])) | ||
204 | return c_ptr->nodes[n_num]; | ||
205 | } | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Routing table management: See description in node.c | ||
211 | */ | ||
212 | |||
213 | static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest) | ||
214 | { | ||
215 | u32 size = INT_H_SIZE + data_size; | ||
216 | struct sk_buff *buf = tipc_buf_acquire(size); | ||
217 | struct tipc_msg *msg; | ||
218 | |||
219 | if (buf) { | ||
220 | msg = buf_msg(buf); | ||
221 | memset((char *)msg, 0, size); | ||
222 | tipc_msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest); | ||
223 | } | ||
224 | return buf; | ||
225 | } | ||
226 | |||
227 | void tipc_cltr_bcast_new_route(struct cluster *c_ptr, u32 dest, | ||
228 | u32 lower, u32 upper) | ||
229 | { | ||
230 | struct sk_buff *buf = tipc_cltr_prepare_routing_msg(0, c_ptr->addr); | ||
231 | struct tipc_msg *msg; | ||
232 | |||
233 | if (buf) { | ||
234 | msg = buf_msg(buf); | ||
235 | msg_set_remote_node(msg, dest); | ||
236 | msg_set_type(msg, ROUTE_ADDITION); | ||
237 | tipc_cltr_multicast(c_ptr, buf, lower, upper); | ||
238 | } else { | ||
239 | warn("Memory squeeze: broadcast of new route failed\n"); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | void tipc_cltr_bcast_lost_route(struct cluster *c_ptr, u32 dest, | ||
244 | u32 lower, u32 upper) | ||
245 | { | ||
246 | struct sk_buff *buf = tipc_cltr_prepare_routing_msg(0, c_ptr->addr); | ||
247 | struct tipc_msg *msg; | ||
248 | |||
249 | if (buf) { | ||
250 | msg = buf_msg(buf); | ||
251 | msg_set_remote_node(msg, dest); | ||
252 | msg_set_type(msg, ROUTE_REMOVAL); | ||
253 | tipc_cltr_multicast(c_ptr, buf, lower, upper); | ||
254 | } else { | ||
255 | warn("Memory squeeze: broadcast of lost route failed\n"); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest) | ||
260 | { | ||
261 | struct sk_buff *buf; | ||
262 | struct tipc_msg *msg; | ||
263 | u32 highest = c_ptr->highest_slave; | ||
264 | u32 n_num; | ||
265 | int send = 0; | ||
266 | |||
267 | assert(!is_slave(dest)); | ||
268 | assert(in_own_cluster(dest)); | ||
269 | assert(in_own_cluster(c_ptr->addr)); | ||
270 | if (highest <= LOWEST_SLAVE) | ||
271 | return; | ||
272 | buf = tipc_cltr_prepare_routing_msg(highest - LOWEST_SLAVE + 1, | ||
273 | c_ptr->addr); | ||
274 | if (buf) { | ||
275 | msg = buf_msg(buf); | ||
276 | msg_set_remote_node(msg, c_ptr->addr); | ||
277 | msg_set_type(msg, SLAVE_ROUTING_TABLE); | ||
278 | for (n_num = LOWEST_SLAVE; n_num <= highest; n_num++) { | ||
279 | if (c_ptr->nodes[n_num] && | ||
280 | tipc_node_has_active_links(c_ptr->nodes[n_num])) { | ||
281 | send = 1; | ||
282 | msg_set_dataoctet(msg, n_num); | ||
283 | } | ||
284 | } | ||
285 | if (send) | ||
286 | tipc_link_send(buf, dest, dest); | ||
287 | else | ||
288 | buf_discard(buf); | ||
289 | } else { | ||
290 | warn("Memory squeeze: broadcast of lost route failed\n"); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest) | ||
295 | { | ||
296 | struct sk_buff *buf; | ||
297 | struct tipc_msg *msg; | ||
298 | u32 highest = c_ptr->highest_node; | ||
299 | u32 n_num; | ||
300 | int send = 0; | ||
301 | |||
302 | if (in_own_cluster(c_ptr->addr)) | ||
303 | return; | ||
304 | assert(!is_slave(dest)); | ||
305 | assert(in_own_cluster(dest)); | ||
306 | highest = c_ptr->highest_node; | ||
307 | buf = tipc_cltr_prepare_routing_msg(highest + 1, c_ptr->addr); | ||
308 | if (buf) { | ||
309 | msg = buf_msg(buf); | ||
310 | msg_set_remote_node(msg, c_ptr->addr); | ||
311 | msg_set_type(msg, EXT_ROUTING_TABLE); | ||
312 | for (n_num = 1; n_num <= highest; n_num++) { | ||
313 | if (c_ptr->nodes[n_num] && | ||
314 | tipc_node_has_active_links(c_ptr->nodes[n_num])) { | ||
315 | send = 1; | ||
316 | msg_set_dataoctet(msg, n_num); | ||
317 | } | ||
318 | } | ||
319 | if (send) | ||
320 | tipc_link_send(buf, dest, dest); | ||
321 | else | ||
322 | buf_discard(buf); | ||
323 | } else { | ||
324 | warn("Memory squeeze: broadcast of external route failed\n"); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | void tipc_cltr_send_local_routes(struct cluster *c_ptr, u32 dest) | ||
329 | { | ||
330 | struct sk_buff *buf; | ||
331 | struct tipc_msg *msg; | ||
332 | u32 highest = c_ptr->highest_node; | ||
333 | u32 n_num; | ||
334 | int send = 0; | ||
335 | |||
336 | assert(is_slave(dest)); | ||
337 | assert(in_own_cluster(c_ptr->addr)); | ||
338 | buf = tipc_cltr_prepare_routing_msg(highest, c_ptr->addr); | ||
339 | if (buf) { | ||
340 | msg = buf_msg(buf); | ||
341 | msg_set_remote_node(msg, c_ptr->addr); | ||
342 | msg_set_type(msg, LOCAL_ROUTING_TABLE); | ||
343 | for (n_num = 1; n_num <= highest; n_num++) { | ||
344 | if (c_ptr->nodes[n_num] && | ||
345 | tipc_node_has_active_links(c_ptr->nodes[n_num])) { | ||
346 | send = 1; | ||
347 | msg_set_dataoctet(msg, n_num); | ||
348 | } | ||
349 | } | ||
350 | if (send) | ||
351 | tipc_link_send(buf, dest, dest); | ||
352 | else | ||
353 | buf_discard(buf); | ||
354 | } else { | ||
355 | warn("Memory squeeze: broadcast of local route failed\n"); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | void tipc_cltr_recv_routing_table(struct sk_buff *buf) | ||
360 | { | ||
361 | struct tipc_msg *msg = buf_msg(buf); | ||
362 | struct cluster *c_ptr; | ||
363 | struct tipc_node *n_ptr; | ||
364 | unchar *node_table; | ||
365 | u32 table_size; | ||
366 | u32 router; | ||
367 | u32 rem_node = msg_remote_node(msg); | ||
368 | u32 z_num; | ||
369 | u32 c_num; | ||
370 | u32 n_num; | ||
371 | |||
372 | c_ptr = tipc_cltr_find(rem_node); | ||
373 | if (!c_ptr) { | ||
374 | c_ptr = tipc_cltr_create(rem_node); | ||
375 | if (!c_ptr) { | ||
376 | buf_discard(buf); | ||
377 | return; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | node_table = buf->data + msg_hdr_sz(msg); | ||
382 | table_size = msg_size(msg) - msg_hdr_sz(msg); | ||
383 | router = msg_prevnode(msg); | ||
384 | z_num = tipc_zone(rem_node); | ||
385 | c_num = tipc_cluster(rem_node); | ||
386 | |||
387 | switch (msg_type(msg)) { | ||
388 | case LOCAL_ROUTING_TABLE: | ||
389 | assert(is_slave(tipc_own_addr)); | ||
390 | case EXT_ROUTING_TABLE: | ||
391 | for (n_num = 1; n_num < table_size; n_num++) { | ||
392 | if (node_table[n_num]) { | ||
393 | u32 addr = tipc_addr(z_num, c_num, n_num); | ||
394 | n_ptr = c_ptr->nodes[n_num]; | ||
395 | if (!n_ptr) { | ||
396 | n_ptr = tipc_node_create(addr); | ||
397 | } | ||
398 | if (n_ptr) | ||
399 | tipc_node_add_router(n_ptr, router); | ||
400 | } | ||
401 | } | ||
402 | break; | ||
403 | case SLAVE_ROUTING_TABLE: | ||
404 | assert(!is_slave(tipc_own_addr)); | ||
405 | assert(in_own_cluster(c_ptr->addr)); | ||
406 | for (n_num = 1; n_num < table_size; n_num++) { | ||
407 | if (node_table[n_num]) { | ||
408 | u32 slave_num = n_num + LOWEST_SLAVE; | ||
409 | u32 addr = tipc_addr(z_num, c_num, slave_num); | ||
410 | n_ptr = c_ptr->nodes[slave_num]; | ||
411 | if (!n_ptr) { | ||
412 | n_ptr = tipc_node_create(addr); | ||
413 | } | ||
414 | if (n_ptr) | ||
415 | tipc_node_add_router(n_ptr, router); | ||
416 | } | ||
417 | } | ||
418 | break; | ||
419 | case ROUTE_ADDITION: | ||
420 | if (!is_slave(tipc_own_addr)) { | ||
421 | assert(!in_own_cluster(c_ptr->addr) || | ||
422 | is_slave(rem_node)); | ||
423 | } else { | ||
424 | assert(in_own_cluster(c_ptr->addr) && | ||
425 | !is_slave(rem_node)); | ||
426 | } | ||
427 | n_ptr = c_ptr->nodes[tipc_node(rem_node)]; | ||
428 | if (!n_ptr) | ||
429 | n_ptr = tipc_node_create(rem_node); | ||
430 | if (n_ptr) | ||
431 | tipc_node_add_router(n_ptr, router); | ||
432 | break; | ||
433 | case ROUTE_REMOVAL: | ||
434 | if (!is_slave(tipc_own_addr)) { | ||
435 | assert(!in_own_cluster(c_ptr->addr) || | ||
436 | is_slave(rem_node)); | ||
437 | } else { | ||
438 | assert(in_own_cluster(c_ptr->addr) && | ||
439 | !is_slave(rem_node)); | ||
440 | } | ||
441 | n_ptr = c_ptr->nodes[tipc_node(rem_node)]; | ||
442 | if (n_ptr) | ||
443 | tipc_node_remove_router(n_ptr, router); | ||
444 | break; | ||
445 | default: | ||
446 | assert(!"Illegal routing manager message received\n"); | ||
447 | } | ||
448 | buf_discard(buf); | ||
449 | } | ||
450 | |||
451 | void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router) | ||
452 | { | ||
453 | u32 start_entry; | ||
454 | u32 tstop; | ||
455 | u32 n_num; | ||
456 | |||
457 | if (is_slave(router)) | ||
458 | return; /* Slave nodes can not be routers */ | ||
459 | |||
460 | if (in_own_cluster(c_ptr->addr)) { | ||
461 | start_entry = LOWEST_SLAVE; | ||
462 | tstop = c_ptr->highest_slave; | ||
463 | } else { | ||
464 | start_entry = 1; | ||
465 | tstop = c_ptr->highest_node; | ||
466 | } | ||
467 | |||
468 | for (n_num = start_entry; n_num <= tstop; n_num++) { | ||
469 | if (c_ptr->nodes[n_num]) { | ||
470 | tipc_node_remove_router(c_ptr->nodes[n_num], router); | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * tipc_cltr_multicast - multicast message to local nodes | ||
477 | */ | ||
478 | |||
479 | static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, | ||
480 | u32 lower, u32 upper) | ||
481 | { | ||
482 | struct sk_buff *buf_copy; | ||
483 | struct tipc_node *n_ptr; | ||
484 | u32 n_num; | ||
485 | u32 tstop; | ||
486 | |||
487 | assert(lower <= upper); | ||
488 | assert(((lower >= 1) && (lower <= tipc_max_nodes)) || | ||
489 | ((lower >= LOWEST_SLAVE) && (lower <= tipc_highest_allowed_slave))); | ||
490 | assert(((upper >= 1) && (upper <= tipc_max_nodes)) || | ||
491 | ((upper >= LOWEST_SLAVE) && (upper <= tipc_highest_allowed_slave))); | ||
492 | assert(in_own_cluster(c_ptr->addr)); | ||
493 | |||
494 | tstop = is_slave(upper) ? c_ptr->highest_slave : c_ptr->highest_node; | ||
495 | if (tstop > upper) | ||
496 | tstop = upper; | ||
497 | for (n_num = lower; n_num <= tstop; n_num++) { | ||
498 | n_ptr = c_ptr->nodes[n_num]; | ||
499 | if (n_ptr && tipc_node_has_active_links(n_ptr)) { | ||
500 | buf_copy = skb_copy(buf, GFP_ATOMIC); | ||
501 | if (buf_copy == NULL) | ||
502 | break; | ||
503 | msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); | ||
504 | tipc_link_send(buf_copy, n_ptr->addr, n_ptr->addr); | ||
505 | } | ||
506 | } | ||
507 | buf_discard(buf); | ||
508 | } | ||
509 | |||
510 | /** | ||
511 | * tipc_cltr_broadcast - broadcast message to all nodes within cluster | ||
512 | */ | ||
513 | |||
514 | void tipc_cltr_broadcast(struct sk_buff *buf) | ||
515 | { | ||
516 | struct sk_buff *buf_copy; | ||
517 | struct cluster *c_ptr; | ||
518 | struct tipc_node *n_ptr; | ||
519 | u32 n_num; | ||
520 | u32 tstart; | ||
521 | u32 tstop; | ||
522 | u32 node_type; | ||
523 | |||
524 | if (tipc_mode == TIPC_NET_MODE) { | ||
525 | c_ptr = tipc_cltr_find(tipc_own_addr); | ||
526 | assert(in_own_cluster(c_ptr->addr)); /* For now */ | ||
527 | |||
528 | /* Send to standard nodes, then repeat loop sending to slaves */ | ||
529 | tstart = 1; | ||
530 | tstop = c_ptr->highest_node; | ||
531 | for (node_type = 1; node_type <= 2; node_type++) { | ||
532 | for (n_num = tstart; n_num <= tstop; n_num++) { | ||
533 | n_ptr = c_ptr->nodes[n_num]; | ||
534 | if (n_ptr && tipc_node_has_active_links(n_ptr)) { | ||
535 | buf_copy = skb_copy(buf, GFP_ATOMIC); | ||
536 | if (buf_copy == NULL) | ||
537 | goto exit; | ||
538 | msg_set_destnode(buf_msg(buf_copy), | ||
539 | n_ptr->addr); | ||
540 | tipc_link_send(buf_copy, n_ptr->addr, | ||
541 | n_ptr->addr); | ||
542 | } | ||
543 | } | ||
544 | tstart = LOWEST_SLAVE; | ||
545 | tstop = c_ptr->highest_slave; | ||
546 | } | ||
547 | } | ||
548 | exit: | ||
549 | buf_discard(buf); | ||
550 | } | ||
551 | |||
552 | int tipc_cltr_init(void) | ||
553 | { | ||
554 | tipc_highest_allowed_slave = LOWEST_SLAVE + tipc_max_slaves; | ||
555 | return tipc_cltr_create(tipc_own_addr) ? 0 : -ENOMEM; | ||
556 | } | ||
557 | |||
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h deleted file mode 100644 index 32636d98c9c6..000000000000 --- a/net/tipc/cluster.h +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | /* | ||
2 | * net/tipc/cluster.h: Include file for TIPC cluster management routines | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2005, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #ifndef _TIPC_CLUSTER_H | ||
38 | #define _TIPC_CLUSTER_H | ||
39 | |||
40 | #include "addr.h" | ||
41 | #include "zone.h" | ||
42 | |||
43 | #define LOWEST_SLAVE 2048u | ||
44 | |||
45 | /** | ||
46 | * struct cluster - TIPC cluster structure | ||
47 | * @addr: network address of cluster | ||
48 | * @owner: pointer to zone that cluster belongs to | ||
49 | * @nodes: array of pointers to all nodes within cluster | ||
50 | * @highest_node: id of highest numbered node within cluster | ||
51 | * @highest_slave: (used for secondary node support) | ||
52 | */ | ||
53 | |||
54 | struct cluster { | ||
55 | u32 addr; | ||
56 | struct _zone *owner; | ||
57 | struct tipc_node **nodes; | ||
58 | u32 highest_node; | ||
59 | u32 highest_slave; | ||
60 | }; | ||
61 | |||
62 | |||
63 | extern struct tipc_node **tipc_local_nodes; | ||
64 | extern u32 tipc_highest_allowed_slave; | ||
65 | extern struct tipc_node_map tipc_cltr_bcast_nodes; | ||
66 | |||
67 | void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router); | ||
68 | void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest); | ||
69 | struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector); | ||
70 | u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref); | ||
71 | void tipc_cltr_recv_routing_table(struct sk_buff *buf); | ||
72 | struct cluster *tipc_cltr_create(u32 addr); | ||
73 | void tipc_cltr_delete(struct cluster *c_ptr); | ||
74 | void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr); | ||
75 | void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest); | ||
76 | void tipc_cltr_broadcast(struct sk_buff *buf); | ||
77 | int tipc_cltr_init(void); | ||
78 | |||
79 | void tipc_cltr_bcast_new_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi); | ||
80 | void tipc_cltr_send_local_routes(struct cluster *c_ptr, u32 dest); | ||
81 | void tipc_cltr_bcast_lost_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi); | ||
82 | |||
83 | static inline struct cluster *tipc_cltr_find(u32 addr) | ||
84 | { | ||
85 | struct _zone *z_ptr = tipc_zone_find(addr); | ||
86 | |||
87 | if (z_ptr) | ||
88 | return z_ptr->clusters[1]; | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | #endif | ||
diff --git a/net/tipc/config.c b/net/tipc/config.c index 50a6133a3668..e16750dcf3c1 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c | |||
@@ -35,30 +35,11 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "dbg.h" | ||
39 | #include "bearer.h" | ||
40 | #include "port.h" | 38 | #include "port.h" |
41 | #include "link.h" | ||
42 | #include "zone.h" | ||
43 | #include "addr.h" | ||
44 | #include "name_table.h" | 39 | #include "name_table.h" |
45 | #include "node.h" | ||
46 | #include "config.h" | 40 | #include "config.h" |
47 | #include "discover.h" | ||
48 | 41 | ||
49 | struct subscr_data { | 42 | static u32 config_port_ref; |
50 | char usr_handle[8]; | ||
51 | u32 domain; | ||
52 | u32 port_ref; | ||
53 | struct list_head subd_list; | ||
54 | }; | ||
55 | |||
56 | struct manager { | ||
57 | u32 user_ref; | ||
58 | u32 port_ref; | ||
59 | }; | ||
60 | |||
61 | static struct manager mng = { 0}; | ||
62 | 43 | ||
63 | static DEFINE_SPINLOCK(config_lock); | 44 | static DEFINE_SPINLOCK(config_lock); |
64 | 45 | ||
@@ -83,10 +64,8 @@ int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, | |||
83 | struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf); | 64 | struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf); |
84 | int new_tlv_space = TLV_SPACE(tlv_data_size); | 65 | int new_tlv_space = TLV_SPACE(tlv_data_size); |
85 | 66 | ||
86 | if (skb_tailroom(buf) < new_tlv_space) { | 67 | if (skb_tailroom(buf) < new_tlv_space) |
87 | dbg("tipc_cfg_append_tlv unable to append TLV\n"); | ||
88 | return 0; | 68 | return 0; |
89 | } | ||
90 | skb_put(buf, new_tlv_space); | 69 | skb_put(buf, new_tlv_space); |
91 | tlv->tlv_type = htons(tlv_type); | 70 | tlv->tlv_type = htons(tlv_type); |
92 | tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size)); | 71 | tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size)); |
@@ -281,38 +260,6 @@ static struct sk_buff *cfg_set_max_ports(void) | |||
281 | return tipc_cfg_reply_none(); | 260 | return tipc_cfg_reply_none(); |
282 | } | 261 | } |
283 | 262 | ||
284 | static struct sk_buff *cfg_set_max_zones(void) | ||
285 | { | ||
286 | u32 value; | ||
287 | |||
288 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) | ||
289 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | ||
290 | value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); | ||
291 | if (value == tipc_max_zones) | ||
292 | return tipc_cfg_reply_none(); | ||
293 | if (value != delimit(value, 1, 255)) | ||
294 | return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE | ||
295 | " (max zones must be 1-255)"); | ||
296 | if (tipc_mode == TIPC_NET_MODE) | ||
297 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | ||
298 | " (cannot change max zones once TIPC has joined a network)"); | ||
299 | tipc_max_zones = value; | ||
300 | return tipc_cfg_reply_none(); | ||
301 | } | ||
302 | |||
303 | static struct sk_buff *cfg_set_max_clusters(void) | ||
304 | { | ||
305 | u32 value; | ||
306 | |||
307 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) | ||
308 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | ||
309 | value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); | ||
310 | if (value != delimit(value, 1, 1)) | ||
311 | return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE | ||
312 | " (max clusters fixed at 1)"); | ||
313 | return tipc_cfg_reply_none(); | ||
314 | } | ||
315 | |||
316 | static struct sk_buff *cfg_set_max_nodes(void) | 263 | static struct sk_buff *cfg_set_max_nodes(void) |
317 | { | 264 | { |
318 | u32 value; | 265 | u32 value; |
@@ -332,19 +279,6 @@ static struct sk_buff *cfg_set_max_nodes(void) | |||
332 | return tipc_cfg_reply_none(); | 279 | return tipc_cfg_reply_none(); |
333 | } | 280 | } |
334 | 281 | ||
335 | static struct sk_buff *cfg_set_max_slaves(void) | ||
336 | { | ||
337 | u32 value; | ||
338 | |||
339 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) | ||
340 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | ||
341 | value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); | ||
342 | if (value != 0) | ||
343 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | ||
344 | " (max secondary nodes fixed at 0)"); | ||
345 | return tipc_cfg_reply_none(); | ||
346 | } | ||
347 | |||
348 | static struct sk_buff *cfg_set_netid(void) | 282 | static struct sk_buff *cfg_set_netid(void) |
349 | { | 283 | { |
350 | u32 value; | 284 | u32 value; |
@@ -388,8 +322,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area | |||
388 | } else if (!tipc_remote_management) { | 322 | } else if (!tipc_remote_management) { |
389 | rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE); | 323 | rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE); |
390 | goto exit; | 324 | goto exit; |
391 | } | 325 | } else if (cmd >= 0x4000) { |
392 | else if (cmd >= 0x4000) { | ||
393 | u32 domain = 0; | 326 | u32 domain = 0; |
394 | 327 | ||
395 | if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) || | 328 | if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) || |
@@ -464,18 +397,9 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area | |||
464 | case TIPC_CMD_SET_MAX_SUBSCR: | 397 | case TIPC_CMD_SET_MAX_SUBSCR: |
465 | rep_tlv_buf = cfg_set_max_subscriptions(); | 398 | rep_tlv_buf = cfg_set_max_subscriptions(); |
466 | break; | 399 | break; |
467 | case TIPC_CMD_SET_MAX_ZONES: | ||
468 | rep_tlv_buf = cfg_set_max_zones(); | ||
469 | break; | ||
470 | case TIPC_CMD_SET_MAX_CLUSTERS: | ||
471 | rep_tlv_buf = cfg_set_max_clusters(); | ||
472 | break; | ||
473 | case TIPC_CMD_SET_MAX_NODES: | 400 | case TIPC_CMD_SET_MAX_NODES: |
474 | rep_tlv_buf = cfg_set_max_nodes(); | 401 | rep_tlv_buf = cfg_set_max_nodes(); |
475 | break; | 402 | break; |
476 | case TIPC_CMD_SET_MAX_SLAVES: | ||
477 | rep_tlv_buf = cfg_set_max_slaves(); | ||
478 | break; | ||
479 | case TIPC_CMD_SET_NETID: | 403 | case TIPC_CMD_SET_NETID: |
480 | rep_tlv_buf = cfg_set_netid(); | 404 | rep_tlv_buf = cfg_set_netid(); |
481 | break; | 405 | break; |
@@ -491,18 +415,9 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area | |||
491 | case TIPC_CMD_GET_MAX_SUBSCR: | 415 | case TIPC_CMD_GET_MAX_SUBSCR: |
492 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions); | 416 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions); |
493 | break; | 417 | break; |
494 | case TIPC_CMD_GET_MAX_ZONES: | ||
495 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_zones); | ||
496 | break; | ||
497 | case TIPC_CMD_GET_MAX_CLUSTERS: | ||
498 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_clusters); | ||
499 | break; | ||
500 | case TIPC_CMD_GET_MAX_NODES: | 418 | case TIPC_CMD_GET_MAX_NODES: |
501 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_nodes); | 419 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_nodes); |
502 | break; | 420 | break; |
503 | case TIPC_CMD_GET_MAX_SLAVES: | ||
504 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_slaves); | ||
505 | break; | ||
506 | case TIPC_CMD_GET_NETID: | 421 | case TIPC_CMD_GET_NETID: |
507 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); | 422 | rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); |
508 | break; | 423 | break; |
@@ -510,6 +425,15 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area | |||
510 | rep_tlv_buf = | 425 | rep_tlv_buf = |
511 | tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); | 426 | tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); |
512 | break; | 427 | break; |
428 | case TIPC_CMD_SET_MAX_ZONES: | ||
429 | case TIPC_CMD_GET_MAX_ZONES: | ||
430 | case TIPC_CMD_SET_MAX_SLAVES: | ||
431 | case TIPC_CMD_GET_MAX_SLAVES: | ||
432 | case TIPC_CMD_SET_MAX_CLUSTERS: | ||
433 | case TIPC_CMD_GET_MAX_CLUSTERS: | ||
434 | rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | ||
435 | " (obsolete command)"); | ||
436 | break; | ||
513 | default: | 437 | default: |
514 | rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | 438 | rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED |
515 | " (unknown command)"); | 439 | " (unknown command)"); |
@@ -572,20 +496,16 @@ int tipc_cfg_init(void) | |||
572 | struct tipc_name_seq seq; | 496 | struct tipc_name_seq seq; |
573 | int res; | 497 | int res; |
574 | 498 | ||
575 | res = tipc_attach(&mng.user_ref, NULL, NULL); | 499 | res = tipc_createport(NULL, TIPC_CRITICAL_IMPORTANCE, |
576 | if (res) | ||
577 | goto failed; | ||
578 | |||
579 | res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE, | ||
580 | NULL, NULL, NULL, | 500 | NULL, NULL, NULL, |
581 | NULL, cfg_named_msg_event, NULL, | 501 | NULL, cfg_named_msg_event, NULL, |
582 | NULL, &mng.port_ref); | 502 | NULL, &config_port_ref); |
583 | if (res) | 503 | if (res) |
584 | goto failed; | 504 | goto failed; |
585 | 505 | ||
586 | seq.type = TIPC_CFG_SRV; | 506 | seq.type = TIPC_CFG_SRV; |
587 | seq.lower = seq.upper = tipc_own_addr; | 507 | seq.lower = seq.upper = tipc_own_addr; |
588 | res = tipc_nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq); | 508 | res = tipc_nametbl_publish_rsv(config_port_ref, TIPC_ZONE_SCOPE, &seq); |
589 | if (res) | 509 | if (res) |
590 | goto failed; | 510 | goto failed; |
591 | 511 | ||
@@ -593,15 +513,13 @@ int tipc_cfg_init(void) | |||
593 | 513 | ||
594 | failed: | 514 | failed: |
595 | err("Unable to create configuration service\n"); | 515 | err("Unable to create configuration service\n"); |
596 | tipc_detach(mng.user_ref); | ||
597 | mng.user_ref = 0; | ||
598 | return res; | 516 | return res; |
599 | } | 517 | } |
600 | 518 | ||
601 | void tipc_cfg_stop(void) | 519 | void tipc_cfg_stop(void) |
602 | { | 520 | { |
603 | if (mng.user_ref) { | 521 | if (config_port_ref) { |
604 | tipc_detach(mng.user_ref); | 522 | tipc_deleteport(config_port_ref); |
605 | mng.user_ref = 0; | 523 | config_port_ref = 0; |
606 | } | 524 | } |
607 | } | 525 | } |
diff --git a/net/tipc/config.h b/net/tipc/config.h index 481e12ece715..443159a166fd 100644 --- a/net/tipc/config.h +++ b/net/tipc/config.h | |||
@@ -39,7 +39,6 @@ | |||
39 | 39 | ||
40 | /* ---------------------------------------------------------------------- */ | 40 | /* ---------------------------------------------------------------------- */ |
41 | 41 | ||
42 | #include "core.h" | ||
43 | #include "link.h" | 42 | #include "link.h" |
44 | 43 | ||
45 | struct sk_buff *tipc_cfg_reply_alloc(int payload_size); | 44 | struct sk_buff *tipc_cfg_reply_alloc(int payload_size); |
diff --git a/net/tipc/core.c b/net/tipc/core.c index e2a09eb8efd4..e071579e0850 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c | |||
@@ -34,37 +34,17 @@ | |||
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/random.h> | ||
41 | |||
42 | #include "core.h" | 37 | #include "core.h" |
43 | #include "dbg.h" | ||
44 | #include "ref.h" | 38 | #include "ref.h" |
45 | #include "net.h" | ||
46 | #include "user_reg.h" | ||
47 | #include "name_table.h" | 39 | #include "name_table.h" |
48 | #include "subscr.h" | 40 | #include "subscr.h" |
49 | #include "config.h" | 41 | #include "config.h" |
50 | 42 | ||
51 | 43 | ||
52 | #ifndef CONFIG_TIPC_ZONES | ||
53 | #define CONFIG_TIPC_ZONES 3 | ||
54 | #endif | ||
55 | |||
56 | #ifndef CONFIG_TIPC_CLUSTERS | ||
57 | #define CONFIG_TIPC_CLUSTERS 1 | ||
58 | #endif | ||
59 | |||
60 | #ifndef CONFIG_TIPC_NODES | 44 | #ifndef CONFIG_TIPC_NODES |
61 | #define CONFIG_TIPC_NODES 255 | 45 | #define CONFIG_TIPC_NODES 255 |
62 | #endif | 46 | #endif |
63 | 47 | ||
64 | #ifndef CONFIG_TIPC_SLAVE_NODES | ||
65 | #define CONFIG_TIPC_SLAVE_NODES 0 | ||
66 | #endif | ||
67 | |||
68 | #ifndef CONFIG_TIPC_PORTS | 48 | #ifndef CONFIG_TIPC_PORTS |
69 | #define CONFIG_TIPC_PORTS 8191 | 49 | #define CONFIG_TIPC_PORTS 8191 |
70 | #endif | 50 | #endif |
@@ -85,10 +65,7 @@ const char tipc_alphabet[] = | |||
85 | /* configurable TIPC parameters */ | 65 | /* configurable TIPC parameters */ |
86 | 66 | ||
87 | u32 tipc_own_addr; | 67 | u32 tipc_own_addr; |
88 | int tipc_max_zones; | ||
89 | int tipc_max_clusters; | ||
90 | int tipc_max_nodes; | 68 | int tipc_max_nodes; |
91 | int tipc_max_slaves; | ||
92 | int tipc_max_ports; | 69 | int tipc_max_ports; |
93 | int tipc_max_subscriptions; | 70 | int tipc_max_subscriptions; |
94 | int tipc_max_publications; | 71 | int tipc_max_publications; |
@@ -138,10 +115,11 @@ int tipc_core_start_net(unsigned long addr) | |||
138 | { | 115 | { |
139 | int res; | 116 | int res; |
140 | 117 | ||
141 | if ((res = tipc_net_start(addr)) || | 118 | res = tipc_net_start(addr); |
142 | (res = tipc_eth_media_start())) { | 119 | if (!res) |
120 | res = tipc_eth_media_start(); | ||
121 | if (res) | ||
143 | tipc_core_stop_net(); | 122 | tipc_core_stop_net(); |
144 | } | ||
145 | return res; | 123 | return res; |
146 | } | 124 | } |
147 | 125 | ||
@@ -160,7 +138,6 @@ static void tipc_core_stop(void) | |||
160 | tipc_handler_stop(); | 138 | tipc_handler_stop(); |
161 | tipc_cfg_stop(); | 139 | tipc_cfg_stop(); |
162 | tipc_subscr_stop(); | 140 | tipc_subscr_stop(); |
163 | tipc_reg_stop(); | ||
164 | tipc_nametbl_stop(); | 141 | tipc_nametbl_stop(); |
165 | tipc_ref_table_stop(); | 142 | tipc_ref_table_stop(); |
166 | tipc_socket_stop(); | 143 | tipc_socket_stop(); |
@@ -181,16 +158,22 @@ static int tipc_core_start(void) | |||
181 | get_random_bytes(&tipc_random, sizeof(tipc_random)); | 158 | get_random_bytes(&tipc_random, sizeof(tipc_random)); |
182 | tipc_mode = TIPC_NODE_MODE; | 159 | tipc_mode = TIPC_NODE_MODE; |
183 | 160 | ||
184 | if ((res = tipc_handler_start()) || | 161 | res = tipc_handler_start(); |
185 | (res = tipc_ref_table_init(tipc_max_ports, tipc_random)) || | 162 | if (!res) |
186 | (res = tipc_reg_start()) || | 163 | res = tipc_ref_table_init(tipc_max_ports, tipc_random); |
187 | (res = tipc_nametbl_init()) || | 164 | if (!res) |
188 | (res = tipc_k_signal((Handler)tipc_subscr_start, 0)) || | 165 | res = tipc_nametbl_init(); |
189 | (res = tipc_k_signal((Handler)tipc_cfg_init, 0)) || | 166 | if (!res) |
190 | (res = tipc_netlink_start()) || | 167 | res = tipc_k_signal((Handler)tipc_subscr_start, 0); |
191 | (res = tipc_socket_init())) { | 168 | if (!res) |
169 | res = tipc_k_signal((Handler)tipc_cfg_init, 0); | ||
170 | if (!res) | ||
171 | res = tipc_netlink_start(); | ||
172 | if (!res) | ||
173 | res = tipc_socket_init(); | ||
174 | if (res) | ||
192 | tipc_core_stop(); | 175 | tipc_core_stop(); |
193 | } | 176 | |
194 | return res; | 177 | return res; |
195 | } | 178 | } |
196 | 179 | ||
@@ -210,13 +193,11 @@ static int __init tipc_init(void) | |||
210 | tipc_max_publications = 10000; | 193 | tipc_max_publications = 10000; |
211 | tipc_max_subscriptions = 2000; | 194 | tipc_max_subscriptions = 2000; |
212 | tipc_max_ports = CONFIG_TIPC_PORTS; | 195 | tipc_max_ports = CONFIG_TIPC_PORTS; |
213 | tipc_max_zones = CONFIG_TIPC_ZONES; | ||
214 | tipc_max_clusters = CONFIG_TIPC_CLUSTERS; | ||
215 | tipc_max_nodes = CONFIG_TIPC_NODES; | 196 | tipc_max_nodes = CONFIG_TIPC_NODES; |
216 | tipc_max_slaves = CONFIG_TIPC_SLAVE_NODES; | ||
217 | tipc_net_id = 4711; | 197 | tipc_net_id = 4711; |
218 | 198 | ||
219 | if ((res = tipc_core_start())) | 199 | res = tipc_core_start(); |
200 | if (res) | ||
220 | err("Unable to start in single node mode\n"); | 201 | err("Unable to start in single node mode\n"); |
221 | else | 202 | else |
222 | info("Started in single node mode\n"); | 203 | info("Started in single node mode\n"); |
@@ -236,43 +217,3 @@ module_exit(tipc_exit); | |||
236 | MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication"); | 217 | MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication"); |
237 | MODULE_LICENSE("Dual BSD/GPL"); | 218 | MODULE_LICENSE("Dual BSD/GPL"); |
238 | MODULE_VERSION(TIPC_MOD_VER); | 219 | MODULE_VERSION(TIPC_MOD_VER); |
239 | |||
240 | /* Native TIPC API for kernel-space applications (see tipc.h) */ | ||
241 | |||
242 | EXPORT_SYMBOL(tipc_attach); | ||
243 | EXPORT_SYMBOL(tipc_detach); | ||
244 | EXPORT_SYMBOL(tipc_createport); | ||
245 | EXPORT_SYMBOL(tipc_deleteport); | ||
246 | EXPORT_SYMBOL(tipc_ownidentity); | ||
247 | EXPORT_SYMBOL(tipc_portimportance); | ||
248 | EXPORT_SYMBOL(tipc_set_portimportance); | ||
249 | EXPORT_SYMBOL(tipc_portunreliable); | ||
250 | EXPORT_SYMBOL(tipc_set_portunreliable); | ||
251 | EXPORT_SYMBOL(tipc_portunreturnable); | ||
252 | EXPORT_SYMBOL(tipc_set_portunreturnable); | ||
253 | EXPORT_SYMBOL(tipc_publish); | ||
254 | EXPORT_SYMBOL(tipc_withdraw); | ||
255 | EXPORT_SYMBOL(tipc_connect2port); | ||
256 | EXPORT_SYMBOL(tipc_disconnect); | ||
257 | EXPORT_SYMBOL(tipc_shutdown); | ||
258 | EXPORT_SYMBOL(tipc_send); | ||
259 | EXPORT_SYMBOL(tipc_send2name); | ||
260 | EXPORT_SYMBOL(tipc_send2port); | ||
261 | EXPORT_SYMBOL(tipc_multicast); | ||
262 | |||
263 | /* TIPC API for external bearers (see tipc_bearer.h) */ | ||
264 | |||
265 | EXPORT_SYMBOL(tipc_block_bearer); | ||
266 | EXPORT_SYMBOL(tipc_continue); | ||
267 | EXPORT_SYMBOL(tipc_disable_bearer); | ||
268 | EXPORT_SYMBOL(tipc_enable_bearer); | ||
269 | EXPORT_SYMBOL(tipc_recv_msg); | ||
270 | EXPORT_SYMBOL(tipc_register_media); | ||
271 | |||
272 | /* TIPC API for external APIs (see tipc_port.h) */ | ||
273 | |||
274 | EXPORT_SYMBOL(tipc_createport_raw); | ||
275 | EXPORT_SYMBOL(tipc_reject_msg); | ||
276 | EXPORT_SYMBOL(tipc_send_buf_fast); | ||
277 | EXPORT_SYMBOL(tipc_acknowledge); | ||
278 | |||
diff --git a/net/tipc/core.h b/net/tipc/core.h index e19389e57227..997158546e25 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h | |||
@@ -39,10 +39,6 @@ | |||
39 | 39 | ||
40 | #include <linux/tipc.h> | 40 | #include <linux/tipc.h> |
41 | #include <linux/tipc_config.h> | 41 | #include <linux/tipc_config.h> |
42 | #include <net/tipc/tipc_msg.h> | ||
43 | #include <net/tipc/tipc_port.h> | ||
44 | #include <net/tipc/tipc_bearer.h> | ||
45 | #include <net/tipc/tipc.h> | ||
46 | #include <linux/types.h> | 42 | #include <linux/types.h> |
47 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
48 | #include <linux/errno.h> | 44 | #include <linux/errno.h> |
@@ -62,6 +58,9 @@ | |||
62 | 58 | ||
63 | #define TIPC_MOD_VER "2.0.0" | 59 | #define TIPC_MOD_VER "2.0.0" |
64 | 60 | ||
61 | struct tipc_msg; /* msg.h */ | ||
62 | struct print_buf; /* log.h */ | ||
63 | |||
65 | /* | 64 | /* |
66 | * TIPC sanity test macros | 65 | * TIPC sanity test macros |
67 | */ | 66 | */ |
@@ -84,6 +83,7 @@ | |||
84 | * user-defined buffers can be configured to do the same thing. | 83 | * user-defined buffers can be configured to do the same thing. |
85 | */ | 84 | */ |
86 | extern struct print_buf *const TIPC_NULL; | 85 | extern struct print_buf *const TIPC_NULL; |
86 | extern struct print_buf *const TIPC_CONS; | ||
87 | extern struct print_buf *const TIPC_LOG; | 87 | extern struct print_buf *const TIPC_LOG; |
88 | 88 | ||
89 | void tipc_printf(struct print_buf *, const char *fmt, ...); | 89 | void tipc_printf(struct print_buf *, const char *fmt, ...); |
@@ -96,73 +96,35 @@ void tipc_printf(struct print_buf *, const char *fmt, ...); | |||
96 | #define TIPC_OUTPUT TIPC_LOG | 96 | #define TIPC_OUTPUT TIPC_LOG |
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | /* | ||
100 | * TIPC can be configured to send system messages to TIPC_OUTPUT | ||
101 | * or to the system console only. | ||
102 | */ | ||
103 | |||
104 | #ifdef CONFIG_TIPC_DEBUG | ||
105 | |||
106 | #define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ | 99 | #define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ |
107 | KERN_ERR "TIPC: " fmt, ## arg) | 100 | KERN_ERR "TIPC: " fmt, ## arg) |
108 | #define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ | 101 | #define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ |
109 | KERN_WARNING "TIPC: " fmt, ## arg) | 102 | KERN_WARNING "TIPC: " fmt, ## arg) |
110 | #define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ | 103 | #define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \ |
111 | KERN_NOTICE "TIPC: " fmt, ## arg) | 104 | KERN_NOTICE "TIPC: " fmt, ## arg) |
112 | |||
113 | #else | ||
114 | |||
115 | #define err(fmt, arg...) printk(KERN_ERR "TIPC: " fmt , ## arg) | ||
116 | #define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg) | ||
117 | #define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg) | ||
118 | 105 | ||
119 | #endif | 106 | #ifdef CONFIG_TIPC_DEBUG |
120 | 107 | ||
121 | /* | 108 | /* |
122 | * DBG_OUTPUT is the destination print buffer for debug messages. | 109 | * DBG_OUTPUT is the destination print buffer for debug messages. |
123 | * It defaults to the the null print buffer, but can be redefined | ||
124 | * (typically in the individual .c files being debugged) to allow | ||
125 | * selected debug messages to be generated where needed. | ||
126 | */ | 110 | */ |
127 | 111 | ||
128 | #ifndef DBG_OUTPUT | 112 | #ifndef DBG_OUTPUT |
129 | #define DBG_OUTPUT TIPC_NULL | 113 | #define DBG_OUTPUT TIPC_LOG |
130 | #endif | 114 | #endif |
131 | 115 | ||
132 | /* | 116 | #define dbg(fmt, arg...) tipc_printf(DBG_OUTPUT, KERN_DEBUG fmt, ## arg); |
133 | * TIPC can be configured to send debug messages to the specified print buffer | ||
134 | * (typically DBG_OUTPUT) or to suppress them entirely. | ||
135 | */ | ||
136 | 117 | ||
137 | #ifdef CONFIG_TIPC_DEBUG | 118 | #define msg_dbg(msg, txt) tipc_msg_dbg(DBG_OUTPUT, msg, txt); |
138 | |||
139 | #define dbg(fmt, arg...) \ | ||
140 | do { \ | ||
141 | if (DBG_OUTPUT != TIPC_NULL) \ | ||
142 | tipc_printf(DBG_OUTPUT, fmt, ## arg); \ | ||
143 | } while (0) | ||
144 | #define msg_dbg(msg, txt) \ | ||
145 | do { \ | ||
146 | if (DBG_OUTPUT != TIPC_NULL) \ | ||
147 | tipc_msg_dbg(DBG_OUTPUT, msg, txt); \ | ||
148 | } while (0) | ||
149 | #define dump(fmt, arg...) \ | ||
150 | do { \ | ||
151 | if (DBG_OUTPUT != TIPC_NULL) \ | ||
152 | tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \ | ||
153 | } while (0) | ||
154 | 119 | ||
155 | void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *); | 120 | void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *); |
156 | void tipc_dump_dbg(struct print_buf *, const char *fmt, ...); | ||
157 | 121 | ||
158 | #else | 122 | #else |
159 | 123 | ||
160 | #define dbg(fmt, arg...) do {} while (0) | 124 | #define dbg(fmt, arg...) do {} while (0) |
161 | #define msg_dbg(msg, txt) do {} while (0) | 125 | #define msg_dbg(msg, txt) do {} while (0) |
162 | #define dump(fmt, arg...) do {} while (0) | ||
163 | 126 | ||
164 | #define tipc_msg_dbg(...) do {} while (0) | 127 | #define tipc_msg_dbg(buf, msg, txt) do {} while (0) |
165 | #define tipc_dump_dbg(...) do {} while (0) | ||
166 | 128 | ||
167 | #endif | 129 | #endif |
168 | 130 | ||
@@ -174,14 +136,18 @@ void tipc_dump_dbg(struct print_buf *, const char *fmt, ...); | |||
174 | #define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */ | 136 | #define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */ |
175 | 137 | ||
176 | /* | 138 | /* |
139 | * TIPC operating mode routines | ||
140 | */ | ||
141 | #define TIPC_NOT_RUNNING 0 | ||
142 | #define TIPC_NODE_MODE 1 | ||
143 | #define TIPC_NET_MODE 2 | ||
144 | |||
145 | /* | ||
177 | * Global configuration variables | 146 | * Global configuration variables |
178 | */ | 147 | */ |
179 | 148 | ||
180 | extern u32 tipc_own_addr; | 149 | extern u32 tipc_own_addr; |
181 | extern int tipc_max_zones; | ||
182 | extern int tipc_max_clusters; | ||
183 | extern int tipc_max_nodes; | 150 | extern int tipc_max_nodes; |
184 | extern int tipc_max_slaves; | ||
185 | extern int tipc_max_ports; | 151 | extern int tipc_max_ports; |
186 | extern int tipc_max_subscriptions; | 152 | extern int tipc_max_subscriptions; |
187 | extern int tipc_max_publications; | 153 | extern int tipc_max_publications; |
@@ -240,7 +206,6 @@ u32 tipc_k_signal(Handler routine, unsigned long argument); | |||
240 | static inline void k_init_timer(struct timer_list *timer, Handler routine, | 206 | static inline void k_init_timer(struct timer_list *timer, Handler routine, |
241 | unsigned long argument) | 207 | unsigned long argument) |
242 | { | 208 | { |
243 | dbg("initializing timer %p\n", timer); | ||
244 | setup_timer(timer, routine, argument); | 209 | setup_timer(timer, routine, argument); |
245 | } | 210 | } |
246 | 211 | ||
@@ -260,7 +225,6 @@ static inline void k_init_timer(struct timer_list *timer, Handler routine, | |||
260 | 225 | ||
261 | static inline void k_start_timer(struct timer_list *timer, unsigned long msec) | 226 | static inline void k_start_timer(struct timer_list *timer, unsigned long msec) |
262 | { | 227 | { |
263 | dbg("starting timer %p for %u\n", timer, msec); | ||
264 | mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1); | 228 | mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1); |
265 | } | 229 | } |
266 | 230 | ||
@@ -277,7 +241,6 @@ static inline void k_start_timer(struct timer_list *timer, unsigned long msec) | |||
277 | 241 | ||
278 | static inline void k_cancel_timer(struct timer_list *timer) | 242 | static inline void k_cancel_timer(struct timer_list *timer) |
279 | { | 243 | { |
280 | dbg("cancelling timer %p\n", timer); | ||
281 | del_timer_sync(timer); | 244 | del_timer_sync(timer); |
282 | } | 245 | } |
283 | 246 | ||
@@ -295,7 +258,6 @@ static inline void k_cancel_timer(struct timer_list *timer) | |||
295 | 258 | ||
296 | static inline void k_term_timer(struct timer_list *timer) | 259 | static inline void k_term_timer(struct timer_list *timer) |
297 | { | 260 | { |
298 | dbg("terminating timer %p\n", timer); | ||
299 | } | 261 | } |
300 | 262 | ||
301 | 263 | ||
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 4a7cd3719b78..fa026bd91a68 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
@@ -35,12 +35,8 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "dbg.h" | ||
39 | #include "link.h" | 38 | #include "link.h" |
40 | #include "zone.h" | ||
41 | #include "discover.h" | 39 | #include "discover.h" |
42 | #include "port.h" | ||
43 | #include "name_table.h" | ||
44 | 40 | ||
45 | #define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */ | 41 | #define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */ |
46 | #define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */ | 42 | #define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */ |
@@ -134,8 +130,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) | |||
134 | u32 net_id = msg_bc_netid(msg); | 130 | u32 net_id = msg_bc_netid(msg); |
135 | u32 type = msg_type(msg); | 131 | u32 type = msg_type(msg); |
136 | 132 | ||
137 | msg_get_media_addr(msg,&media_addr); | 133 | msg_get_media_addr(msg, &media_addr); |
138 | msg_dbg(msg, "RECV:"); | ||
139 | buf_discard(buf); | 134 | buf_discard(buf); |
140 | 135 | ||
141 | if (net_id != tipc_net_id) | 136 | if (net_id != tipc_net_id) |
@@ -151,10 +146,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) | |||
151 | } | 146 | } |
152 | if (!tipc_in_scope(dest, tipc_own_addr)) | 147 | if (!tipc_in_scope(dest, tipc_own_addr)) |
153 | return; | 148 | return; |
154 | if (is_slave(tipc_own_addr) && is_slave(orig)) | ||
155 | return; | ||
156 | if (is_slave(orig) && !in_own_cluster(orig)) | ||
157 | return; | ||
158 | if (in_own_cluster(orig)) { | 149 | if (in_own_cluster(orig)) { |
159 | /* Always accept link here */ | 150 | /* Always accept link here */ |
160 | struct sk_buff *rbuf; | 151 | struct sk_buff *rbuf; |
@@ -162,7 +153,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) | |||
162 | struct tipc_node *n_ptr = tipc_node_find(orig); | 153 | struct tipc_node *n_ptr = tipc_node_find(orig); |
163 | int link_fully_up; | 154 | int link_fully_up; |
164 | 155 | ||
165 | dbg(" in own cluster\n"); | ||
166 | if (n_ptr == NULL) { | 156 | if (n_ptr == NULL) { |
167 | n_ptr = tipc_node_create(orig); | 157 | n_ptr = tipc_node_create(orig); |
168 | if (!n_ptr) | 158 | if (!n_ptr) |
@@ -179,7 +169,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) | |||
179 | 169 | ||
180 | link = n_ptr->links[b_ptr->identity]; | 170 | link = n_ptr->links[b_ptr->identity]; |
181 | if (!link) { | 171 | if (!link) { |
182 | dbg("creating link\n"); | ||
183 | link = tipc_link_create(b_ptr, orig, &media_addr); | 172 | link = tipc_link_create(b_ptr, orig, &media_addr); |
184 | if (!link) { | 173 | if (!link) { |
185 | spin_unlock_bh(&n_ptr->lock); | 174 | spin_unlock_bh(&n_ptr->lock); |
@@ -204,7 +193,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr) | |||
204 | return; | 193 | return; |
205 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); | 194 | rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr); |
206 | if (rbuf != NULL) { | 195 | if (rbuf != NULL) { |
207 | msg_dbg(buf_msg(rbuf),"SEND:"); | ||
208 | b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr); | 196 | b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr); |
209 | buf_discard(rbuf); | 197 | buf_discard(rbuf); |
210 | } | 198 | } |
diff --git a/net/tipc/discover.h b/net/tipc/discover.h index f8e750636123..d2c3cffb79fc 100644 --- a/net/tipc/discover.h +++ b/net/tipc/discover.h | |||
@@ -37,8 +37,6 @@ | |||
37 | #ifndef _TIPC_DISCOVER_H | 37 | #ifndef _TIPC_DISCOVER_H |
38 | #define _TIPC_DISCOVER_H | 38 | #define _TIPC_DISCOVER_H |
39 | 39 | ||
40 | #include "core.h" | ||
41 | |||
42 | struct link_req; | 40 | struct link_req; |
43 | 41 | ||
44 | struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr, | 42 | struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr, |
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 6e988ba485fd..b69092eb95d8 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c | |||
@@ -34,12 +34,8 @@ | |||
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <net/tipc/tipc.h> | 37 | #include "core.h" |
38 | #include <net/tipc/tipc_bearer.h> | 38 | #include "bearer.h" |
39 | #include <net/tipc/tipc_msg.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/slab.h> | ||
42 | #include <net/net_namespace.h> | ||
43 | 39 | ||
44 | #define MAX_ETH_BEARERS 2 | 40 | #define MAX_ETH_BEARERS 2 |
45 | #define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI | 41 | #define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI |
@@ -60,7 +56,7 @@ struct eth_bearer { | |||
60 | }; | 56 | }; |
61 | 57 | ||
62 | static struct eth_bearer eth_bearers[MAX_ETH_BEARERS]; | 58 | static struct eth_bearer eth_bearers[MAX_ETH_BEARERS]; |
63 | static int eth_started = 0; | 59 | static int eth_started; |
64 | static struct notifier_block notifier; | 60 | static struct notifier_block notifier; |
65 | 61 | ||
66 | /** | 62 | /** |
@@ -148,7 +144,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) | |||
148 | 144 | ||
149 | /* Find device with specified name */ | 145 | /* Find device with specified name */ |
150 | 146 | ||
151 | for_each_netdev(&init_net, pdev){ | 147 | for_each_netdev(&init_net, pdev) { |
152 | if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) { | 148 | if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) { |
153 | dev = pdev; | 149 | dev = pdev; |
154 | break; | 150 | break; |
@@ -159,7 +155,8 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) | |||
159 | 155 | ||
160 | /* Find Ethernet bearer for device (or create one) */ | 156 | /* Find Ethernet bearer for device (or create one) */ |
161 | 157 | ||
162 | for (;(eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev); eb_ptr++); | 158 | while ((eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev)) |
159 | eb_ptr++; | ||
163 | if (eb_ptr == stop) | 160 | if (eb_ptr == stop) |
164 | return -EDQUOT; | 161 | return -EDQUOT; |
165 | if (!eb_ptr->dev) { | 162 | if (!eb_ptr->dev) { |
diff --git a/net/tipc/handler.c b/net/tipc/handler.c index 0c70010a7dfe..274c98e164b7 100644 --- a/net/tipc/handler.c +++ b/net/tipc/handler.c | |||
@@ -45,7 +45,7 @@ struct queue_item { | |||
45 | static struct kmem_cache *tipc_queue_item_cache; | 45 | static struct kmem_cache *tipc_queue_item_cache; |
46 | static struct list_head signal_queue_head; | 46 | static struct list_head signal_queue_head; |
47 | static DEFINE_SPINLOCK(qitem_lock); | 47 | static DEFINE_SPINLOCK(qitem_lock); |
48 | static int handler_enabled = 0; | 48 | static int handler_enabled; |
49 | 49 | ||
50 | static void process_signal_queue(unsigned long dummy); | 50 | static void process_signal_queue(unsigned long dummy); |
51 | 51 | ||
diff --git a/net/tipc/link.c b/net/tipc/link.c index b31992ccd5d3..18702f58d111 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -35,19 +35,11 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "dbg.h" | ||
39 | #include "link.h" | 38 | #include "link.h" |
40 | #include "net.h" | ||
41 | #include "node.h" | ||
42 | #include "port.h" | 39 | #include "port.h" |
43 | #include "addr.h" | ||
44 | #include "node_subscr.h" | ||
45 | #include "name_distr.h" | 40 | #include "name_distr.h" |
46 | #include "bearer.h" | ||
47 | #include "name_table.h" | ||
48 | #include "discover.h" | 41 | #include "discover.h" |
49 | #include "config.h" | 42 | #include "config.h" |
50 | #include "bcast.h" | ||
51 | 43 | ||
52 | 44 | ||
53 | /* | 45 | /* |
@@ -57,12 +49,6 @@ | |||
57 | #define INVALID_SESSION 0x10000 | 49 | #define INVALID_SESSION 0x10000 |
58 | 50 | ||
59 | /* | 51 | /* |
60 | * Limit for deferred reception queue: | ||
61 | */ | ||
62 | |||
63 | #define DEF_QUEUE_LIMIT 256u | ||
64 | |||
65 | /* | ||
66 | * Link state events: | 52 | * Link state events: |
67 | */ | 53 | */ |
68 | 54 | ||
@@ -110,75 +96,10 @@ static int link_send_sections_long(struct port *sender, | |||
110 | static void link_check_defragm_bufs(struct link *l_ptr); | 96 | static void link_check_defragm_bufs(struct link *l_ptr); |
111 | static void link_state_event(struct link *l_ptr, u32 event); | 97 | static void link_state_event(struct link *l_ptr, u32 event); |
112 | static void link_reset_statistics(struct link *l_ptr); | 98 | static void link_reset_statistics(struct link *l_ptr); |
113 | static void link_print(struct link *l_ptr, struct print_buf *buf, | 99 | static void link_print(struct link *l_ptr, const char *str); |
114 | const char *str); | ||
115 | static void link_start(struct link *l_ptr); | 100 | static void link_start(struct link *l_ptr); |
116 | static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf); | 101 | static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf); |
117 | 102 | ||
118 | |||
119 | /* | ||
120 | * Debugging code used by link routines only | ||
121 | * | ||
122 | * When debugging link problems on a system that has multiple links, | ||
123 | * the standard TIPC debugging routines may not be useful since they | ||
124 | * allow the output from multiple links to be intermixed. For this reason | ||
125 | * routines of the form "dbg_link_XXX()" have been created that will capture | ||
126 | * debug info into a link's personal print buffer, which can then be dumped | ||
127 | * into the TIPC system log (TIPC_LOG) upon request. | ||
128 | * | ||
129 | * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size | ||
130 | * of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0, | ||
131 | * the dbg_link_XXX() routines simply send their output to the standard | ||
132 | * debug print buffer (DBG_OUTPUT), if it has been defined; this can be useful | ||
133 | * when there is only a single link in the system being debugged. | ||
134 | * | ||
135 | * Notes: | ||
136 | * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE | ||
137 | * - "l_ptr" must be valid when using dbg_link_XXX() macros | ||
138 | */ | ||
139 | |||
140 | #define LINK_LOG_BUF_SIZE 0 | ||
141 | |||
142 | #define dbg_link(fmt, arg...) \ | ||
143 | do { \ | ||
144 | if (LINK_LOG_BUF_SIZE) \ | ||
145 | tipc_printf(&l_ptr->print_buf, fmt, ## arg); \ | ||
146 | } while (0) | ||
147 | #define dbg_link_msg(msg, txt) \ | ||
148 | do { \ | ||
149 | if (LINK_LOG_BUF_SIZE) \ | ||
150 | tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \ | ||
151 | } while (0) | ||
152 | #define dbg_link_state(txt) \ | ||
153 | do { \ | ||
154 | if (LINK_LOG_BUF_SIZE) \ | ||
155 | link_print(l_ptr, &l_ptr->print_buf, txt); \ | ||
156 | } while (0) | ||
157 | #define dbg_link_dump() do { \ | ||
158 | if (LINK_LOG_BUF_SIZE) { \ | ||
159 | tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \ | ||
160 | tipc_printbuf_move(LOG, &l_ptr->print_buf); \ | ||
161 | } \ | ||
162 | } while (0) | ||
163 | |||
164 | static void dbg_print_link(struct link *l_ptr, const char *str) | ||
165 | { | ||
166 | if (DBG_OUTPUT != TIPC_NULL) | ||
167 | link_print(l_ptr, DBG_OUTPUT, str); | ||
168 | } | ||
169 | |||
170 | static void dbg_print_buf_chain(struct sk_buff *root_buf) | ||
171 | { | ||
172 | if (DBG_OUTPUT != TIPC_NULL) { | ||
173 | struct sk_buff *buf = root_buf; | ||
174 | |||
175 | while (buf) { | ||
176 | msg_dbg(buf_msg(buf), "In chain: "); | ||
177 | buf = buf->next; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /* | 103 | /* |
183 | * Simple link routines | 104 | * Simple link routines |
184 | */ | 105 | */ |
@@ -266,14 +187,17 @@ static int link_name_validate(const char *name, struct link_name *name_parts) | |||
266 | /* ensure all component parts of link name are present */ | 187 | /* ensure all component parts of link name are present */ |
267 | 188 | ||
268 | addr_local = name_copy; | 189 | addr_local = name_copy; |
269 | if ((if_local = strchr(addr_local, ':')) == NULL) | 190 | if_local = strchr(addr_local, ':'); |
191 | if (if_local == NULL) | ||
270 | return 0; | 192 | return 0; |
271 | *(if_local++) = 0; | 193 | *(if_local++) = 0; |
272 | if ((addr_peer = strchr(if_local, '-')) == NULL) | 194 | addr_peer = strchr(if_local, '-'); |
195 | if (addr_peer == NULL) | ||
273 | return 0; | 196 | return 0; |
274 | *(addr_peer++) = 0; | 197 | *(addr_peer++) = 0; |
275 | if_local_len = addr_peer - if_local; | 198 | if_local_len = addr_peer - if_local; |
276 | if ((if_peer = strchr(addr_peer, ':')) == NULL) | 199 | if_peer = strchr(addr_peer, ':'); |
200 | if (if_peer == NULL) | ||
277 | return 0; | 201 | return 0; |
278 | *(if_peer++) = 0; | 202 | *(if_peer++) = 0; |
279 | if_peer_len = strlen(if_peer) + 1; | 203 | if_peer_len = strlen(if_peer) + 1; |
@@ -392,17 +316,6 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer, | |||
392 | return NULL; | 316 | return NULL; |
393 | } | 317 | } |
394 | 318 | ||
395 | if (LINK_LOG_BUF_SIZE) { | ||
396 | char *pb = kmalloc(LINK_LOG_BUF_SIZE, GFP_ATOMIC); | ||
397 | |||
398 | if (!pb) { | ||
399 | kfree(l_ptr); | ||
400 | warn("Link creation failed, no memory for print buffer\n"); | ||
401 | return NULL; | ||
402 | } | ||
403 | tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE); | ||
404 | } | ||
405 | |||
406 | l_ptr->addr = peer; | 319 | l_ptr->addr = peer; |
407 | if_name = strchr(b_ptr->publ.name, ':') + 1; | 320 | if_name = strchr(b_ptr->publ.name, ':') + 1; |
408 | sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:", | 321 | sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:", |
@@ -437,8 +350,6 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer, | |||
437 | 350 | ||
438 | l_ptr->owner = tipc_node_attach_link(l_ptr); | 351 | l_ptr->owner = tipc_node_attach_link(l_ptr); |
439 | if (!l_ptr->owner) { | 352 | if (!l_ptr->owner) { |
440 | if (LINK_LOG_BUF_SIZE) | ||
441 | kfree(l_ptr->print_buf.buf); | ||
442 | kfree(l_ptr); | 353 | kfree(l_ptr); |
443 | return NULL; | 354 | return NULL; |
444 | } | 355 | } |
@@ -447,9 +358,6 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer, | |||
447 | list_add_tail(&l_ptr->link_list, &b_ptr->links); | 358 | list_add_tail(&l_ptr->link_list, &b_ptr->links); |
448 | tipc_k_signal((Handler)link_start, (unsigned long)l_ptr); | 359 | tipc_k_signal((Handler)link_start, (unsigned long)l_ptr); |
449 | 360 | ||
450 | dbg("tipc_link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n", | ||
451 | l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit); | ||
452 | |||
453 | return l_ptr; | 361 | return l_ptr; |
454 | } | 362 | } |
455 | 363 | ||
@@ -469,8 +377,6 @@ void tipc_link_delete(struct link *l_ptr) | |||
469 | return; | 377 | return; |
470 | } | 378 | } |
471 | 379 | ||
472 | dbg("tipc_link_delete()\n"); | ||
473 | |||
474 | k_cancel_timer(&l_ptr->timer); | 380 | k_cancel_timer(&l_ptr->timer); |
475 | 381 | ||
476 | tipc_node_lock(l_ptr->owner); | 382 | tipc_node_lock(l_ptr->owner); |
@@ -478,8 +384,6 @@ void tipc_link_delete(struct link *l_ptr) | |||
478 | tipc_node_detach_link(l_ptr->owner, l_ptr); | 384 | tipc_node_detach_link(l_ptr->owner, l_ptr); |
479 | tipc_link_stop(l_ptr); | 385 | tipc_link_stop(l_ptr); |
480 | list_del_init(&l_ptr->link_list); | 386 | list_del_init(&l_ptr->link_list); |
481 | if (LINK_LOG_BUF_SIZE) | ||
482 | kfree(l_ptr->print_buf.buf); | ||
483 | tipc_node_unlock(l_ptr->owner); | 387 | tipc_node_unlock(l_ptr->owner); |
484 | k_term_timer(&l_ptr->timer); | 388 | k_term_timer(&l_ptr->timer); |
485 | kfree(l_ptr); | 389 | kfree(l_ptr); |
@@ -487,7 +391,6 @@ void tipc_link_delete(struct link *l_ptr) | |||
487 | 391 | ||
488 | static void link_start(struct link *l_ptr) | 392 | static void link_start(struct link *l_ptr) |
489 | { | 393 | { |
490 | dbg("link_start %x\n", l_ptr); | ||
491 | link_state_event(l_ptr, STARTING_EVT); | 394 | link_state_event(l_ptr, STARTING_EVT); |
492 | } | 395 | } |
493 | 396 | ||
@@ -639,7 +542,6 @@ void tipc_link_reset(struct link *l_ptr) | |||
639 | link_init_max_pkt(l_ptr); | 542 | link_init_max_pkt(l_ptr); |
640 | 543 | ||
641 | l_ptr->state = RESET_UNKNOWN; | 544 | l_ptr->state = RESET_UNKNOWN; |
642 | dbg_link_state("Resetting Link\n"); | ||
643 | 545 | ||
644 | if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET)) | 546 | if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET)) |
645 | return; | 547 | return; |
@@ -713,25 +615,18 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
713 | return; /* Not yet. */ | 615 | return; /* Not yet. */ |
714 | 616 | ||
715 | if (link_blocked(l_ptr)) { | 617 | if (link_blocked(l_ptr)) { |
716 | if (event == TIMEOUT_EVT) { | 618 | if (event == TIMEOUT_EVT) |
717 | link_set_timer(l_ptr, cont_intv); | 619 | link_set_timer(l_ptr, cont_intv); |
718 | } | ||
719 | return; /* Changeover going on */ | 620 | return; /* Changeover going on */ |
720 | } | 621 | } |
721 | dbg_link("STATE_EV: <%s> ", l_ptr->name); | ||
722 | 622 | ||
723 | switch (l_ptr->state) { | 623 | switch (l_ptr->state) { |
724 | case WORKING_WORKING: | 624 | case WORKING_WORKING: |
725 | dbg_link("WW/"); | ||
726 | switch (event) { | 625 | switch (event) { |
727 | case TRAFFIC_MSG_EVT: | 626 | case TRAFFIC_MSG_EVT: |
728 | dbg_link("TRF-"); | ||
729 | /* fall through */ | ||
730 | case ACTIVATE_MSG: | 627 | case ACTIVATE_MSG: |
731 | dbg_link("ACT\n"); | ||
732 | break; | 628 | break; |
733 | case TIMEOUT_EVT: | 629 | case TIMEOUT_EVT: |
734 | dbg_link("TIM "); | ||
735 | if (l_ptr->next_in_no != l_ptr->checkpoint) { | 630 | if (l_ptr->next_in_no != l_ptr->checkpoint) { |
736 | l_ptr->checkpoint = l_ptr->next_in_no; | 631 | l_ptr->checkpoint = l_ptr->next_in_no; |
737 | if (tipc_bclink_acks_missing(l_ptr->owner)) { | 632 | if (tipc_bclink_acks_missing(l_ptr->owner)) { |
@@ -746,7 +641,6 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
746 | link_set_timer(l_ptr, cont_intv); | 641 | link_set_timer(l_ptr, cont_intv); |
747 | break; | 642 | break; |
748 | } | 643 | } |
749 | dbg_link(" -> WU\n"); | ||
750 | l_ptr->state = WORKING_UNKNOWN; | 644 | l_ptr->state = WORKING_UNKNOWN; |
751 | l_ptr->fsm_msg_cnt = 0; | 645 | l_ptr->fsm_msg_cnt = 0; |
752 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); | 646 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); |
@@ -754,7 +648,6 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
754 | link_set_timer(l_ptr, cont_intv / 4); | 648 | link_set_timer(l_ptr, cont_intv / 4); |
755 | break; | 649 | break; |
756 | case RESET_MSG: | 650 | case RESET_MSG: |
757 | dbg_link("RES -> RR\n"); | ||
758 | info("Resetting link <%s>, requested by peer\n", | 651 | info("Resetting link <%s>, requested by peer\n", |
759 | l_ptr->name); | 652 | l_ptr->name); |
760 | tipc_link_reset(l_ptr); | 653 | tipc_link_reset(l_ptr); |
@@ -769,18 +662,14 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
769 | } | 662 | } |
770 | break; | 663 | break; |
771 | case WORKING_UNKNOWN: | 664 | case WORKING_UNKNOWN: |
772 | dbg_link("WU/"); | ||
773 | switch (event) { | 665 | switch (event) { |
774 | case TRAFFIC_MSG_EVT: | 666 | case TRAFFIC_MSG_EVT: |
775 | dbg_link("TRF-"); | ||
776 | case ACTIVATE_MSG: | 667 | case ACTIVATE_MSG: |
777 | dbg_link("ACT -> WW\n"); | ||
778 | l_ptr->state = WORKING_WORKING; | 668 | l_ptr->state = WORKING_WORKING; |
779 | l_ptr->fsm_msg_cnt = 0; | 669 | l_ptr->fsm_msg_cnt = 0; |
780 | link_set_timer(l_ptr, cont_intv); | 670 | link_set_timer(l_ptr, cont_intv); |
781 | break; | 671 | break; |
782 | case RESET_MSG: | 672 | case RESET_MSG: |
783 | dbg_link("RES -> RR\n"); | ||
784 | info("Resetting link <%s>, requested by peer " | 673 | info("Resetting link <%s>, requested by peer " |
785 | "while probing\n", l_ptr->name); | 674 | "while probing\n", l_ptr->name); |
786 | tipc_link_reset(l_ptr); | 675 | tipc_link_reset(l_ptr); |
@@ -791,9 +680,7 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
791 | link_set_timer(l_ptr, cont_intv); | 680 | link_set_timer(l_ptr, cont_intv); |
792 | break; | 681 | break; |
793 | case TIMEOUT_EVT: | 682 | case TIMEOUT_EVT: |
794 | dbg_link("TIM "); | ||
795 | if (l_ptr->next_in_no != l_ptr->checkpoint) { | 683 | if (l_ptr->next_in_no != l_ptr->checkpoint) { |
796 | dbg_link("-> WW\n"); | ||
797 | l_ptr->state = WORKING_WORKING; | 684 | l_ptr->state = WORKING_WORKING; |
798 | l_ptr->fsm_msg_cnt = 0; | 685 | l_ptr->fsm_msg_cnt = 0; |
799 | l_ptr->checkpoint = l_ptr->next_in_no; | 686 | l_ptr->checkpoint = l_ptr->next_in_no; |
@@ -804,16 +691,11 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
804 | } | 691 | } |
805 | link_set_timer(l_ptr, cont_intv); | 692 | link_set_timer(l_ptr, cont_intv); |
806 | } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) { | 693 | } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) { |
807 | dbg_link("Probing %u/%u,timer = %u ms)\n", | ||
808 | l_ptr->fsm_msg_cnt, l_ptr->abort_limit, | ||
809 | cont_intv / 4); | ||
810 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, | 694 | tipc_link_send_proto_msg(l_ptr, STATE_MSG, |
811 | 1, 0, 0, 0, 0); | 695 | 1, 0, 0, 0, 0); |
812 | l_ptr->fsm_msg_cnt++; | 696 | l_ptr->fsm_msg_cnt++; |
813 | link_set_timer(l_ptr, cont_intv / 4); | 697 | link_set_timer(l_ptr, cont_intv / 4); |
814 | } else { /* Link has failed */ | 698 | } else { /* Link has failed */ |
815 | dbg_link("-> RU (%u probes unanswered)\n", | ||
816 | l_ptr->fsm_msg_cnt); | ||
817 | warn("Resetting link <%s>, peer not responding\n", | 699 | warn("Resetting link <%s>, peer not responding\n", |
818 | l_ptr->name); | 700 | l_ptr->name); |
819 | tipc_link_reset(l_ptr); | 701 | tipc_link_reset(l_ptr); |
@@ -830,18 +712,13 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
830 | } | 712 | } |
831 | break; | 713 | break; |
832 | case RESET_UNKNOWN: | 714 | case RESET_UNKNOWN: |
833 | dbg_link("RU/"); | ||
834 | switch (event) { | 715 | switch (event) { |
835 | case TRAFFIC_MSG_EVT: | 716 | case TRAFFIC_MSG_EVT: |
836 | dbg_link("TRF-\n"); | ||
837 | break; | 717 | break; |
838 | case ACTIVATE_MSG: | 718 | case ACTIVATE_MSG: |
839 | other = l_ptr->owner->active_links[0]; | 719 | other = l_ptr->owner->active_links[0]; |
840 | if (other && link_working_unknown(other)) { | 720 | if (other && link_working_unknown(other)) |
841 | dbg_link("ACT\n"); | ||
842 | break; | 721 | break; |
843 | } | ||
844 | dbg_link("ACT -> WW\n"); | ||
845 | l_ptr->state = WORKING_WORKING; | 722 | l_ptr->state = WORKING_WORKING; |
846 | l_ptr->fsm_msg_cnt = 0; | 723 | l_ptr->fsm_msg_cnt = 0; |
847 | link_activate(l_ptr); | 724 | link_activate(l_ptr); |
@@ -850,8 +727,6 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
850 | link_set_timer(l_ptr, cont_intv); | 727 | link_set_timer(l_ptr, cont_intv); |
851 | break; | 728 | break; |
852 | case RESET_MSG: | 729 | case RESET_MSG: |
853 | dbg_link("RES\n"); | ||
854 | dbg_link(" -> RR\n"); | ||
855 | l_ptr->state = RESET_RESET; | 730 | l_ptr->state = RESET_RESET; |
856 | l_ptr->fsm_msg_cnt = 0; | 731 | l_ptr->fsm_msg_cnt = 0; |
857 | tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0); | 732 | tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0); |
@@ -859,11 +734,9 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
859 | link_set_timer(l_ptr, cont_intv); | 734 | link_set_timer(l_ptr, cont_intv); |
860 | break; | 735 | break; |
861 | case STARTING_EVT: | 736 | case STARTING_EVT: |
862 | dbg_link("START-"); | ||
863 | l_ptr->started = 1; | 737 | l_ptr->started = 1; |
864 | /* fall through */ | 738 | /* fall through */ |
865 | case TIMEOUT_EVT: | 739 | case TIMEOUT_EVT: |
866 | dbg_link("TIM\n"); | ||
867 | tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0); | 740 | tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0); |
868 | l_ptr->fsm_msg_cnt++; | 741 | l_ptr->fsm_msg_cnt++; |
869 | link_set_timer(l_ptr, cont_intv); | 742 | link_set_timer(l_ptr, cont_intv); |
@@ -873,18 +746,12 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
873 | } | 746 | } |
874 | break; | 747 | break; |
875 | case RESET_RESET: | 748 | case RESET_RESET: |
876 | dbg_link("RR/ "); | ||
877 | switch (event) { | 749 | switch (event) { |
878 | case TRAFFIC_MSG_EVT: | 750 | case TRAFFIC_MSG_EVT: |
879 | dbg_link("TRF-"); | ||
880 | /* fall through */ | ||
881 | case ACTIVATE_MSG: | 751 | case ACTIVATE_MSG: |
882 | other = l_ptr->owner->active_links[0]; | 752 | other = l_ptr->owner->active_links[0]; |
883 | if (other && link_working_unknown(other)) { | 753 | if (other && link_working_unknown(other)) |
884 | dbg_link("ACT\n"); | ||
885 | break; | 754 | break; |
886 | } | ||
887 | dbg_link("ACT -> WW\n"); | ||
888 | l_ptr->state = WORKING_WORKING; | 755 | l_ptr->state = WORKING_WORKING; |
889 | l_ptr->fsm_msg_cnt = 0; | 756 | l_ptr->fsm_msg_cnt = 0; |
890 | link_activate(l_ptr); | 757 | link_activate(l_ptr); |
@@ -893,14 +760,11 @@ static void link_state_event(struct link *l_ptr, unsigned event) | |||
893 | link_set_timer(l_ptr, cont_intv); | 760 | link_set_timer(l_ptr, cont_intv); |
894 | break; | 761 | break; |
895 | case RESET_MSG: | 762 | case RESET_MSG: |
896 | dbg_link("RES\n"); | ||
897 | break; | 763 | break; |
898 | case TIMEOUT_EVT: | 764 | case TIMEOUT_EVT: |
899 | dbg_link("TIM\n"); | ||
900 | tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0); | 765 | tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0); |
901 | l_ptr->fsm_msg_cnt++; | 766 | l_ptr->fsm_msg_cnt++; |
902 | link_set_timer(l_ptr, cont_intv); | 767 | link_set_timer(l_ptr, cont_intv); |
903 | dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt); | ||
904 | break; | 768 | break; |
905 | default: | 769 | default: |
906 | err("Unknown link event %u in RR state\n", event); | 770 | err("Unknown link event %u in RR state\n", event); |
@@ -940,9 +804,6 @@ static int link_bundle_buf(struct link *l_ptr, | |||
940 | skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size); | 804 | skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size); |
941 | msg_set_size(bundler_msg, to_pos + size); | 805 | msg_set_size(bundler_msg, to_pos + size); |
942 | msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); | 806 | msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); |
943 | dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n", | ||
944 | msg_msgcnt(bundler_msg), size, to_pos, msg_seqno(bundler_msg)); | ||
945 | msg_dbg(msg, "PACKD:"); | ||
946 | buf_discard(buf); | 807 | buf_discard(buf); |
947 | l_ptr->stats.sent_bundled++; | 808 | l_ptr->stats.sent_bundled++; |
948 | return 1; | 809 | return 1; |
@@ -991,7 +852,6 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf) | |||
991 | return link_schedule_port(l_ptr, msg_origport(msg), | 852 | return link_schedule_port(l_ptr, msg_origport(msg), |
992 | size); | 853 | size); |
993 | } | 854 | } |
994 | msg_dbg(msg, "TIPC: Congestion, throwing away\n"); | ||
995 | buf_discard(buf); | 855 | buf_discard(buf); |
996 | if (imp > CONN_MANAGER) { | 856 | if (imp > CONN_MANAGER) { |
997 | warn("Resetting link <%s>, send queue full", l_ptr->name); | 857 | warn("Resetting link <%s>, send queue full", l_ptr->name); |
@@ -1075,22 +935,16 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector) | |||
1075 | int res = -ELINKCONG; | 935 | int res = -ELINKCONG; |
1076 | 936 | ||
1077 | read_lock_bh(&tipc_net_lock); | 937 | read_lock_bh(&tipc_net_lock); |
1078 | n_ptr = tipc_node_select(dest, selector); | 938 | n_ptr = tipc_node_find(dest); |
1079 | if (n_ptr) { | 939 | if (n_ptr) { |
1080 | tipc_node_lock(n_ptr); | 940 | tipc_node_lock(n_ptr); |
1081 | l_ptr = n_ptr->active_links[selector & 1]; | 941 | l_ptr = n_ptr->active_links[selector & 1]; |
1082 | if (l_ptr) { | 942 | if (l_ptr) |
1083 | dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest); | ||
1084 | res = tipc_link_send_buf(l_ptr, buf); | 943 | res = tipc_link_send_buf(l_ptr, buf); |
1085 | } else { | 944 | else |
1086 | dbg("Attempt to send msg to unreachable node:\n"); | ||
1087 | msg_dbg(buf_msg(buf),">>>"); | ||
1088 | buf_discard(buf); | 945 | buf_discard(buf); |
1089 | } | ||
1090 | tipc_node_unlock(n_ptr); | 946 | tipc_node_unlock(n_ptr); |
1091 | } else { | 947 | } else { |
1092 | dbg("Attempt to send msg to unknown node:\n"); | ||
1093 | msg_dbg(buf_msg(buf),">>>"); | ||
1094 | buf_discard(buf); | 948 | buf_discard(buf); |
1095 | } | 949 | } |
1096 | read_unlock_bh(&tipc_net_lock); | 950 | read_unlock_bh(&tipc_net_lock); |
@@ -1117,17 +971,14 @@ static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf, | |||
1117 | if (likely(tipc_bearer_send(l_ptr->b_ptr, buf, | 971 | if (likely(tipc_bearer_send(l_ptr->b_ptr, buf, |
1118 | &l_ptr->media_addr))) { | 972 | &l_ptr->media_addr))) { |
1119 | l_ptr->unacked_window = 0; | 973 | l_ptr->unacked_window = 0; |
1120 | msg_dbg(msg,"SENT_FAST:"); | ||
1121 | return res; | 974 | return res; |
1122 | } | 975 | } |
1123 | dbg("failed sent fast...\n"); | ||
1124 | tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); | 976 | tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); |
1125 | l_ptr->stats.bearer_congs++; | 977 | l_ptr->stats.bearer_congs++; |
1126 | l_ptr->next_out = buf; | 978 | l_ptr->next_out = buf; |
1127 | return res; | 979 | return res; |
1128 | } | 980 | } |
1129 | } | 981 | } else |
1130 | else | ||
1131 | *used_max_pkt = l_ptr->max_pkt; | 982 | *used_max_pkt = l_ptr->max_pkt; |
1132 | } | 983 | } |
1133 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ | 984 | return tipc_link_send_buf(l_ptr, buf); /* All other cases */ |
@@ -1151,12 +1002,10 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode) | |||
1151 | return tipc_port_recv_msg(buf); | 1002 | return tipc_port_recv_msg(buf); |
1152 | 1003 | ||
1153 | read_lock_bh(&tipc_net_lock); | 1004 | read_lock_bh(&tipc_net_lock); |
1154 | n_ptr = tipc_node_select(destnode, selector); | 1005 | n_ptr = tipc_node_find(destnode); |
1155 | if (likely(n_ptr)) { | 1006 | if (likely(n_ptr)) { |
1156 | tipc_node_lock(n_ptr); | 1007 | tipc_node_lock(n_ptr); |
1157 | l_ptr = n_ptr->active_links[selector]; | 1008 | l_ptr = n_ptr->active_links[selector]; |
1158 | dbg("send_fast: buf %x selected %x, destnode = %x\n", | ||
1159 | buf, l_ptr, destnode); | ||
1160 | if (likely(l_ptr)) { | 1009 | if (likely(l_ptr)) { |
1161 | res = link_send_buf_fast(l_ptr, buf, &dummy); | 1010 | res = link_send_buf_fast(l_ptr, buf, &dummy); |
1162 | tipc_node_unlock(n_ptr); | 1011 | tipc_node_unlock(n_ptr); |
@@ -1200,7 +1049,7 @@ again: | |||
1200 | !sender->user_port, &buf); | 1049 | !sender->user_port, &buf); |
1201 | 1050 | ||
1202 | read_lock_bh(&tipc_net_lock); | 1051 | read_lock_bh(&tipc_net_lock); |
1203 | node = tipc_node_select(destaddr, selector); | 1052 | node = tipc_node_find(destaddr); |
1204 | if (likely(node)) { | 1053 | if (likely(node)) { |
1205 | tipc_node_lock(node); | 1054 | tipc_node_lock(node); |
1206 | l_ptr = node->active_links[selector]; | 1055 | l_ptr = node->active_links[selector]; |
@@ -1283,10 +1132,10 @@ static int link_send_sections_long(struct port *sender, | |||
1283 | struct tipc_node *node; | 1132 | struct tipc_node *node; |
1284 | struct tipc_msg *hdr = &sender->publ.phdr; | 1133 | struct tipc_msg *hdr = &sender->publ.phdr; |
1285 | u32 dsz = msg_data_sz(hdr); | 1134 | u32 dsz = msg_data_sz(hdr); |
1286 | u32 max_pkt,fragm_sz,rest; | 1135 | u32 max_pkt, fragm_sz, rest; |
1287 | struct tipc_msg fragm_hdr; | 1136 | struct tipc_msg fragm_hdr; |
1288 | struct sk_buff *buf,*buf_chain,*prev; | 1137 | struct sk_buff *buf, *buf_chain, *prev; |
1289 | u32 fragm_crs,fragm_rest,hsz,sect_rest; | 1138 | u32 fragm_crs, fragm_rest, hsz, sect_rest; |
1290 | const unchar *sect_crs; | 1139 | const unchar *sect_crs; |
1291 | int curr_sect; | 1140 | int curr_sect; |
1292 | u32 fragm_no; | 1141 | u32 fragm_no; |
@@ -1306,7 +1155,6 @@ again: | |||
1306 | 1155 | ||
1307 | /* Prepare reusable fragment header: */ | 1156 | /* Prepare reusable fragment header: */ |
1308 | 1157 | ||
1309 | msg_dbg(hdr, ">FRAGMENTING>"); | ||
1310 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | 1158 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, |
1311 | INT_H_SIZE, msg_destnode(hdr)); | 1159 | INT_H_SIZE, msg_destnode(hdr)); |
1312 | msg_set_link_selector(&fragm_hdr, sender->publ.ref); | 1160 | msg_set_link_selector(&fragm_hdr, sender->publ.ref); |
@@ -1322,7 +1170,6 @@ again: | |||
1322 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); | 1170 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); |
1323 | hsz = msg_hdr_sz(hdr); | 1171 | hsz = msg_hdr_sz(hdr); |
1324 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz); | 1172 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz); |
1325 | msg_dbg(buf_msg(buf), ">BUILD>"); | ||
1326 | 1173 | ||
1327 | /* Chop up message: */ | 1174 | /* Chop up message: */ |
1328 | 1175 | ||
@@ -1365,7 +1212,7 @@ error: | |||
1365 | /* Initiate new fragment: */ | 1212 | /* Initiate new fragment: */ |
1366 | if (rest <= fragm_sz) { | 1213 | if (rest <= fragm_sz) { |
1367 | fragm_sz = rest; | 1214 | fragm_sz = rest; |
1368 | msg_set_type(&fragm_hdr,LAST_FRAGMENT); | 1215 | msg_set_type(&fragm_hdr, LAST_FRAGMENT); |
1369 | } else { | 1216 | } else { |
1370 | msg_set_type(&fragm_hdr, FRAGMENT); | 1217 | msg_set_type(&fragm_hdr, FRAGMENT); |
1371 | } | 1218 | } |
@@ -1381,16 +1228,14 @@ error: | |||
1381 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); | 1228 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); |
1382 | fragm_crs = INT_H_SIZE; | 1229 | fragm_crs = INT_H_SIZE; |
1383 | fragm_rest = fragm_sz; | 1230 | fragm_rest = fragm_sz; |
1384 | msg_dbg(buf_msg(buf)," >BUILD>"); | ||
1385 | } | 1231 | } |
1386 | } | 1232 | } while (rest > 0); |
1387 | while (rest > 0); | ||
1388 | 1233 | ||
1389 | /* | 1234 | /* |
1390 | * Now we have a buffer chain. Select a link and check | 1235 | * Now we have a buffer chain. Select a link and check |
1391 | * that packet size is still OK | 1236 | * that packet size is still OK |
1392 | */ | 1237 | */ |
1393 | node = tipc_node_select(destaddr, sender->publ.ref & 1); | 1238 | node = tipc_node_find(destaddr); |
1394 | if (likely(node)) { | 1239 | if (likely(node)) { |
1395 | tipc_node_lock(node); | 1240 | tipc_node_lock(node); |
1396 | l_ptr = node->active_links[sender->publ.ref & 1]; | 1241 | l_ptr = node->active_links[sender->publ.ref & 1]; |
@@ -1431,7 +1276,6 @@ reject: | |||
1431 | l_ptr->stats.sent_fragments++; | 1276 | l_ptr->stats.sent_fragments++; |
1432 | msg_set_long_msgno(msg, l_ptr->long_msg_seq_no); | 1277 | msg_set_long_msgno(msg, l_ptr->long_msg_seq_no); |
1433 | link_add_to_outqueue(l_ptr, buf, msg); | 1278 | link_add_to_outqueue(l_ptr, buf, msg); |
1434 | msg_dbg(msg, ">ADD>"); | ||
1435 | buf = next; | 1279 | buf = next; |
1436 | } | 1280 | } |
1437 | 1281 | ||
@@ -1473,14 +1317,12 @@ u32 tipc_link_push_packet(struct link *l_ptr) | |||
1473 | msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1)); | 1317 | msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1)); |
1474 | msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); | 1318 | msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); |
1475 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { | 1319 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { |
1476 | msg_dbg(buf_msg(buf), ">DEF-RETR>"); | ||
1477 | l_ptr->retransm_queue_head = mod(++r_q_head); | 1320 | l_ptr->retransm_queue_head = mod(++r_q_head); |
1478 | l_ptr->retransm_queue_size = --r_q_size; | 1321 | l_ptr->retransm_queue_size = --r_q_size; |
1479 | l_ptr->stats.retransmitted++; | 1322 | l_ptr->stats.retransmitted++; |
1480 | return 0; | 1323 | return 0; |
1481 | } else { | 1324 | } else { |
1482 | l_ptr->stats.bearer_congs++; | 1325 | l_ptr->stats.bearer_congs++; |
1483 | msg_dbg(buf_msg(buf), "|>DEF-RETR>"); | ||
1484 | return PUSH_FAILED; | 1326 | return PUSH_FAILED; |
1485 | } | 1327 | } |
1486 | } | 1328 | } |
@@ -1490,15 +1332,13 @@ u32 tipc_link_push_packet(struct link *l_ptr) | |||
1490 | buf = l_ptr->proto_msg_queue; | 1332 | buf = l_ptr->proto_msg_queue; |
1491 | if (buf) { | 1333 | if (buf) { |
1492 | msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1)); | 1334 | msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1)); |
1493 | msg_set_bcast_ack(buf_msg(buf),l_ptr->owner->bclink.last_in); | 1335 | msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); |
1494 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { | 1336 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { |
1495 | msg_dbg(buf_msg(buf), ">DEF-PROT>"); | ||
1496 | l_ptr->unacked_window = 0; | 1337 | l_ptr->unacked_window = 0; |
1497 | buf_discard(buf); | 1338 | buf_discard(buf); |
1498 | l_ptr->proto_msg_queue = NULL; | 1339 | l_ptr->proto_msg_queue = NULL; |
1499 | return 0; | 1340 | return 0; |
1500 | } else { | 1341 | } else { |
1501 | msg_dbg(buf_msg(buf), "|>DEF-PROT>"); | ||
1502 | l_ptr->stats.bearer_congs++; | 1342 | l_ptr->stats.bearer_congs++; |
1503 | return PUSH_FAILED; | 1343 | return PUSH_FAILED; |
1504 | } | 1344 | } |
@@ -1518,11 +1358,9 @@ u32 tipc_link_push_packet(struct link *l_ptr) | |||
1518 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { | 1358 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { |
1519 | if (msg_user(msg) == MSG_BUNDLER) | 1359 | if (msg_user(msg) == MSG_BUNDLER) |
1520 | msg_set_type(msg, CLOSED_MSG); | 1360 | msg_set_type(msg, CLOSED_MSG); |
1521 | msg_dbg(msg, ">PUSH-DATA>"); | ||
1522 | l_ptr->next_out = buf->next; | 1361 | l_ptr->next_out = buf->next; |
1523 | return 0; | 1362 | return 0; |
1524 | } else { | 1363 | } else { |
1525 | msg_dbg(msg, "|PUSH-DATA|"); | ||
1526 | l_ptr->stats.bearer_congs++; | 1364 | l_ptr->stats.bearer_congs++; |
1527 | return PUSH_FAILED; | 1365 | return PUSH_FAILED; |
1528 | } | 1366 | } |
@@ -1570,8 +1408,7 @@ static void link_reset_all(unsigned long addr) | |||
1570 | 1408 | ||
1571 | for (i = 0; i < MAX_BEARERS; i++) { | 1409 | for (i = 0; i < MAX_BEARERS; i++) { |
1572 | if (n_ptr->links[i]) { | 1410 | if (n_ptr->links[i]) { |
1573 | link_print(n_ptr->links[i], TIPC_OUTPUT, | 1411 | link_print(n_ptr->links[i], "Resetting link\n"); |
1574 | "Resetting link\n"); | ||
1575 | tipc_link_reset(n_ptr->links[i]); | 1412 | tipc_link_reset(n_ptr->links[i]); |
1576 | } | 1413 | } |
1577 | } | 1414 | } |
@@ -1585,13 +1422,12 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf) | |||
1585 | struct tipc_msg *msg = buf_msg(buf); | 1422 | struct tipc_msg *msg = buf_msg(buf); |
1586 | 1423 | ||
1587 | warn("Retransmission failure on link <%s>\n", l_ptr->name); | 1424 | warn("Retransmission failure on link <%s>\n", l_ptr->name); |
1588 | tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>"); | ||
1589 | 1425 | ||
1590 | if (l_ptr->addr) { | 1426 | if (l_ptr->addr) { |
1591 | 1427 | ||
1592 | /* Handle failure on standard link */ | 1428 | /* Handle failure on standard link */ |
1593 | 1429 | ||
1594 | link_print(l_ptr, TIPC_OUTPUT, "Resetting link\n"); | 1430 | link_print(l_ptr, "Resetting link\n"); |
1595 | tipc_link_reset(l_ptr); | 1431 | tipc_link_reset(l_ptr); |
1596 | 1432 | ||
1597 | } else { | 1433 | } else { |
@@ -1601,21 +1437,21 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf) | |||
1601 | struct tipc_node *n_ptr; | 1437 | struct tipc_node *n_ptr; |
1602 | char addr_string[16]; | 1438 | char addr_string[16]; |
1603 | 1439 | ||
1604 | tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg)); | 1440 | info("Msg seq number: %u, ", msg_seqno(msg)); |
1605 | tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n", | 1441 | info("Outstanding acks: %lu\n", |
1606 | (unsigned long) TIPC_SKB_CB(buf)->handle); | 1442 | (unsigned long) TIPC_SKB_CB(buf)->handle); |
1607 | 1443 | ||
1608 | n_ptr = l_ptr->owner->next; | 1444 | n_ptr = l_ptr->owner->next; |
1609 | tipc_node_lock(n_ptr); | 1445 | tipc_node_lock(n_ptr); |
1610 | 1446 | ||
1611 | tipc_addr_string_fill(addr_string, n_ptr->addr); | 1447 | tipc_addr_string_fill(addr_string, n_ptr->addr); |
1612 | tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string); | 1448 | info("Multicast link info for %s\n", addr_string); |
1613 | tipc_printf(TIPC_OUTPUT, "Supported: %d, ", n_ptr->bclink.supported); | 1449 | info("Supported: %d, ", n_ptr->bclink.supported); |
1614 | tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked); | 1450 | info("Acked: %u\n", n_ptr->bclink.acked); |
1615 | tipc_printf(TIPC_OUTPUT, "Last in: %u, ", n_ptr->bclink.last_in); | 1451 | info("Last in: %u, ", n_ptr->bclink.last_in); |
1616 | tipc_printf(TIPC_OUTPUT, "Gap after: %u, ", n_ptr->bclink.gap_after); | 1452 | info("Gap after: %u, ", n_ptr->bclink.gap_after); |
1617 | tipc_printf(TIPC_OUTPUT, "Gap to: %u\n", n_ptr->bclink.gap_to); | 1453 | info("Gap to: %u\n", n_ptr->bclink.gap_to); |
1618 | tipc_printf(TIPC_OUTPUT, "Nack sync: %u\n\n", n_ptr->bclink.nack_sync); | 1454 | info("Nack sync: %u\n\n", n_ptr->bclink.nack_sync); |
1619 | 1455 | ||
1620 | tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr); | 1456 | tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr); |
1621 | 1457 | ||
@@ -1635,12 +1471,8 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, | |||
1635 | 1471 | ||
1636 | msg = buf_msg(buf); | 1472 | msg = buf_msg(buf); |
1637 | 1473 | ||
1638 | dbg("Retransmitting %u in link %x\n", retransmits, l_ptr); | ||
1639 | |||
1640 | if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) { | 1474 | if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) { |
1641 | if (l_ptr->retransm_queue_size == 0) { | 1475 | if (l_ptr->retransm_queue_size == 0) { |
1642 | msg_dbg(msg, ">NO_RETR->BCONG>"); | ||
1643 | dbg_print_link(l_ptr, " "); | ||
1644 | l_ptr->retransm_queue_head = msg_seqno(msg); | 1476 | l_ptr->retransm_queue_head = msg_seqno(msg); |
1645 | l_ptr->retransm_queue_size = retransmits; | 1477 | l_ptr->retransm_queue_size = retransmits; |
1646 | } else { | 1478 | } else { |
@@ -1667,7 +1499,6 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, | |||
1667 | msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); | 1499 | msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); |
1668 | msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); | 1500 | msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); |
1669 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { | 1501 | if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { |
1670 | msg_dbg(buf_msg(buf), ">RETR>"); | ||
1671 | buf = buf->next; | 1502 | buf = buf->next; |
1672 | retransmits--; | 1503 | retransmits--; |
1673 | l_ptr->stats.retransmitted++; | 1504 | l_ptr->stats.retransmitted++; |
@@ -1793,9 +1624,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) | |||
1793 | 1624 | ||
1794 | /* Ensure message data is a single contiguous unit */ | 1625 | /* Ensure message data is a single contiguous unit */ |
1795 | 1626 | ||
1796 | if (unlikely(buf_linearize(buf))) { | 1627 | if (unlikely(buf_linearize(buf))) |
1797 | goto cont; | 1628 | goto cont; |
1798 | } | ||
1799 | 1629 | ||
1800 | /* Handle arrival of a non-unicast link message */ | 1630 | /* Handle arrival of a non-unicast link message */ |
1801 | 1631 | ||
@@ -1907,7 +1737,7 @@ deliver: | |||
1907 | continue; | 1737 | continue; |
1908 | case ROUTE_DISTRIBUTOR: | 1738 | case ROUTE_DISTRIBUTOR: |
1909 | tipc_node_unlock(n_ptr); | 1739 | tipc_node_unlock(n_ptr); |
1910 | tipc_cltr_recv_routing_table(buf); | 1740 | buf_discard(buf); |
1911 | continue; | 1741 | continue; |
1912 | case NAME_DISTRIBUTOR: | 1742 | case NAME_DISTRIBUTOR: |
1913 | tipc_node_unlock(n_ptr); | 1743 | tipc_node_unlock(n_ptr); |
@@ -1953,12 +1783,10 @@ deliver: | |||
1953 | tipc_node_unlock(n_ptr); | 1783 | tipc_node_unlock(n_ptr); |
1954 | continue; | 1784 | continue; |
1955 | } | 1785 | } |
1956 | msg_dbg(msg,"NSEQ<REC<"); | ||
1957 | link_state_event(l_ptr, TRAFFIC_MSG_EVT); | 1786 | link_state_event(l_ptr, TRAFFIC_MSG_EVT); |
1958 | 1787 | ||
1959 | if (link_working_working(l_ptr)) { | 1788 | if (link_working_working(l_ptr)) { |
1960 | /* Re-insert in front of queue */ | 1789 | /* Re-insert in front of queue */ |
1961 | msg_dbg(msg,"RECV-REINS:"); | ||
1962 | buf->next = head; | 1790 | buf->next = head; |
1963 | head = buf; | 1791 | head = buf; |
1964 | tipc_node_unlock(n_ptr); | 1792 | tipc_node_unlock(n_ptr); |
@@ -2012,13 +1840,11 @@ u32 tipc_link_defer_pkt(struct sk_buff **head, | |||
2012 | *head = buf; | 1840 | *head = buf; |
2013 | return 1; | 1841 | return 1; |
2014 | } | 1842 | } |
2015 | if (seq_no == msg_seqno(msg)) { | 1843 | if (seq_no == msg_seqno(msg)) |
2016 | break; | 1844 | break; |
2017 | } | ||
2018 | prev = crs; | 1845 | prev = crs; |
2019 | crs = crs->next; | 1846 | crs = crs->next; |
2020 | } | 1847 | } while (crs); |
2021 | while (crs); | ||
2022 | 1848 | ||
2023 | /* Message is a duplicate of an existing message */ | 1849 | /* Message is a duplicate of an existing message */ |
2024 | 1850 | ||
@@ -2040,9 +1866,6 @@ static void link_handle_out_of_seq_msg(struct link *l_ptr, | |||
2040 | return; | 1866 | return; |
2041 | } | 1867 | } |
2042 | 1868 | ||
2043 | dbg("rx OOS msg: seq_no %u, expecting %u (%u)\n", | ||
2044 | seq_no, mod(l_ptr->next_in_no), l_ptr->next_in_no); | ||
2045 | |||
2046 | /* Record OOS packet arrival (force mismatch on next timeout) */ | 1869 | /* Record OOS packet arrival (force mismatch on next timeout) */ |
2047 | 1870 | ||
2048 | l_ptr->checkpoint--; | 1871 | l_ptr->checkpoint--; |
@@ -2132,11 +1955,10 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg, | |||
2132 | msg_set_max_pkt(msg, l_ptr->max_pkt_target); | 1955 | msg_set_max_pkt(msg, l_ptr->max_pkt_target); |
2133 | } | 1956 | } |
2134 | 1957 | ||
2135 | if (tipc_node_has_redundant_links(l_ptr->owner)) { | 1958 | if (tipc_node_has_redundant_links(l_ptr->owner)) |
2136 | msg_set_redundant_link(msg); | 1959 | msg_set_redundant_link(msg); |
2137 | } else { | 1960 | else |
2138 | msg_clear_redundant_link(msg); | 1961 | msg_clear_redundant_link(msg); |
2139 | } | ||
2140 | msg_set_linkprio(msg, l_ptr->priority); | 1962 | msg_set_linkprio(msg, l_ptr->priority); |
2141 | 1963 | ||
2142 | /* Ensure sequence number will not fit : */ | 1964 | /* Ensure sequence number will not fit : */ |
@@ -2160,8 +1982,6 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg, | |||
2160 | 1982 | ||
2161 | /* Message can be sent */ | 1983 | /* Message can be sent */ |
2162 | 1984 | ||
2163 | msg_dbg(msg, ">>"); | ||
2164 | |||
2165 | buf = tipc_buf_acquire(msg_size); | 1985 | buf = tipc_buf_acquire(msg_size); |
2166 | if (!buf) | 1986 | if (!buf) |
2167 | return; | 1987 | return; |
@@ -2195,8 +2015,6 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2195 | u32 msg_tol; | 2015 | u32 msg_tol; |
2196 | struct tipc_msg *msg = buf_msg(buf); | 2016 | struct tipc_msg *msg = buf_msg(buf); |
2197 | 2017 | ||
2198 | dbg("AT(%u):", jiffies_to_msecs(jiffies)); | ||
2199 | msg_dbg(msg, "<<"); | ||
2200 | if (link_blocked(l_ptr)) | 2018 | if (link_blocked(l_ptr)) |
2201 | goto exit; | 2019 | goto exit; |
2202 | 2020 | ||
@@ -2215,11 +2033,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2215 | case RESET_MSG: | 2033 | case RESET_MSG: |
2216 | if (!link_working_unknown(l_ptr) && | 2034 | if (!link_working_unknown(l_ptr) && |
2217 | (l_ptr->peer_session != INVALID_SESSION)) { | 2035 | (l_ptr->peer_session != INVALID_SESSION)) { |
2218 | if (msg_session(msg) == l_ptr->peer_session) { | 2036 | if (msg_session(msg) == l_ptr->peer_session) |
2219 | dbg("Duplicate RESET: %u<->%u\n", | ||
2220 | msg_session(msg), l_ptr->peer_session); | ||
2221 | break; /* duplicate: ignore */ | 2037 | break; /* duplicate: ignore */ |
2222 | } | ||
2223 | } | 2038 | } |
2224 | /* fall thru' */ | 2039 | /* fall thru' */ |
2225 | case ACTIVATE_MSG: | 2040 | case ACTIVATE_MSG: |
@@ -2227,8 +2042,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2227 | 2042 | ||
2228 | strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg)); | 2043 | strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg)); |
2229 | 2044 | ||
2230 | if ((msg_tol = msg_link_tolerance(msg)) && | 2045 | msg_tol = msg_link_tolerance(msg); |
2231 | (msg_tol > l_ptr->tolerance)) | 2046 | if (msg_tol > l_ptr->tolerance) |
2232 | link_set_supervision_props(l_ptr, msg_tol); | 2047 | link_set_supervision_props(l_ptr, msg_tol); |
2233 | 2048 | ||
2234 | if (msg_linkprio(msg) > l_ptr->priority) | 2049 | if (msg_linkprio(msg) > l_ptr->priority) |
@@ -2251,13 +2066,13 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2251 | l_ptr->peer_bearer_id = msg_bearer_id(msg); | 2066 | l_ptr->peer_bearer_id = msg_bearer_id(msg); |
2252 | 2067 | ||
2253 | /* Synchronize broadcast sequence numbers */ | 2068 | /* Synchronize broadcast sequence numbers */ |
2254 | if (!tipc_node_has_redundant_links(l_ptr->owner)) { | 2069 | if (!tipc_node_has_redundant_links(l_ptr->owner)) |
2255 | l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg)); | 2070 | l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg)); |
2256 | } | ||
2257 | break; | 2071 | break; |
2258 | case STATE_MSG: | 2072 | case STATE_MSG: |
2259 | 2073 | ||
2260 | if ((msg_tol = msg_link_tolerance(msg))) | 2074 | msg_tol = msg_link_tolerance(msg); |
2075 | if (msg_tol) | ||
2261 | link_set_supervision_props(l_ptr, msg_tol); | 2076 | link_set_supervision_props(l_ptr, msg_tol); |
2262 | 2077 | ||
2263 | if (msg_linkprio(msg) && | 2078 | if (msg_linkprio(msg) && |
@@ -2280,8 +2095,6 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2280 | 2095 | ||
2281 | max_pkt_ack = msg_max_pkt(msg); | 2096 | max_pkt_ack = msg_max_pkt(msg); |
2282 | if (max_pkt_ack > l_ptr->max_pkt) { | 2097 | if (max_pkt_ack > l_ptr->max_pkt) { |
2283 | dbg("Link <%s> updated MTU %u -> %u\n", | ||
2284 | l_ptr->name, l_ptr->max_pkt, max_pkt_ack); | ||
2285 | l_ptr->max_pkt = max_pkt_ack; | 2098 | l_ptr->max_pkt = max_pkt_ack; |
2286 | l_ptr->max_pkt_probes = 0; | 2099 | l_ptr->max_pkt_probes = 0; |
2287 | } | 2100 | } |
@@ -2289,9 +2102,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2289 | max_pkt_ack = 0; | 2102 | max_pkt_ack = 0; |
2290 | if (msg_probe(msg)) { | 2103 | if (msg_probe(msg)) { |
2291 | l_ptr->stats.recv_probes++; | 2104 | l_ptr->stats.recv_probes++; |
2292 | if (msg_size(msg) > sizeof(l_ptr->proto_msg)) { | 2105 | if (msg_size(msg) > sizeof(l_ptr->proto_msg)) |
2293 | max_pkt_ack = msg_size(msg); | 2106 | max_pkt_ack = msg_size(msg); |
2294 | } | ||
2295 | } | 2107 | } |
2296 | 2108 | ||
2297 | /* Protocol message before retransmits, reduce loss risk */ | 2109 | /* Protocol message before retransmits, reduce loss risk */ |
@@ -2303,14 +2115,11 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) | |||
2303 | 0, rec_gap, 0, 0, max_pkt_ack); | 2115 | 0, rec_gap, 0, 0, max_pkt_ack); |
2304 | } | 2116 | } |
2305 | if (msg_seq_gap(msg)) { | 2117 | if (msg_seq_gap(msg)) { |
2306 | msg_dbg(msg, "With Gap:"); | ||
2307 | l_ptr->stats.recv_nacks++; | 2118 | l_ptr->stats.recv_nacks++; |
2308 | tipc_link_retransmit(l_ptr, l_ptr->first_out, | 2119 | tipc_link_retransmit(l_ptr, l_ptr->first_out, |
2309 | msg_seq_gap(msg)); | 2120 | msg_seq_gap(msg)); |
2310 | } | 2121 | } |
2311 | break; | 2122 | break; |
2312 | default: | ||
2313 | msg_dbg(buf_msg(buf), "<DISCARDING UNKNOWN<"); | ||
2314 | } | 2123 | } |
2315 | exit: | 2124 | exit: |
2316 | buf_discard(buf); | 2125 | buf_discard(buf); |
@@ -2345,8 +2154,6 @@ static void tipc_link_tunnel(struct link *l_ptr, | |||
2345 | } | 2154 | } |
2346 | skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE); | 2155 | skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE); |
2347 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length); | 2156 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length); |
2348 | dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane); | ||
2349 | msg_dbg(buf_msg(buf), ">SEND>"); | ||
2350 | tipc_link_send_buf(tunnel, buf); | 2157 | tipc_link_send_buf(tunnel, buf); |
2351 | } | 2158 | } |
2352 | 2159 | ||
@@ -2378,7 +2185,6 @@ void tipc_link_changeover(struct link *l_ptr) | |||
2378 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); | 2185 | ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); |
2379 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); | 2186 | msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id); |
2380 | msg_set_msgcnt(&tunnel_hdr, msgcount); | 2187 | msg_set_msgcnt(&tunnel_hdr, msgcount); |
2381 | dbg("Link changeover requires %u tunnel messages\n", msgcount); | ||
2382 | 2188 | ||
2383 | if (!l_ptr->first_out) { | 2189 | if (!l_ptr->first_out) { |
2384 | struct sk_buff *buf; | 2190 | struct sk_buff *buf; |
@@ -2387,9 +2193,6 @@ void tipc_link_changeover(struct link *l_ptr) | |||
2387 | if (buf) { | 2193 | if (buf) { |
2388 | skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE); | 2194 | skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE); |
2389 | msg_set_size(&tunnel_hdr, INT_H_SIZE); | 2195 | msg_set_size(&tunnel_hdr, INT_H_SIZE); |
2390 | dbg("%c->%c:", l_ptr->b_ptr->net_plane, | ||
2391 | tunnel->b_ptr->net_plane); | ||
2392 | msg_dbg(&tunnel_hdr, "EMPTY>SEND>"); | ||
2393 | tipc_link_send_buf(tunnel, buf); | 2196 | tipc_link_send_buf(tunnel, buf); |
2394 | } else { | 2197 | } else { |
2395 | warn("Link changeover error, " | 2198 | warn("Link changeover error, " |
@@ -2406,11 +2209,11 @@ void tipc_link_changeover(struct link *l_ptr) | |||
2406 | 2209 | ||
2407 | if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) { | 2210 | if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) { |
2408 | struct tipc_msg *m = msg_get_wrapped(msg); | 2211 | struct tipc_msg *m = msg_get_wrapped(msg); |
2409 | unchar* pos = (unchar*)m; | 2212 | unchar *pos = (unchar *)m; |
2410 | 2213 | ||
2411 | msgcount = msg_msgcnt(msg); | 2214 | msgcount = msg_msgcnt(msg); |
2412 | while (msgcount--) { | 2215 | while (msgcount--) { |
2413 | msg_set_seqno(m,msg_seqno(msg)); | 2216 | msg_set_seqno(m, msg_seqno(msg)); |
2414 | tipc_link_tunnel(l_ptr, &tunnel_hdr, m, | 2217 | tipc_link_tunnel(l_ptr, &tunnel_hdr, m, |
2415 | msg_link_selector(m)); | 2218 | msg_link_selector(m)); |
2416 | pos += align(msg_size(m)); | 2219 | pos += align(msg_size(m)); |
@@ -2453,9 +2256,6 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel) | |||
2453 | skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE); | 2256 | skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE); |
2454 | skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data, | 2257 | skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data, |
2455 | length); | 2258 | length); |
2456 | dbg("%c->%c:", l_ptr->b_ptr->net_plane, | ||
2457 | tunnel->b_ptr->net_plane); | ||
2458 | msg_dbg(buf_msg(outbuf), ">SEND>"); | ||
2459 | tipc_link_send_buf(tunnel, outbuf); | 2259 | tipc_link_send_buf(tunnel, outbuf); |
2460 | if (!tipc_link_is_up(l_ptr)) | 2260 | if (!tipc_link_is_up(l_ptr)) |
2461 | return; | 2261 | return; |
@@ -2502,31 +2302,24 @@ static int link_recv_changeover_msg(struct link **l_ptr, | |||
2502 | u32 msg_count = msg_msgcnt(tunnel_msg); | 2302 | u32 msg_count = msg_msgcnt(tunnel_msg); |
2503 | 2303 | ||
2504 | dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)]; | 2304 | dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)]; |
2505 | if (!dest_link) { | 2305 | if (!dest_link) |
2506 | msg_dbg(tunnel_msg, "NOLINK/<REC<"); | ||
2507 | goto exit; | 2306 | goto exit; |
2508 | } | ||
2509 | if (dest_link == *l_ptr) { | 2307 | if (dest_link == *l_ptr) { |
2510 | err("Unexpected changeover message on link <%s>\n", | 2308 | err("Unexpected changeover message on link <%s>\n", |
2511 | (*l_ptr)->name); | 2309 | (*l_ptr)->name); |
2512 | goto exit; | 2310 | goto exit; |
2513 | } | 2311 | } |
2514 | dbg("%c<-%c:", dest_link->b_ptr->net_plane, | ||
2515 | (*l_ptr)->b_ptr->net_plane); | ||
2516 | *l_ptr = dest_link; | 2312 | *l_ptr = dest_link; |
2517 | msg = msg_get_wrapped(tunnel_msg); | 2313 | msg = msg_get_wrapped(tunnel_msg); |
2518 | 2314 | ||
2519 | if (msg_typ == DUPLICATE_MSG) { | 2315 | if (msg_typ == DUPLICATE_MSG) { |
2520 | if (less(msg_seqno(msg), mod(dest_link->next_in_no))) { | 2316 | if (less(msg_seqno(msg), mod(dest_link->next_in_no))) |
2521 | msg_dbg(tunnel_msg, "DROP/<REC<"); | ||
2522 | goto exit; | 2317 | goto exit; |
2523 | } | 2318 | *buf = buf_extract(tunnel_buf, INT_H_SIZE); |
2524 | *buf = buf_extract(tunnel_buf,INT_H_SIZE); | ||
2525 | if (*buf == NULL) { | 2319 | if (*buf == NULL) { |
2526 | warn("Link changeover error, duplicate msg dropped\n"); | 2320 | warn("Link changeover error, duplicate msg dropped\n"); |
2527 | goto exit; | 2321 | goto exit; |
2528 | } | 2322 | } |
2529 | msg_dbg(tunnel_msg, "TNL<REC<"); | ||
2530 | buf_discard(tunnel_buf); | 2323 | buf_discard(tunnel_buf); |
2531 | return 1; | 2324 | return 1; |
2532 | } | 2325 | } |
@@ -2534,18 +2327,14 @@ static int link_recv_changeover_msg(struct link **l_ptr, | |||
2534 | /* First original message ?: */ | 2327 | /* First original message ?: */ |
2535 | 2328 | ||
2536 | if (tipc_link_is_up(dest_link)) { | 2329 | if (tipc_link_is_up(dest_link)) { |
2537 | msg_dbg(tunnel_msg, "UP/FIRST/<REC<"); | ||
2538 | info("Resetting link <%s>, changeover initiated by peer\n", | 2330 | info("Resetting link <%s>, changeover initiated by peer\n", |
2539 | dest_link->name); | 2331 | dest_link->name); |
2540 | tipc_link_reset(dest_link); | 2332 | tipc_link_reset(dest_link); |
2541 | dest_link->exp_msg_count = msg_count; | 2333 | dest_link->exp_msg_count = msg_count; |
2542 | dbg("Expecting %u tunnelled messages\n", msg_count); | ||
2543 | if (!msg_count) | 2334 | if (!msg_count) |
2544 | goto exit; | 2335 | goto exit; |
2545 | } else if (dest_link->exp_msg_count == START_CHANGEOVER) { | 2336 | } else if (dest_link->exp_msg_count == START_CHANGEOVER) { |
2546 | msg_dbg(tunnel_msg, "BLK/FIRST/<REC<"); | ||
2547 | dest_link->exp_msg_count = msg_count; | 2337 | dest_link->exp_msg_count = msg_count; |
2548 | dbg("Expecting %u tunnelled messages\n", msg_count); | ||
2549 | if (!msg_count) | 2338 | if (!msg_count) |
2550 | goto exit; | 2339 | goto exit; |
2551 | } | 2340 | } |
@@ -2555,18 +2344,14 @@ static int link_recv_changeover_msg(struct link **l_ptr, | |||
2555 | if (dest_link->exp_msg_count == 0) { | 2344 | if (dest_link->exp_msg_count == 0) { |
2556 | warn("Link switchover error, " | 2345 | warn("Link switchover error, " |
2557 | "got too many tunnelled messages\n"); | 2346 | "got too many tunnelled messages\n"); |
2558 | msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<"); | ||
2559 | dbg_print_link(dest_link, "LINK:"); | ||
2560 | goto exit; | 2347 | goto exit; |
2561 | } | 2348 | } |
2562 | dest_link->exp_msg_count--; | 2349 | dest_link->exp_msg_count--; |
2563 | if (less(msg_seqno(msg), dest_link->reset_checkpoint)) { | 2350 | if (less(msg_seqno(msg), dest_link->reset_checkpoint)) { |
2564 | msg_dbg(tunnel_msg, "DROP/DUPL/<REC<"); | ||
2565 | goto exit; | 2351 | goto exit; |
2566 | } else { | 2352 | } else { |
2567 | *buf = buf_extract(tunnel_buf, INT_H_SIZE); | 2353 | *buf = buf_extract(tunnel_buf, INT_H_SIZE); |
2568 | if (*buf != NULL) { | 2354 | if (*buf != NULL) { |
2569 | msg_dbg(tunnel_msg, "TNL<REC<"); | ||
2570 | buf_discard(tunnel_buf); | 2355 | buf_discard(tunnel_buf); |
2571 | return 1; | 2356 | return 1; |
2572 | } else { | 2357 | } else { |
@@ -2588,7 +2373,6 @@ void tipc_link_recv_bundle(struct sk_buff *buf) | |||
2588 | u32 pos = INT_H_SIZE; | 2373 | u32 pos = INT_H_SIZE; |
2589 | struct sk_buff *obuf; | 2374 | struct sk_buff *obuf; |
2590 | 2375 | ||
2591 | msg_dbg(buf_msg(buf), "<BNDL<: "); | ||
2592 | while (msgcount--) { | 2376 | while (msgcount--) { |
2593 | obuf = buf_extract(buf, pos); | 2377 | obuf = buf_extract(buf, pos); |
2594 | if (obuf == NULL) { | 2378 | if (obuf == NULL) { |
@@ -2596,7 +2380,6 @@ void tipc_link_recv_bundle(struct sk_buff *buf) | |||
2596 | break; | 2380 | break; |
2597 | } | 2381 | } |
2598 | pos += align(msg_size(buf_msg(obuf))); | 2382 | pos += align(msg_size(buf_msg(obuf))); |
2599 | msg_dbg(buf_msg(obuf), " /"); | ||
2600 | tipc_net_route_msg(obuf); | 2383 | tipc_net_route_msg(obuf); |
2601 | } | 2384 | } |
2602 | buf_discard(buf); | 2385 | buf_discard(buf); |
@@ -2733,7 +2516,6 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | |||
2733 | u32 long_msg_seq_no = msg_long_msgno(fragm); | 2516 | u32 long_msg_seq_no = msg_long_msgno(fragm); |
2734 | 2517 | ||
2735 | *fb = NULL; | 2518 | *fb = NULL; |
2736 | msg_dbg(fragm,"FRG<REC<"); | ||
2737 | 2519 | ||
2738 | /* Is there an incomplete message waiting for this fragment? */ | 2520 | /* Is there an incomplete message waiting for this fragment? */ |
2739 | 2521 | ||
@@ -2752,7 +2534,6 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | |||
2752 | if (msg_type(imsg) == TIPC_MCAST_MSG) | 2534 | if (msg_type(imsg) == TIPC_MCAST_MSG) |
2753 | max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; | 2535 | max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; |
2754 | if (msg_size(imsg) > max) { | 2536 | if (msg_size(imsg) > max) { |
2755 | msg_dbg(fragm,"<REC<Oversized: "); | ||
2756 | buf_discard(fbuf); | 2537 | buf_discard(fbuf); |
2757 | return 0; | 2538 | return 0; |
2758 | } | 2539 | } |
@@ -2765,8 +2546,8 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | |||
2765 | /* Prepare buffer for subsequent fragments. */ | 2546 | /* Prepare buffer for subsequent fragments. */ |
2766 | 2547 | ||
2767 | set_long_msg_seqno(pbuf, long_msg_seq_no); | 2548 | set_long_msg_seqno(pbuf, long_msg_seq_no); |
2768 | set_fragm_size(pbuf,fragm_sz); | 2549 | set_fragm_size(pbuf, fragm_sz); |
2769 | set_expected_frags(pbuf,exp_fragm_cnt - 1); | 2550 | set_expected_frags(pbuf, exp_fragm_cnt - 1); |
2770 | } else { | 2551 | } else { |
2771 | warn("Link unable to reassemble fragmented message\n"); | 2552 | warn("Link unable to reassemble fragmented message\n"); |
2772 | } | 2553 | } |
@@ -2793,13 +2574,9 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | |||
2793 | *m = buf_msg(pbuf); | 2574 | *m = buf_msg(pbuf); |
2794 | return 1; | 2575 | return 1; |
2795 | } | 2576 | } |
2796 | set_expected_frags(pbuf,exp_frags); | 2577 | set_expected_frags(pbuf, exp_frags); |
2797 | return 0; | 2578 | return 0; |
2798 | } | 2579 | } |
2799 | dbg(" Discarding orphan fragment %x\n",fbuf); | ||
2800 | msg_dbg(fragm,"ORPHAN:"); | ||
2801 | dbg("Pending long buffers:\n"); | ||
2802 | dbg_print_buf_chain(*pending); | ||
2803 | buf_discard(fbuf); | 2580 | buf_discard(fbuf); |
2804 | return 0; | 2581 | return 0; |
2805 | } | 2582 | } |
@@ -2827,11 +2604,6 @@ static void link_check_defragm_bufs(struct link *l_ptr) | |||
2827 | incr_timer_cnt(buf); | 2604 | incr_timer_cnt(buf); |
2828 | prev = buf; | 2605 | prev = buf; |
2829 | } else { | 2606 | } else { |
2830 | dbg(" Discarding incomplete long buffer\n"); | ||
2831 | msg_dbg(buf_msg(buf), "LONG:"); | ||
2832 | dbg_print_link(l_ptr, "curr:"); | ||
2833 | dbg("Pending long buffers:\n"); | ||
2834 | dbg_print_buf_chain(l_ptr->defragm_buf); | ||
2835 | if (prev) | 2607 | if (prev) |
2836 | prev->next = buf->next; | 2608 | prev->next = buf->next; |
2837 | else | 2609 | else |
@@ -2866,7 +2638,6 @@ void tipc_link_set_queue_limits(struct link *l_ptr, u32 window) | |||
2866 | l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900; | 2638 | l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900; |
2867 | l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200; | 2639 | l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200; |
2868 | l_ptr->queue_limit[CONN_MANAGER] = 1200; | 2640 | l_ptr->queue_limit[CONN_MANAGER] = 1200; |
2869 | l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200; | ||
2870 | l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500; | 2641 | l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500; |
2871 | l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000; | 2642 | l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000; |
2872 | /* FRAGMENT and LAST_FRAGMENT packets */ | 2643 | /* FRAGMENT and LAST_FRAGMENT packets */ |
@@ -3168,7 +2939,7 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector) | |||
3168 | return MAX_MSG_SIZE; | 2939 | return MAX_MSG_SIZE; |
3169 | 2940 | ||
3170 | read_lock_bh(&tipc_net_lock); | 2941 | read_lock_bh(&tipc_net_lock); |
3171 | n_ptr = tipc_node_select(dest, selector); | 2942 | n_ptr = tipc_node_find(dest); |
3172 | if (n_ptr) { | 2943 | if (n_ptr) { |
3173 | tipc_node_lock(n_ptr); | 2944 | tipc_node_lock(n_ptr); |
3174 | l_ptr = n_ptr->active_links[selector & 1]; | 2945 | l_ptr = n_ptr->active_links[selector & 1]; |
@@ -3180,27 +2951,22 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector) | |||
3180 | return res; | 2951 | return res; |
3181 | } | 2952 | } |
3182 | 2953 | ||
3183 | static void link_dump_send_queue(struct link *l_ptr) | 2954 | static void link_print(struct link *l_ptr, const char *str) |
3184 | { | 2955 | { |
3185 | if (l_ptr->next_out) { | 2956 | char print_area[256]; |
3186 | info("\nContents of unsent queue:\n"); | 2957 | struct print_buf pb; |
3187 | dbg_print_buf_chain(l_ptr->next_out); | 2958 | struct print_buf *buf = &pb; |
3188 | } | 2959 | |
3189 | info("\nContents of send queue:\n"); | 2960 | tipc_printbuf_init(buf, print_area, sizeof(print_area)); |
3190 | if (l_ptr->first_out) { | ||
3191 | dbg_print_buf_chain(l_ptr->first_out); | ||
3192 | } | ||
3193 | info("Empty send queue\n"); | ||
3194 | } | ||
3195 | 2961 | ||
3196 | static void link_print(struct link *l_ptr, struct print_buf *buf, | ||
3197 | const char *str) | ||
3198 | { | ||
3199 | tipc_printf(buf, str); | 2962 | tipc_printf(buf, str); |
3200 | if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr)) | ||
3201 | return; | ||
3202 | tipc_printf(buf, "Link %x<%s>:", | 2963 | tipc_printf(buf, "Link %x<%s>:", |
3203 | l_ptr->addr, l_ptr->b_ptr->publ.name); | 2964 | l_ptr->addr, l_ptr->b_ptr->publ.name); |
2965 | |||
2966 | #ifdef CONFIG_TIPC_DEBUG | ||
2967 | if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr)) | ||
2968 | goto print_state; | ||
2969 | |||
3204 | tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no)); | 2970 | tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no)); |
3205 | tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no)); | 2971 | tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no)); |
3206 | tipc_printf(buf, "SQUE"); | 2972 | tipc_printf(buf, "SQUE"); |
@@ -3218,7 +2984,6 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, | |||
3218 | tipc_printf(buf, "first_out= %x ", l_ptr->first_out); | 2984 | tipc_printf(buf, "first_out= %x ", l_ptr->first_out); |
3219 | tipc_printf(buf, "next_out= %x ", l_ptr->next_out); | 2985 | tipc_printf(buf, "next_out= %x ", l_ptr->next_out); |
3220 | tipc_printf(buf, "last_out= %x ", l_ptr->last_out); | 2986 | tipc_printf(buf, "last_out= %x ", l_ptr->last_out); |
3221 | link_dump_send_queue(l_ptr); | ||
3222 | } | 2987 | } |
3223 | } else | 2988 | } else |
3224 | tipc_printf(buf, "[]"); | 2989 | tipc_printf(buf, "[]"); |
@@ -3232,14 +2997,20 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, | |||
3232 | l_ptr->deferred_inqueue_sz); | 2997 | l_ptr->deferred_inqueue_sz); |
3233 | } | 2998 | } |
3234 | } | 2999 | } |
3000 | print_state: | ||
3001 | #endif | ||
3002 | |||
3235 | if (link_working_unknown(l_ptr)) | 3003 | if (link_working_unknown(l_ptr)) |
3236 | tipc_printf(buf, ":WU"); | 3004 | tipc_printf(buf, ":WU"); |
3237 | if (link_reset_reset(l_ptr)) | 3005 | else if (link_reset_reset(l_ptr)) |
3238 | tipc_printf(buf, ":RR"); | 3006 | tipc_printf(buf, ":RR"); |
3239 | if (link_reset_unknown(l_ptr)) | 3007 | else if (link_reset_unknown(l_ptr)) |
3240 | tipc_printf(buf, ":RU"); | 3008 | tipc_printf(buf, ":RU"); |
3241 | if (link_working_working(l_ptr)) | 3009 | else if (link_working_working(l_ptr)) |
3242 | tipc_printf(buf, ":WW"); | 3010 | tipc_printf(buf, ":WW"); |
3243 | tipc_printf(buf, "\n"); | 3011 | tipc_printf(buf, "\n"); |
3012 | |||
3013 | tipc_printbuf_validate(buf); | ||
3014 | info("%s", print_area); | ||
3244 | } | 3015 | } |
3245 | 3016 | ||
diff --git a/net/tipc/link.h b/net/tipc/link.h index f98bc613de67..70967e637027 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
@@ -37,9 +37,8 @@ | |||
37 | #ifndef _TIPC_LINK_H | 37 | #ifndef _TIPC_LINK_H |
38 | #define _TIPC_LINK_H | 38 | #define _TIPC_LINK_H |
39 | 39 | ||
40 | #include "dbg.h" | 40 | #include "log.h" |
41 | #include "msg.h" | 41 | #include "msg.h" |
42 | #include "bearer.h" | ||
43 | #include "node.h" | 42 | #include "node.h" |
44 | 43 | ||
45 | #define PUSH_FAILED 1 | 44 | #define PUSH_FAILED 1 |
@@ -108,7 +107,6 @@ | |||
108 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages | 107 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages |
109 | * @defragm_buf: list of partially reassembled inbound message fragments | 108 | * @defragm_buf: list of partially reassembled inbound message fragments |
110 | * @stats: collects statistics regarding link activity | 109 | * @stats: collects statistics regarding link activity |
111 | * @print_buf: print buffer used to log link activity | ||
112 | */ | 110 | */ |
113 | 111 | ||
114 | struct link { | 112 | struct link { |
@@ -211,8 +209,6 @@ struct link { | |||
211 | u32 msg_lengths_total; | 209 | u32 msg_lengths_total; |
212 | u32 msg_length_profile[7]; | 210 | u32 msg_length_profile[7]; |
213 | } stats; | 211 | } stats; |
214 | |||
215 | struct print_buf print_buf; | ||
216 | }; | 212 | }; |
217 | 213 | ||
218 | struct port; | 214 | struct port; |
@@ -233,8 +229,8 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_ | |||
233 | void tipc_link_reset(struct link *l_ptr); | 229 | void tipc_link_reset(struct link *l_ptr); |
234 | int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); | 230 | int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); |
235 | int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf); | 231 | int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf); |
236 | u32 tipc_link_get_max_pkt(u32 dest,u32 selector); | 232 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); |
237 | int tipc_link_send_sections_fast(struct port* sender, | 233 | int tipc_link_send_sections_fast(struct port *sender, |
238 | struct iovec const *msg_sect, | 234 | struct iovec const *msg_sect, |
239 | const u32 num_sect, | 235 | const u32 num_sect, |
240 | u32 destnode); | 236 | u32 destnode); |
diff --git a/net/tipc/dbg.c b/net/tipc/log.c index 46f51d208e5e..952c39f643e6 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/log.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/dbg.c: TIPC print buffer routines for debugging | 2 | * net/tipc/log.c: TIPC print buffer routines for debugging |
3 | * | 3 | * |
4 | * Copyright (c) 1996-2006, Ericsson AB | 4 | * Copyright (c) 1996-2006, Ericsson AB |
5 | * Copyright (c) 2005-2007, Wind River Systems | 5 | * Copyright (c) 2005-2007, Wind River Systems |
@@ -36,7 +36,7 @@ | |||
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "config.h" | 38 | #include "config.h" |
39 | #include "dbg.h" | 39 | #include "log.h" |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * TIPC pre-defines the following print buffers: | 42 | * TIPC pre-defines the following print buffers: |
@@ -52,7 +52,7 @@ static struct print_buf null_buf = { NULL, 0, NULL, 0 }; | |||
52 | struct print_buf *const TIPC_NULL = &null_buf; | 52 | struct print_buf *const TIPC_NULL = &null_buf; |
53 | 53 | ||
54 | static struct print_buf cons_buf = { NULL, 0, NULL, 1 }; | 54 | static struct print_buf cons_buf = { NULL, 0, NULL, 1 }; |
55 | static struct print_buf *const TIPC_CONS = &cons_buf; | 55 | struct print_buf *const TIPC_CONS = &cons_buf; |
56 | 56 | ||
57 | static struct print_buf log_buf = { NULL, 0, NULL, 1 }; | 57 | static struct print_buf log_buf = { NULL, 0, NULL, 1 }; |
58 | struct print_buf *const TIPC_LOG = &log_buf; | 58 | struct print_buf *const TIPC_LOG = &log_buf; |
@@ -64,9 +64,9 @@ struct print_buf *const TIPC_LOG = &log_buf; | |||
64 | * 'print_string' when writing to a print buffer. This also protects against | 64 | * 'print_string' when writing to a print buffer. This also protects against |
65 | * concurrent writes to the print buffer being written to. | 65 | * concurrent writes to the print buffer being written to. |
66 | * | 66 | * |
67 | * 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned | 67 | * 2) tipc_log_XXX() leverages the aforementioned use of 'print_lock' to |
68 | * use of 'print_lock' to protect against all types of concurrent operations | 68 | * protect against all types of concurrent operations on their associated |
69 | * on their associated print buffer (not just write operations). | 69 | * print buffer (not just write operations). |
70 | * | 70 | * |
71 | * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely | 71 | * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely |
72 | * on the caller to prevent simultaneous use of the print buffer(s) being | 72 | * on the caller to prevent simultaneous use of the print buffer(s) being |
@@ -76,18 +76,16 @@ struct print_buf *const TIPC_LOG = &log_buf; | |||
76 | static char print_string[TIPC_PB_MAX_STR]; | 76 | static char print_string[TIPC_PB_MAX_STR]; |
77 | static DEFINE_SPINLOCK(print_lock); | 77 | static DEFINE_SPINLOCK(print_lock); |
78 | 78 | ||
79 | static void tipc_printbuf_reset(struct print_buf *pb); | ||
80 | static int tipc_printbuf_empty(struct print_buf *pb); | ||
81 | static void tipc_printbuf_move(struct print_buf *pb_to, | 79 | static void tipc_printbuf_move(struct print_buf *pb_to, |
82 | struct print_buf *pb_from); | 80 | struct print_buf *pb_from); |
83 | 81 | ||
84 | #define FORMAT(PTR,LEN,FMT) \ | 82 | #define FORMAT(PTR, LEN, FMT) \ |
85 | {\ | 83 | {\ |
86 | va_list args;\ | 84 | va_list args;\ |
87 | va_start(args, FMT);\ | 85 | va_start(args, FMT);\ |
88 | LEN = vsprintf(PTR, FMT, args);\ | 86 | LEN = vsprintf(PTR, FMT, args);\ |
89 | va_end(args);\ | 87 | va_end(args);\ |
90 | *(PTR + LEN) = '\0';\ | 88 | *(PTR + LEN) = '\0';\ |
91 | } | 89 | } |
92 | 90 | ||
93 | /** | 91 | /** |
@@ -268,81 +266,6 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) | |||
268 | spin_unlock_bh(&print_lock); | 266 | spin_unlock_bh(&print_lock); |
269 | } | 267 | } |
270 | 268 | ||
271 | #ifdef CONFIG_TIPC_DEBUG | ||
272 | |||
273 | /** | ||
274 | * print_to_console - write string of bytes to console in multiple chunks | ||
275 | */ | ||
276 | |||
277 | static void print_to_console(char *crs, int len) | ||
278 | { | ||
279 | int rest = len; | ||
280 | |||
281 | while (rest > 0) { | ||
282 | int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR; | ||
283 | char c = crs[sz]; | ||
284 | |||
285 | crs[sz] = 0; | ||
286 | printk((const char *)crs); | ||
287 | crs[sz] = c; | ||
288 | rest -= sz; | ||
289 | crs += sz; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * printbuf_dump - write print buffer contents to console | ||
295 | */ | ||
296 | |||
297 | static void printbuf_dump(struct print_buf *pb) | ||
298 | { | ||
299 | int len; | ||
300 | |||
301 | if (!pb->buf) { | ||
302 | printk("*** PRINT BUFFER NOT ALLOCATED ***"); | ||
303 | return; | ||
304 | } | ||
305 | |||
306 | /* Dump print buffer from char after cursor to end (if used) */ | ||
307 | |||
308 | len = pb->buf + pb->size - pb->crs - 2; | ||
309 | if ((pb->buf[pb->size - 1] == 0) && (len > 0)) | ||
310 | print_to_console(pb->crs + 1, len); | ||
311 | |||
312 | /* Dump print buffer from start to cursor (always) */ | ||
313 | |||
314 | len = pb->crs - pb->buf; | ||
315 | print_to_console(pb->buf, len); | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * tipc_dump_dbg - dump (non-console) print buffer to console | ||
320 | * @pb: pointer to print buffer | ||
321 | */ | ||
322 | |||
323 | void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...) | ||
324 | { | ||
325 | int len; | ||
326 | |||
327 | if (pb == TIPC_CONS) | ||
328 | return; | ||
329 | |||
330 | spin_lock_bh(&print_lock); | ||
331 | |||
332 | FORMAT(print_string, len, fmt); | ||
333 | printk(print_string); | ||
334 | |||
335 | printk("\n---- Start of %s log dump ----\n\n", | ||
336 | (pb == TIPC_LOG) ? "global" : "local"); | ||
337 | printbuf_dump(pb); | ||
338 | tipc_printbuf_reset(pb); | ||
339 | printk("\n---- End of dump ----\n"); | ||
340 | |||
341 | spin_unlock_bh(&print_lock); | ||
342 | } | ||
343 | |||
344 | #endif | ||
345 | |||
346 | /** | 269 | /** |
347 | * tipc_log_resize - change the size of the TIPC log buffer | 270 | * tipc_log_resize - change the size of the TIPC log buffer |
348 | * @log_size: print buffer size to use | 271 | * @log_size: print buffer size to use |
@@ -353,10 +276,8 @@ int tipc_log_resize(int log_size) | |||
353 | int res = 0; | 276 | int res = 0; |
354 | 277 | ||
355 | spin_lock_bh(&print_lock); | 278 | spin_lock_bh(&print_lock); |
356 | if (TIPC_LOG->buf) { | 279 | kfree(TIPC_LOG->buf); |
357 | kfree(TIPC_LOG->buf); | 280 | TIPC_LOG->buf = NULL; |
358 | TIPC_LOG->buf = NULL; | ||
359 | } | ||
360 | if (log_size) { | 281 | if (log_size) { |
361 | if (log_size < TIPC_PB_MIN_SIZE) | 282 | if (log_size < TIPC_PB_MIN_SIZE) |
362 | log_size = TIPC_PB_MIN_SIZE; | 283 | log_size = TIPC_PB_MIN_SIZE; |
@@ -407,8 +328,7 @@ struct sk_buff *tipc_log_dump(void) | |||
407 | } else if (tipc_printbuf_empty(TIPC_LOG)) { | 328 | } else if (tipc_printbuf_empty(TIPC_LOG)) { |
408 | spin_unlock_bh(&print_lock); | 329 | spin_unlock_bh(&print_lock); |
409 | reply = tipc_cfg_reply_ultra_string("log is empty\n"); | 330 | reply = tipc_cfg_reply_ultra_string("log is empty\n"); |
410 | } | 331 | } else { |
411 | else { | ||
412 | struct tlv_desc *rep_tlv; | 332 | struct tlv_desc *rep_tlv; |
413 | struct print_buf pb; | 333 | struct print_buf pb; |
414 | int str_len; | 334 | int str_len; |
@@ -429,4 +349,3 @@ struct sk_buff *tipc_log_dump(void) | |||
429 | } | 349 | } |
430 | return reply; | 350 | return reply; |
431 | } | 351 | } |
432 | |||
diff --git a/net/tipc/dbg.h b/net/tipc/log.h index 3ba6ba8b434a..2248d96238e6 100644 --- a/net/tipc/dbg.h +++ b/net/tipc/log.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/dbg.h: Include file for TIPC print buffer routines | 2 | * net/tipc/log.h: Include file for TIPC print buffer routines |
3 | * | 3 | * |
4 | * Copyright (c) 1997-2006, Ericsson AB | 4 | * Copyright (c) 1997-2006, Ericsson AB |
5 | * Copyright (c) 2005-2007, Wind River Systems | 5 | * Copyright (c) 2005-2007, Wind River Systems |
@@ -34,8 +34,8 @@ | |||
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #ifndef _TIPC_DBG_H | 37 | #ifndef _TIPC_LOG_H |
38 | #define _TIPC_DBG_H | 38 | #define _TIPC_LOG_H |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * struct print_buf - TIPC print buffer structure | 41 | * struct print_buf - TIPC print buffer structure |
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index ecb532fb0351..bb6180c4fcbb 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -35,10 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "addr.h" | ||
39 | #include "dbg.h" | ||
40 | #include "msg.h" | 38 | #include "msg.h" |
41 | #include "bearer.h" | ||
42 | 39 | ||
43 | u32 tipc_msg_tot_importance(struct tipc_msg *m) | 40 | u32 tipc_msg_tot_importance(struct tipc_msg *m) |
44 | { | 41 | { |
@@ -94,7 +91,7 @@ int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect) | |||
94 | 91 | ||
95 | int tipc_msg_build(struct tipc_msg *hdr, | 92 | int tipc_msg_build(struct tipc_msg *hdr, |
96 | struct iovec const *msg_sect, u32 num_sect, | 93 | struct iovec const *msg_sect, u32 num_sect, |
97 | int max_size, int usrmem, struct sk_buff** buf) | 94 | int max_size, int usrmem, struct sk_buff **buf) |
98 | { | 95 | { |
99 | int dsz, sz, hsz, pos, res, cnt; | 96 | int dsz, sz, hsz, pos, res, cnt; |
100 | 97 | ||
@@ -140,6 +137,7 @@ int tipc_msg_build(struct tipc_msg *hdr, | |||
140 | void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | 137 | void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) |
141 | { | 138 | { |
142 | u32 usr = msg_user(msg); | 139 | u32 usr = msg_user(msg); |
140 | tipc_printf(buf, KERN_DEBUG); | ||
143 | tipc_printf(buf, str); | 141 | tipc_printf(buf, str); |
144 | 142 | ||
145 | switch (usr) { | 143 | switch (usr) { |
@@ -163,10 +161,10 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
163 | tipc_printf(buf, "LAST:"); | 161 | tipc_printf(buf, "LAST:"); |
164 | break; | 162 | break; |
165 | default: | 163 | default: |
166 | tipc_printf(buf, "UNKNOWN:%x",msg_type(msg)); | 164 | tipc_printf(buf, "UNKNOWN:%x", msg_type(msg)); |
167 | 165 | ||
168 | } | 166 | } |
169 | tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg), | 167 | tipc_printf(buf, "NO(%u/%u):", msg_long_msgno(msg), |
170 | msg_fragm_no(msg)); | 168 | msg_fragm_no(msg)); |
171 | break; | 169 | break; |
172 | case TIPC_LOW_IMPORTANCE: | 170 | case TIPC_LOW_IMPORTANCE: |
@@ -192,7 +190,7 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
192 | tipc_printf(buf, "DIR:"); | 190 | tipc_printf(buf, "DIR:"); |
193 | break; | 191 | break; |
194 | default: | 192 | default: |
195 | tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg)); | 193 | tipc_printf(buf, "UNKNOWN TYPE %u", msg_type(msg)); |
196 | } | 194 | } |
197 | if (msg_routed(msg) && !msg_non_seq(msg)) | 195 | if (msg_routed(msg) && !msg_non_seq(msg)) |
198 | tipc_printf(buf, "ROUT:"); | 196 | tipc_printf(buf, "ROUT:"); |
@@ -210,7 +208,7 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
210 | tipc_printf(buf, "WDRW:"); | 208 | tipc_printf(buf, "WDRW:"); |
211 | break; | 209 | break; |
212 | default: | 210 | default: |
213 | tipc_printf(buf, "UNKNOWN:%x",msg_type(msg)); | 211 | tipc_printf(buf, "UNKNOWN:%x", msg_type(msg)); |
214 | } | 212 | } |
215 | if (msg_routed(msg)) | 213 | if (msg_routed(msg)) |
216 | tipc_printf(buf, "ROUT:"); | 214 | tipc_printf(buf, "ROUT:"); |
@@ -229,39 +227,39 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
229 | break; | 227 | break; |
230 | case CONN_ACK: | 228 | case CONN_ACK: |
231 | tipc_printf(buf, "CONN_ACK:"); | 229 | tipc_printf(buf, "CONN_ACK:"); |
232 | tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg)); | 230 | tipc_printf(buf, "ACK(%u):", msg_msgcnt(msg)); |
233 | break; | 231 | break; |
234 | default: | 232 | default: |
235 | tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); | 233 | tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); |
236 | } | 234 | } |
237 | if (msg_routed(msg)) | 235 | if (msg_routed(msg)) |
238 | tipc_printf(buf, "ROUT:"); | 236 | tipc_printf(buf, "ROUT:"); |
239 | if (msg_reroute_cnt(msg)) | 237 | if (msg_reroute_cnt(msg)) |
240 | tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg)); | 238 | tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); |
241 | break; | 239 | break; |
242 | case LINK_PROTOCOL: | 240 | case LINK_PROTOCOL: |
243 | tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg)); | 241 | tipc_printf(buf, "PROT:TIM(%u):", msg_timestamp(msg)); |
244 | switch (msg_type(msg)) { | 242 | switch (msg_type(msg)) { |
245 | case STATE_MSG: | 243 | case STATE_MSG: |
246 | tipc_printf(buf, "STATE:"); | 244 | tipc_printf(buf, "STATE:"); |
247 | tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :""); | 245 | tipc_printf(buf, "%s:", msg_probe(msg) ? "PRB" : ""); |
248 | tipc_printf(buf, "NXS(%u):",msg_next_sent(msg)); | 246 | tipc_printf(buf, "NXS(%u):", msg_next_sent(msg)); |
249 | tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg)); | 247 | tipc_printf(buf, "GAP(%u):", msg_seq_gap(msg)); |
250 | tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg)); | 248 | tipc_printf(buf, "LSTBC(%u):", msg_last_bcast(msg)); |
251 | break; | 249 | break; |
252 | case RESET_MSG: | 250 | case RESET_MSG: |
253 | tipc_printf(buf, "RESET:"); | 251 | tipc_printf(buf, "RESET:"); |
254 | if (msg_size(msg) != msg_hdr_sz(msg)) | 252 | if (msg_size(msg) != msg_hdr_sz(msg)) |
255 | tipc_printf(buf, "BEAR:%s:",msg_data(msg)); | 253 | tipc_printf(buf, "BEAR:%s:", msg_data(msg)); |
256 | break; | 254 | break; |
257 | case ACTIVATE_MSG: | 255 | case ACTIVATE_MSG: |
258 | tipc_printf(buf, "ACTIVATE:"); | 256 | tipc_printf(buf, "ACTIVATE:"); |
259 | break; | 257 | break; |
260 | default: | 258 | default: |
261 | tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); | 259 | tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); |
262 | } | 260 | } |
263 | tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg)); | 261 | tipc_printf(buf, "PLANE(%c):", msg_net_plane(msg)); |
264 | tipc_printf(buf, "SESS(%u):",msg_session(msg)); | 262 | tipc_printf(buf, "SESS(%u):", msg_session(msg)); |
265 | break; | 263 | break; |
266 | case CHANGEOVER_PROTOCOL: | 264 | case CHANGEOVER_PROTOCOL: |
267 | tipc_printf(buf, "TUNL:"); | 265 | tipc_printf(buf, "TUNL:"); |
@@ -271,10 +269,10 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
271 | break; | 269 | break; |
272 | case ORIGINAL_MSG: | 270 | case ORIGINAL_MSG: |
273 | tipc_printf(buf, "ORIG:"); | 271 | tipc_printf(buf, "ORIG:"); |
274 | tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg)); | 272 | tipc_printf(buf, "EXP(%u)", msg_msgcnt(msg)); |
275 | break; | 273 | break; |
276 | default: | 274 | default: |
277 | tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); | 275 | tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); |
278 | } | 276 | } |
279 | break; | 277 | break; |
280 | case ROUTE_DISTRIBUTOR: | 278 | case ROUTE_DISTRIBUTOR: |
@@ -282,26 +280,26 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
282 | switch (msg_type(msg)) { | 280 | switch (msg_type(msg)) { |
283 | case EXT_ROUTING_TABLE: | 281 | case EXT_ROUTING_TABLE: |
284 | tipc_printf(buf, "EXT_TBL:"); | 282 | tipc_printf(buf, "EXT_TBL:"); |
285 | tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); | 283 | tipc_printf(buf, "TO:%x:", msg_remote_node(msg)); |
286 | break; | 284 | break; |
287 | case LOCAL_ROUTING_TABLE: | 285 | case LOCAL_ROUTING_TABLE: |
288 | tipc_printf(buf, "LOCAL_TBL:"); | 286 | tipc_printf(buf, "LOCAL_TBL:"); |
289 | tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); | 287 | tipc_printf(buf, "TO:%x:", msg_remote_node(msg)); |
290 | break; | 288 | break; |
291 | case SLAVE_ROUTING_TABLE: | 289 | case SLAVE_ROUTING_TABLE: |
292 | tipc_printf(buf, "DP_TBL:"); | 290 | tipc_printf(buf, "DP_TBL:"); |
293 | tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); | 291 | tipc_printf(buf, "TO:%x:", msg_remote_node(msg)); |
294 | break; | 292 | break; |
295 | case ROUTE_ADDITION: | 293 | case ROUTE_ADDITION: |
296 | tipc_printf(buf, "ADD:"); | 294 | tipc_printf(buf, "ADD:"); |
297 | tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); | 295 | tipc_printf(buf, "TO:%x:", msg_remote_node(msg)); |
298 | break; | 296 | break; |
299 | case ROUTE_REMOVAL: | 297 | case ROUTE_REMOVAL: |
300 | tipc_printf(buf, "REMOVE:"); | 298 | tipc_printf(buf, "REMOVE:"); |
301 | tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); | 299 | tipc_printf(buf, "TO:%x:", msg_remote_node(msg)); |
302 | break; | 300 | break; |
303 | default: | 301 | default: |
304 | tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); | 302 | tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); |
305 | } | 303 | } |
306 | break; | 304 | break; |
307 | case LINK_CONFIG: | 305 | case LINK_CONFIG: |
@@ -314,7 +312,7 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
314 | tipc_printf(buf, "DSC_RESP:"); | 312 | tipc_printf(buf, "DSC_RESP:"); |
315 | break; | 313 | break; |
316 | default: | 314 | default: |
317 | tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg)); | 315 | tipc_printf(buf, "UNKNOWN TYPE:%x:", msg_type(msg)); |
318 | break; | 316 | break; |
319 | } | 317 | } |
320 | break; | 318 | break; |
@@ -350,7 +348,8 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
350 | tipc_printf(buf, "UNKNOWN ERROR(%x):", | 348 | tipc_printf(buf, "UNKNOWN ERROR(%x):", |
351 | msg_errcode(msg)); | 349 | msg_errcode(msg)); |
352 | } | 350 | } |
353 | default:{} | 351 | default: |
352 | break; | ||
354 | } | 353 | } |
355 | 354 | ||
356 | tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg)); | 355 | tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg)); |
@@ -359,9 +358,8 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
359 | 358 | ||
360 | if (msg_non_seq(msg)) | 359 | if (msg_non_seq(msg)) |
361 | tipc_printf(buf, "NOSEQ:"); | 360 | tipc_printf(buf, "NOSEQ:"); |
362 | else { | 361 | else |
363 | tipc_printf(buf, "ACK(%u):", msg_ack(msg)); | 362 | tipc_printf(buf, "ACK(%u):", msg_ack(msg)); |
364 | } | ||
365 | tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg)); | 363 | tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg)); |
366 | tipc_printf(buf, "PRND(%x)", msg_prevnode(msg)); | 364 | tipc_printf(buf, "PRND(%x)", msg_prevnode(msg)); |
367 | 365 | ||
@@ -389,14 +387,13 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
389 | if (msg_user(msg) == NAME_DISTRIBUTOR) { | 387 | if (msg_user(msg) == NAME_DISTRIBUTOR) { |
390 | tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg)); | 388 | tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg)); |
391 | tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg)); | 389 | tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg)); |
392 | if (msg_routed(msg)) { | 390 | if (msg_routed(msg)) |
393 | tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg)); | 391 | tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg)); |
394 | } | ||
395 | } | 392 | } |
396 | 393 | ||
397 | if (msg_user(msg) == LINK_CONFIG) { | 394 | if (msg_user(msg) == LINK_CONFIG) { |
398 | u32* raw = (u32*)msg; | 395 | u32 *raw = (u32 *)msg; |
399 | struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5]; | 396 | struct tipc_media_addr *orig = (struct tipc_media_addr *)&raw[5]; |
400 | tipc_printf(buf, ":REQL(%u):", msg_req_links(msg)); | 397 | tipc_printf(buf, ":REQL(%u):", msg_req_links(msg)); |
401 | tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg)); | 398 | tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg)); |
402 | tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg)); | 399 | tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg)); |
@@ -407,12 +404,10 @@ void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) | |||
407 | tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg)); | 404 | tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg)); |
408 | } | 405 | } |
409 | tipc_printf(buf, "\n"); | 406 | tipc_printf(buf, "\n"); |
410 | if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) { | 407 | if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) |
411 | tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); | 408 | tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); |
412 | } | 409 | if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) |
413 | if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) { | ||
414 | tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); | 410 | tipc_msg_dbg(buf, msg_get_wrapped(msg), " /"); |
415 | } | ||
416 | } | 411 | } |
417 | 412 | ||
418 | #endif | 413 | #endif |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 031aad18efce..92c4c4fd7b3f 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
@@ -37,10 +37,51 @@ | |||
37 | #ifndef _TIPC_MSG_H | 37 | #ifndef _TIPC_MSG_H |
38 | #define _TIPC_MSG_H | 38 | #define _TIPC_MSG_H |
39 | 39 | ||
40 | #include "core.h" | 40 | #include "bearer.h" |
41 | 41 | ||
42 | #define TIPC_VERSION 2 | 42 | #define TIPC_VERSION 2 |
43 | 43 | ||
44 | /* | ||
45 | * TIPC user data message header format, version 2: | ||
46 | * | ||
47 | * | ||
48 | * 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 | ||
49 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
50 | * w0:|vers | user |hdr sz |n|d|s|-| message size | | ||
51 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
52 | * w1:|mstyp| error |rer cnt|lsc|opt p| broadcast ack no | | ||
53 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
54 | * w2:| link level ack no | broadcast/link level seq no | | ||
55 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
56 | * w3:| previous node | | ||
57 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
58 | * w4:| originating port | | ||
59 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
60 | * w5:| destination port | | ||
61 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
62 | * w6:| originating node | | ||
63 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
64 | * w7:| destination node | | ||
65 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
66 | * w8:| name type / transport sequence number | | ||
67 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
68 | * w9:| name instance/multicast lower bound | | ||
69 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
70 | * wA:| multicast upper bound | | ||
71 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
72 | * / / | ||
73 | * \ options \ | ||
74 | * / / | ||
75 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
76 | * | ||
77 | */ | ||
78 | |||
79 | #define TIPC_CONN_MSG 0 | ||
80 | #define TIPC_MCAST_MSG 1 | ||
81 | #define TIPC_NAMED_MSG 2 | ||
82 | #define TIPC_DIRECT_MSG 3 | ||
83 | |||
84 | |||
44 | #define SHORT_H_SIZE 24 /* Connected, in-cluster messages */ | 85 | #define SHORT_H_SIZE 24 /* Connected, in-cluster messages */ |
45 | #define DIR_MSG_H_SIZE 32 /* Directly addressed messages */ | 86 | #define DIR_MSG_H_SIZE 32 /* Directly addressed messages */ |
46 | #define LONG_H_SIZE 40 /* Named messages */ | 87 | #define LONG_H_SIZE 40 /* Named messages */ |
@@ -52,20 +93,26 @@ | |||
52 | #define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE) | 93 | #define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE) |
53 | 94 | ||
54 | 95 | ||
55 | /* | 96 | struct tipc_msg { |
56 | TIPC user data message header format, version 2 | 97 | __be32 hdr[15]; |
98 | }; | ||
57 | 99 | ||
58 | - Fundamental definitions available to privileged TIPC users | ||
59 | are located in tipc_msg.h. | ||
60 | - Remaining definitions available to TIPC internal users appear below. | ||
61 | */ | ||
62 | 100 | ||
101 | static inline u32 msg_word(struct tipc_msg *m, u32 pos) | ||
102 | { | ||
103 | return ntohl(m->hdr[pos]); | ||
104 | } | ||
63 | 105 | ||
64 | static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val) | 106 | static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val) |
65 | { | 107 | { |
66 | m->hdr[w] = htonl(val); | 108 | m->hdr[w] = htonl(val); |
67 | } | 109 | } |
68 | 110 | ||
111 | static inline u32 msg_bits(struct tipc_msg *m, u32 w, u32 pos, u32 mask) | ||
112 | { | ||
113 | return (msg_word(m, w) >> pos) & mask; | ||
114 | } | ||
115 | |||
69 | static inline void msg_set_bits(struct tipc_msg *m, u32 w, | 116 | static inline void msg_set_bits(struct tipc_msg *m, u32 w, |
70 | u32 pos, u32 mask, u32 val) | 117 | u32 pos, u32 mask, u32 val) |
71 | { | 118 | { |
@@ -112,16 +159,36 @@ static inline void msg_set_user(struct tipc_msg *m, u32 n) | |||
112 | msg_set_bits(m, 0, 25, 0xf, n); | 159 | msg_set_bits(m, 0, 25, 0xf, n); |
113 | } | 160 | } |
114 | 161 | ||
162 | static inline u32 msg_importance(struct tipc_msg *m) | ||
163 | { | ||
164 | return msg_bits(m, 0, 25, 0xf); | ||
165 | } | ||
166 | |||
115 | static inline void msg_set_importance(struct tipc_msg *m, u32 i) | 167 | static inline void msg_set_importance(struct tipc_msg *m, u32 i) |
116 | { | 168 | { |
117 | msg_set_user(m, i); | 169 | msg_set_user(m, i); |
118 | } | 170 | } |
119 | 171 | ||
120 | static inline void msg_set_hdr_sz(struct tipc_msg *m,u32 n) | 172 | static inline u32 msg_hdr_sz(struct tipc_msg *m) |
173 | { | ||
174 | return msg_bits(m, 0, 21, 0xf) << 2; | ||
175 | } | ||
176 | |||
177 | static inline void msg_set_hdr_sz(struct tipc_msg *m, u32 n) | ||
121 | { | 178 | { |
122 | msg_set_bits(m, 0, 21, 0xf, n>>2); | 179 | msg_set_bits(m, 0, 21, 0xf, n>>2); |
123 | } | 180 | } |
124 | 181 | ||
182 | static inline u32 msg_size(struct tipc_msg *m) | ||
183 | { | ||
184 | return msg_bits(m, 0, 0, 0x1ffff); | ||
185 | } | ||
186 | |||
187 | static inline u32 msg_data_sz(struct tipc_msg *m) | ||
188 | { | ||
189 | return msg_size(m) - msg_hdr_sz(m); | ||
190 | } | ||
191 | |||
125 | static inline int msg_non_seq(struct tipc_msg *m) | 192 | static inline int msg_non_seq(struct tipc_msg *m) |
126 | { | 193 | { |
127 | return msg_bits(m, 0, 20, 1); | 194 | return msg_bits(m, 0, 20, 1); |
@@ -162,11 +229,36 @@ static inline void msg_set_size(struct tipc_msg *m, u32 sz) | |||
162 | * Word 1 | 229 | * Word 1 |
163 | */ | 230 | */ |
164 | 231 | ||
232 | static inline u32 msg_type(struct tipc_msg *m) | ||
233 | { | ||
234 | return msg_bits(m, 1, 29, 0x7); | ||
235 | } | ||
236 | |||
165 | static inline void msg_set_type(struct tipc_msg *m, u32 n) | 237 | static inline void msg_set_type(struct tipc_msg *m, u32 n) |
166 | { | 238 | { |
167 | msg_set_bits(m, 1, 29, 0x7, n); | 239 | msg_set_bits(m, 1, 29, 0x7, n); |
168 | } | 240 | } |
169 | 241 | ||
242 | static inline u32 msg_named(struct tipc_msg *m) | ||
243 | { | ||
244 | return msg_type(m) == TIPC_NAMED_MSG; | ||
245 | } | ||
246 | |||
247 | static inline u32 msg_mcast(struct tipc_msg *m) | ||
248 | { | ||
249 | return msg_type(m) == TIPC_MCAST_MSG; | ||
250 | } | ||
251 | |||
252 | static inline u32 msg_connected(struct tipc_msg *m) | ||
253 | { | ||
254 | return msg_type(m) == TIPC_CONN_MSG; | ||
255 | } | ||
256 | |||
257 | static inline u32 msg_errcode(struct tipc_msg *m) | ||
258 | { | ||
259 | return msg_bits(m, 1, 25, 0xf); | ||
260 | } | ||
261 | |||
170 | static inline void msg_set_errcode(struct tipc_msg *m, u32 err) | 262 | static inline void msg_set_errcode(struct tipc_msg *m, u32 err) |
171 | { | 263 | { |
172 | msg_set_bits(m, 1, 25, 0xf, err); | 264 | msg_set_bits(m, 1, 25, 0xf, err); |
@@ -257,31 +349,68 @@ static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode) | |||
257 | */ | 349 | */ |
258 | 350 | ||
259 | 351 | ||
352 | static inline u32 msg_prevnode(struct tipc_msg *m) | ||
353 | { | ||
354 | return msg_word(m, 3); | ||
355 | } | ||
356 | |||
260 | static inline void msg_set_prevnode(struct tipc_msg *m, u32 a) | 357 | static inline void msg_set_prevnode(struct tipc_msg *m, u32 a) |
261 | { | 358 | { |
262 | msg_set_word(m, 3, a); | 359 | msg_set_word(m, 3, a); |
263 | } | 360 | } |
264 | 361 | ||
362 | static inline u32 msg_origport(struct tipc_msg *m) | ||
363 | { | ||
364 | return msg_word(m, 4); | ||
365 | } | ||
366 | |||
265 | static inline void msg_set_origport(struct tipc_msg *m, u32 p) | 367 | static inline void msg_set_origport(struct tipc_msg *m, u32 p) |
266 | { | 368 | { |
267 | msg_set_word(m, 4, p); | 369 | msg_set_word(m, 4, p); |
268 | } | 370 | } |
269 | 371 | ||
372 | static inline u32 msg_destport(struct tipc_msg *m) | ||
373 | { | ||
374 | return msg_word(m, 5); | ||
375 | } | ||
376 | |||
270 | static inline void msg_set_destport(struct tipc_msg *m, u32 p) | 377 | static inline void msg_set_destport(struct tipc_msg *m, u32 p) |
271 | { | 378 | { |
272 | msg_set_word(m, 5, p); | 379 | msg_set_word(m, 5, p); |
273 | } | 380 | } |
274 | 381 | ||
382 | static inline u32 msg_mc_netid(struct tipc_msg *m) | ||
383 | { | ||
384 | return msg_word(m, 5); | ||
385 | } | ||
386 | |||
275 | static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p) | 387 | static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p) |
276 | { | 388 | { |
277 | msg_set_word(m, 5, p); | 389 | msg_set_word(m, 5, p); |
278 | } | 390 | } |
279 | 391 | ||
392 | static inline int msg_short(struct tipc_msg *m) | ||
393 | { | ||
394 | return msg_hdr_sz(m) == 24; | ||
395 | } | ||
396 | |||
397 | static inline u32 msg_orignode(struct tipc_msg *m) | ||
398 | { | ||
399 | if (likely(msg_short(m))) | ||
400 | return msg_prevnode(m); | ||
401 | return msg_word(m, 6); | ||
402 | } | ||
403 | |||
280 | static inline void msg_set_orignode(struct tipc_msg *m, u32 a) | 404 | static inline void msg_set_orignode(struct tipc_msg *m, u32 a) |
281 | { | 405 | { |
282 | msg_set_word(m, 6, a); | 406 | msg_set_word(m, 6, a); |
283 | } | 407 | } |
284 | 408 | ||
409 | static inline u32 msg_destnode(struct tipc_msg *m) | ||
410 | { | ||
411 | return msg_word(m, 7); | ||
412 | } | ||
413 | |||
285 | static inline void msg_set_destnode(struct tipc_msg *m, u32 a) | 414 | static inline void msg_set_destnode(struct tipc_msg *m, u32 a) |
286 | { | 415 | { |
287 | msg_set_word(m, 7, a); | 416 | msg_set_word(m, 7, a); |
@@ -296,7 +425,12 @@ static inline u32 msg_routed(struct tipc_msg *m) | |||
296 | { | 425 | { |
297 | if (likely(msg_short(m))) | 426 | if (likely(msg_short(m))) |
298 | return 0; | 427 | return 0; |
299 | return(msg_destnode(m) ^ msg_orignode(m)) >> 11; | 428 | return (msg_destnode(m) ^ msg_orignode(m)) >> 11; |
429 | } | ||
430 | |||
431 | static inline u32 msg_nametype(struct tipc_msg *m) | ||
432 | { | ||
433 | return msg_word(m, 8); | ||
300 | } | 434 | } |
301 | 435 | ||
302 | static inline void msg_set_nametype(struct tipc_msg *m, u32 n) | 436 | static inline void msg_set_nametype(struct tipc_msg *m, u32 n) |
@@ -324,6 +458,16 @@ static inline void msg_set_transp_seqno(struct tipc_msg *m, u32 n) | |||
324 | msg_set_word(m, 8, n); | 458 | msg_set_word(m, 8, n); |
325 | } | 459 | } |
326 | 460 | ||
461 | static inline u32 msg_nameinst(struct tipc_msg *m) | ||
462 | { | ||
463 | return msg_word(m, 9); | ||
464 | } | ||
465 | |||
466 | static inline u32 msg_namelower(struct tipc_msg *m) | ||
467 | { | ||
468 | return msg_nameinst(m); | ||
469 | } | ||
470 | |||
327 | static inline void msg_set_namelower(struct tipc_msg *m, u32 n) | 471 | static inline void msg_set_namelower(struct tipc_msg *m, u32 n) |
328 | { | 472 | { |
329 | msg_set_word(m, 9, n); | 473 | msg_set_word(m, 9, n); |
@@ -334,11 +478,21 @@ static inline void msg_set_nameinst(struct tipc_msg *m, u32 n) | |||
334 | msg_set_namelower(m, n); | 478 | msg_set_namelower(m, n); |
335 | } | 479 | } |
336 | 480 | ||
481 | static inline u32 msg_nameupper(struct tipc_msg *m) | ||
482 | { | ||
483 | return msg_word(m, 10); | ||
484 | } | ||
485 | |||
337 | static inline void msg_set_nameupper(struct tipc_msg *m, u32 n) | 486 | static inline void msg_set_nameupper(struct tipc_msg *m, u32 n) |
338 | { | 487 | { |
339 | msg_set_word(m, 10, n); | 488 | msg_set_word(m, 10, n); |
340 | } | 489 | } |
341 | 490 | ||
491 | static inline unchar *msg_data(struct tipc_msg *m) | ||
492 | { | ||
493 | return ((unchar *)m) + msg_hdr_sz(m); | ||
494 | } | ||
495 | |||
342 | static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) | 496 | static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) |
343 | { | 497 | { |
344 | return (struct tipc_msg *)msg_data(m); | 498 | return (struct tipc_msg *)msg_data(m); |
@@ -386,7 +540,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) | |||
386 | #define MSG_BUNDLER 6 | 540 | #define MSG_BUNDLER 6 |
387 | #define LINK_PROTOCOL 7 | 541 | #define LINK_PROTOCOL 7 |
388 | #define CONN_MANAGER 8 | 542 | #define CONN_MANAGER 8 |
389 | #define ROUTE_DISTRIBUTOR 9 | 543 | #define ROUTE_DISTRIBUTOR 9 /* obsoleted */ |
390 | #define CHANGEOVER_PROTOCOL 10 | 544 | #define CHANGEOVER_PROTOCOL 10 |
391 | #define NAME_DISTRIBUTOR 11 | 545 | #define NAME_DISTRIBUTOR 11 |
392 | #define MSG_FRAGMENTER 12 | 546 | #define MSG_FRAGMENTER 12 |
@@ -665,11 +819,6 @@ static inline void msg_set_remote_node(struct tipc_msg *m, u32 a) | |||
665 | msg_set_word(m, msg_hdr_sz(m)/4, a); | 819 | msg_set_word(m, msg_hdr_sz(m)/4, a); |
666 | } | 820 | } |
667 | 821 | ||
668 | static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos) | ||
669 | { | ||
670 | msg_data(m)[pos + 4] = 1; | ||
671 | } | ||
672 | |||
673 | /* | 822 | /* |
674 | * Segmentation message types | 823 | * Segmentation message types |
675 | */ | 824 | */ |
@@ -696,7 +845,7 @@ static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos) | |||
696 | * Routing table message types | 845 | * Routing table message types |
697 | */ | 846 | */ |
698 | #define EXT_ROUTING_TABLE 0 | 847 | #define EXT_ROUTING_TABLE 0 |
699 | #define LOCAL_ROUTING_TABLE 1 | 848 | #define LOCAL_ROUTING_TABLE 1 /* obsoleted */ |
700 | #define SLAVE_ROUTING_TABLE 2 | 849 | #define SLAVE_ROUTING_TABLE 2 |
701 | #define ROUTE_ADDITION 3 | 850 | #define ROUTE_ADDITION 3 |
702 | #define ROUTE_REMOVAL 4 | 851 | #define ROUTE_REMOVAL 4 |
@@ -714,7 +863,7 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, | |||
714 | int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect); | 863 | int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect); |
715 | int tipc_msg_build(struct tipc_msg *hdr, | 864 | int tipc_msg_build(struct tipc_msg *hdr, |
716 | struct iovec const *msg_sect, u32 num_sect, | 865 | struct iovec const *msg_sect, u32 num_sect, |
717 | int max_size, int usrmem, struct sk_buff** buf); | 866 | int max_size, int usrmem, struct sk_buff **buf); |
718 | 867 | ||
719 | static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a) | 868 | static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a) |
720 | { | 869 | { |
@@ -723,7 +872,7 @@ static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr | |||
723 | 872 | ||
724 | static inline void msg_get_media_addr(struct tipc_msg *m, struct tipc_media_addr *a) | 873 | static inline void msg_get_media_addr(struct tipc_msg *m, struct tipc_media_addr *a) |
725 | { | 874 | { |
726 | memcpy(a, &((int*)m)[5], sizeof(*a)); | 875 | memcpy(a, &((int *)m)[5], sizeof(*a)); |
727 | } | 876 | } |
728 | 877 | ||
729 | #endif | 878 | #endif |
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 7b907171f879..483c226c9581 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c | |||
@@ -35,10 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "cluster.h" | ||
39 | #include "dbg.h" | ||
40 | #include "link.h" | 38 | #include "link.h" |
41 | #include "msg.h" | ||
42 | #include "name_distr.h" | 39 | #include "name_distr.h" |
43 | 40 | ||
44 | #define ITEM_SIZE sizeof(struct distr_item) | 41 | #define ITEM_SIZE sizeof(struct distr_item) |
@@ -76,7 +73,7 @@ struct distr_item { | |||
76 | */ | 73 | */ |
77 | 74 | ||
78 | static LIST_HEAD(publ_root); | 75 | static LIST_HEAD(publ_root); |
79 | static u32 publ_cnt = 0; | 76 | static u32 publ_cnt; |
80 | 77 | ||
81 | /** | 78 | /** |
82 | * publ_to_item - add publication info to a publication message | 79 | * publ_to_item - add publication info to a publication message |
@@ -89,7 +86,6 @@ static void publ_to_item(struct distr_item *i, struct publication *p) | |||
89 | i->upper = htonl(p->upper); | 86 | i->upper = htonl(p->upper); |
90 | i->ref = htonl(p->ref); | 87 | i->ref = htonl(p->ref); |
91 | i->key = htonl(p->key); | 88 | i->key = htonl(p->key); |
92 | dbg("publ_to_item: %u, %u, %u\n", p->type, p->lower, p->upper); | ||
93 | } | 89 | } |
94 | 90 | ||
95 | /** | 91 | /** |
@@ -109,6 +105,26 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) | |||
109 | return buf; | 105 | return buf; |
110 | } | 106 | } |
111 | 107 | ||
108 | static void named_cluster_distribute(struct sk_buff *buf) | ||
109 | { | ||
110 | struct sk_buff *buf_copy; | ||
111 | struct tipc_node *n_ptr; | ||
112 | u32 n_num; | ||
113 | |||
114 | for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) { | ||
115 | n_ptr = tipc_net.nodes[n_num]; | ||
116 | if (n_ptr && tipc_node_has_active_links(n_ptr)) { | ||
117 | buf_copy = skb_copy(buf, GFP_ATOMIC); | ||
118 | if (!buf_copy) | ||
119 | break; | ||
120 | msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); | ||
121 | tipc_link_send(buf_copy, n_ptr->addr, n_ptr->addr); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | buf_discard(buf); | ||
126 | } | ||
127 | |||
112 | /** | 128 | /** |
113 | * tipc_named_publish - tell other nodes about a new publication by this node | 129 | * tipc_named_publish - tell other nodes about a new publication by this node |
114 | */ | 130 | */ |
@@ -129,8 +145,7 @@ void tipc_named_publish(struct publication *publ) | |||
129 | 145 | ||
130 | item = (struct distr_item *)msg_data(buf_msg(buf)); | 146 | item = (struct distr_item *)msg_data(buf_msg(buf)); |
131 | publ_to_item(item, publ); | 147 | publ_to_item(item, publ); |
132 | dbg("tipc_named_withdraw: broadcasting publish msg\n"); | 148 | named_cluster_distribute(buf); |
133 | tipc_cltr_broadcast(buf); | ||
134 | } | 149 | } |
135 | 150 | ||
136 | /** | 151 | /** |
@@ -153,8 +168,7 @@ void tipc_named_withdraw(struct publication *publ) | |||
153 | 168 | ||
154 | item = (struct distr_item *)msg_data(buf_msg(buf)); | 169 | item = (struct distr_item *)msg_data(buf_msg(buf)); |
155 | publ_to_item(item, publ); | 170 | publ_to_item(item, publ); |
156 | dbg("tipc_named_withdraw: broadcasting withdraw msg\n"); | 171 | named_cluster_distribute(buf); |
157 | tipc_cltr_broadcast(buf); | ||
158 | } | 172 | } |
159 | 173 | ||
160 | /** | 174 | /** |
@@ -191,9 +205,6 @@ void tipc_named_node_up(unsigned long node) | |||
191 | left -= ITEM_SIZE; | 205 | left -= ITEM_SIZE; |
192 | if (!left) { | 206 | if (!left) { |
193 | msg_set_link_selector(buf_msg(buf), node); | 207 | msg_set_link_selector(buf_msg(buf), node); |
194 | dbg("tipc_named_node_up: sending publish msg to " | ||
195 | "<%u.%u.%u>\n", tipc_zone(node), | ||
196 | tipc_cluster(node), tipc_node(node)); | ||
197 | tipc_link_send(buf, node, node); | 208 | tipc_link_send(buf, node, node); |
198 | buf = NULL; | 209 | buf = NULL; |
199 | } | 210 | } |
@@ -218,8 +229,6 @@ static void node_is_down(struct publication *publ) | |||
218 | struct publication *p; | 229 | struct publication *p; |
219 | 230 | ||
220 | write_lock_bh(&tipc_nametbl_lock); | 231 | write_lock_bh(&tipc_nametbl_lock); |
221 | dbg("node_is_down: withdrawing %u, %u, %u\n", | ||
222 | publ->type, publ->lower, publ->upper); | ||
223 | publ->key += 1222345; | 232 | publ->key += 1222345; |
224 | p = tipc_nametbl_remove_publ(publ->type, publ->lower, | 233 | p = tipc_nametbl_remove_publ(publ->type, publ->lower, |
225 | publ->node, publ->ref, publ->key); | 234 | publ->node, publ->ref, publ->key); |
@@ -231,9 +240,7 @@ static void node_is_down(struct publication *publ) | |||
231 | publ->type, publ->lower, publ->node, publ->ref, publ->key); | 240 | publ->type, publ->lower, publ->node, publ->ref, publ->key); |
232 | } | 241 | } |
233 | 242 | ||
234 | if (p) { | 243 | kfree(p); |
235 | kfree(p); | ||
236 | } | ||
237 | } | 244 | } |
238 | 245 | ||
239 | /** | 246 | /** |
@@ -250,9 +257,6 @@ void tipc_named_recv(struct sk_buff *buf) | |||
250 | write_lock_bh(&tipc_nametbl_lock); | 257 | write_lock_bh(&tipc_nametbl_lock); |
251 | while (count--) { | 258 | while (count--) { |
252 | if (msg_type(msg) == PUBLICATION) { | 259 | if (msg_type(msg) == PUBLICATION) { |
253 | dbg("tipc_named_recv: got publication for %u, %u, %u\n", | ||
254 | ntohl(item->type), ntohl(item->lower), | ||
255 | ntohl(item->upper)); | ||
256 | publ = tipc_nametbl_insert_publ(ntohl(item->type), | 260 | publ = tipc_nametbl_insert_publ(ntohl(item->type), |
257 | ntohl(item->lower), | 261 | ntohl(item->lower), |
258 | ntohl(item->upper), | 262 | ntohl(item->upper), |
@@ -267,9 +271,6 @@ void tipc_named_recv(struct sk_buff *buf) | |||
267 | (net_ev_handler)node_is_down); | 271 | (net_ev_handler)node_is_down); |
268 | } | 272 | } |
269 | } else if (msg_type(msg) == WITHDRAWAL) { | 273 | } else if (msg_type(msg) == WITHDRAWAL) { |
270 | dbg("tipc_named_recv: got withdrawl for %u, %u, %u\n", | ||
271 | ntohl(item->type), ntohl(item->lower), | ||
272 | ntohl(item->upper)); | ||
273 | publ = tipc_nametbl_remove_publ(ntohl(item->type), | 274 | publ = tipc_nametbl_remove_publ(ntohl(item->type), |
274 | ntohl(item->lower), | 275 | ntohl(item->lower), |
275 | msg_orignode(msg), | 276 | msg_orignode(msg), |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 3a8de4334da1..205ed4a4e186 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
@@ -36,15 +36,10 @@ | |||
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "config.h" | 38 | #include "config.h" |
39 | #include "dbg.h" | ||
40 | #include "name_table.h" | 39 | #include "name_table.h" |
41 | #include "name_distr.h" | 40 | #include "name_distr.h" |
42 | #include "addr.h" | ||
43 | #include "node_subscr.h" | ||
44 | #include "subscr.h" | 41 | #include "subscr.h" |
45 | #include "port.h" | 42 | #include "port.h" |
46 | #include "cluster.h" | ||
47 | #include "bcast.h" | ||
48 | 43 | ||
49 | static int tipc_nametbl_size = 1024; /* must be a power of 2 */ | 44 | static int tipc_nametbl_size = 1024; /* must be a power of 2 */ |
50 | 45 | ||
@@ -109,7 +104,7 @@ struct name_table { | |||
109 | u32 local_publ_count; | 104 | u32 local_publ_count; |
110 | }; | 105 | }; |
111 | 106 | ||
112 | static struct name_table table = { NULL } ; | 107 | static struct name_table table; |
113 | static atomic_t rsv_publ_ok = ATOMIC_INIT(0); | 108 | static atomic_t rsv_publ_ok = ATOMIC_INIT(0); |
114 | DEFINE_RWLOCK(tipc_nametbl_lock); | 109 | DEFINE_RWLOCK(tipc_nametbl_lock); |
115 | 110 | ||
@@ -177,8 +172,6 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea | |||
177 | spin_lock_init(&nseq->lock); | 172 | spin_lock_init(&nseq->lock); |
178 | nseq->type = type; | 173 | nseq->type = type; |
179 | nseq->sseqs = sseq; | 174 | nseq->sseqs = sseq; |
180 | dbg("tipc_nameseq_create(): nseq = %p, type %u, ssseqs %p, ff: %u\n", | ||
181 | nseq, type, nseq->sseqs, nseq->first_free); | ||
182 | nseq->alloc = 1; | 175 | nseq->alloc = 1; |
183 | INIT_HLIST_NODE(&nseq->ns_list); | 176 | INIT_HLIST_NODE(&nseq->ns_list); |
184 | INIT_LIST_HEAD(&nseq->subscriptions); | 177 | INIT_LIST_HEAD(&nseq->subscriptions); |
@@ -256,8 +249,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
256 | int created_subseq = 0; | 249 | int created_subseq = 0; |
257 | 250 | ||
258 | sseq = nameseq_find_subseq(nseq, lower); | 251 | sseq = nameseq_find_subseq(nseq, lower); |
259 | dbg("nameseq_ins: for seq %p, {%u,%u}, found sseq %p\n", | ||
260 | nseq, type, lower, sseq); | ||
261 | if (sseq) { | 252 | if (sseq) { |
262 | 253 | ||
263 | /* Lower end overlaps existing entry => need an exact match */ | 254 | /* Lower end overlaps existing entry => need an exact match */ |
@@ -294,38 +285,30 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
294 | type, lower, upper); | 285 | type, lower, upper); |
295 | return NULL; | 286 | return NULL; |
296 | } | 287 | } |
297 | dbg("Allocated %u more sseqs\n", nseq->alloc); | ||
298 | memcpy(sseqs, nseq->sseqs, | 288 | memcpy(sseqs, nseq->sseqs, |
299 | nseq->alloc * sizeof(struct sub_seq)); | 289 | nseq->alloc * sizeof(struct sub_seq)); |
300 | kfree(nseq->sseqs); | 290 | kfree(nseq->sseqs); |
301 | nseq->sseqs = sseqs; | 291 | nseq->sseqs = sseqs; |
302 | nseq->alloc *= 2; | 292 | nseq->alloc *= 2; |
303 | } | 293 | } |
304 | dbg("Have %u sseqs for type %u\n", nseq->alloc, type); | ||
305 | 294 | ||
306 | /* Insert new sub-sequence */ | 295 | /* Insert new sub-sequence */ |
307 | 296 | ||
308 | dbg("ins in pos %u, ff = %u\n", inspos, nseq->first_free); | ||
309 | sseq = &nseq->sseqs[inspos]; | 297 | sseq = &nseq->sseqs[inspos]; |
310 | freesseq = &nseq->sseqs[nseq->first_free]; | 298 | freesseq = &nseq->sseqs[nseq->first_free]; |
311 | memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof (*sseq)); | 299 | memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof(*sseq)); |
312 | memset(sseq, 0, sizeof (*sseq)); | 300 | memset(sseq, 0, sizeof(*sseq)); |
313 | nseq->first_free++; | 301 | nseq->first_free++; |
314 | sseq->lower = lower; | 302 | sseq->lower = lower; |
315 | sseq->upper = upper; | 303 | sseq->upper = upper; |
316 | created_subseq = 1; | 304 | created_subseq = 1; |
317 | } | 305 | } |
318 | dbg("inserting {%u,%u,%u} from <0x%x:%u> into sseq %p(%u,%u) of seq %p\n", | ||
319 | type, lower, upper, node, port, sseq, | ||
320 | sseq->lower, sseq->upper, nseq); | ||
321 | 306 | ||
322 | /* Insert a publication: */ | 307 | /* Insert a publication: */ |
323 | 308 | ||
324 | publ = publ_create(type, lower, upper, scope, node, port, key); | 309 | publ = publ_create(type, lower, upper, scope, node, port, key); |
325 | if (!publ) | 310 | if (!publ) |
326 | return NULL; | 311 | return NULL; |
327 | dbg("inserting publ %p, node=0x%x publ->node=0x%x, subscr->node=%p\n", | ||
328 | publ, node, publ->node, publ->subscr.node); | ||
329 | 312 | ||
330 | sseq->zone_list_size++; | 313 | sseq->zone_list_size++; |
331 | if (!sseq->zone_list) | 314 | if (!sseq->zone_list) |
@@ -360,7 +343,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
360 | * Any subscriptions waiting for notification? | 343 | * Any subscriptions waiting for notification? |
361 | */ | 344 | */ |
362 | list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { | 345 | list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { |
363 | dbg("calling report_overlap()\n"); | ||
364 | tipc_subscr_report_overlap(s, | 346 | tipc_subscr_report_overlap(s, |
365 | publ->lower, | 347 | publ->lower, |
366 | publ->upper, | 348 | publ->upper, |
@@ -398,9 +380,6 @@ static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 i | |||
398 | if (!sseq) | 380 | if (!sseq) |
399 | return NULL; | 381 | return NULL; |
400 | 382 | ||
401 | dbg("tipc_nameseq_remove_publ: seq: %p, sseq %p, {%u,%u}, key %u\n", | ||
402 | nseq, sseq, nseq->type, inst, key); | ||
403 | |||
404 | /* Remove publication from zone scope list */ | 383 | /* Remove publication from zone scope list */ |
405 | 384 | ||
406 | prev = sseq->zone_list; | 385 | prev = sseq->zone_list; |
@@ -492,7 +471,7 @@ end_node: | |||
492 | 471 | ||
493 | if (!sseq->zone_list) { | 472 | if (!sseq->zone_list) { |
494 | free = &nseq->sseqs[nseq->first_free--]; | 473 | free = &nseq->sseqs[nseq->first_free--]; |
495 | memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq)); | 474 | memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq)); |
496 | removed_subseq = 1; | 475 | removed_subseq = 1; |
497 | } | 476 | } |
498 | 477 | ||
@@ -528,7 +507,7 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq, struct subscription *s | |||
528 | 507 | ||
529 | while (sseq != &nseq->sseqs[nseq->first_free]) { | 508 | while (sseq != &nseq->sseqs[nseq->first_free]) { |
530 | struct publication *zl = sseq->zone_list; | 509 | struct publication *zl = sseq->zone_list; |
531 | if (zl && tipc_subscr_overlap(s,sseq->lower,sseq->upper)) { | 510 | if (zl && tipc_subscr_overlap(s, sseq->lower, sseq->upper)) { |
532 | struct publication *crs = zl; | 511 | struct publication *crs = zl; |
533 | int must_report = 1; | 512 | int must_report = 1; |
534 | 513 | ||
@@ -554,15 +533,10 @@ static struct name_seq *nametbl_find_seq(u32 type) | |||
554 | struct hlist_node *seq_node; | 533 | struct hlist_node *seq_node; |
555 | struct name_seq *ns; | 534 | struct name_seq *ns; |
556 | 535 | ||
557 | dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n", | ||
558 | type, htonl(type), type, table.types, hash(type)); | ||
559 | |||
560 | seq_head = &table.types[hash(type)]; | 536 | seq_head = &table.types[hash(type)]; |
561 | hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { | 537 | hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { |
562 | if (ns->type == type) { | 538 | if (ns->type == type) |
563 | dbg("found %p\n", ns); | ||
564 | return ns; | 539 | return ns; |
565 | } | ||
566 | } | 540 | } |
567 | 541 | ||
568 | return NULL; | 542 | return NULL; |
@@ -573,18 +547,14 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, | |||
573 | { | 547 | { |
574 | struct name_seq *seq = nametbl_find_seq(type); | 548 | struct name_seq *seq = nametbl_find_seq(type); |
575 | 549 | ||
576 | dbg("tipc_nametbl_insert_publ: {%u,%u,%u} found %p\n", type, lower, upper, seq); | ||
577 | if (lower > upper) { | 550 | if (lower > upper) { |
578 | warn("Failed to publish illegal {%u,%u,%u}\n", | 551 | warn("Failed to publish illegal {%u,%u,%u}\n", |
579 | type, lower, upper); | 552 | type, lower, upper); |
580 | return NULL; | 553 | return NULL; |
581 | } | 554 | } |
582 | 555 | ||
583 | dbg("Publishing {%u,%u,%u} from 0x%x\n", type, lower, upper, node); | 556 | if (!seq) |
584 | if (!seq) { | ||
585 | seq = tipc_nameseq_create(type, &table.types[hash(type)]); | 557 | seq = tipc_nameseq_create(type, &table.types[hash(type)]); |
586 | dbg("tipc_nametbl_insert_publ: created %p\n", seq); | ||
587 | } | ||
588 | if (!seq) | 558 | if (!seq) |
589 | return NULL; | 559 | return NULL; |
590 | 560 | ||
@@ -601,7 +571,6 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, | |||
601 | if (!seq) | 571 | if (!seq) |
602 | return NULL; | 572 | return NULL; |
603 | 573 | ||
604 | dbg("Withdrawing {%u,%u} from 0x%x\n", type, lower, node); | ||
605 | publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); | 574 | publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); |
606 | 575 | ||
607 | if (!seq->first_free && list_empty(&seq->subscriptions)) { | 576 | if (!seq->first_free && list_empty(&seq->subscriptions)) { |
@@ -782,9 +751,8 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, | |||
782 | table.local_publ_count++; | 751 | table.local_publ_count++; |
783 | publ = tipc_nametbl_insert_publ(type, lower, upper, scope, | 752 | publ = tipc_nametbl_insert_publ(type, lower, upper, scope, |
784 | tipc_own_addr, port_ref, key); | 753 | tipc_own_addr, port_ref, key); |
785 | if (publ && (scope != TIPC_NODE_SCOPE)) { | 754 | if (publ && (scope != TIPC_NODE_SCOPE)) |
786 | tipc_named_publish(publ); | 755 | tipc_named_publish(publ); |
787 | } | ||
788 | write_unlock_bh(&tipc_nametbl_lock); | 756 | write_unlock_bh(&tipc_nametbl_lock); |
789 | return publ; | 757 | return publ; |
790 | } | 758 | } |
@@ -797,7 +765,6 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) | |||
797 | { | 765 | { |
798 | struct publication *publ; | 766 | struct publication *publ; |
799 | 767 | ||
800 | dbg("tipc_nametbl_withdraw: {%u,%u}, key=%u\n", type, lower, key); | ||
801 | write_lock_bh(&tipc_nametbl_lock); | 768 | write_lock_bh(&tipc_nametbl_lock); |
802 | publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); | 769 | publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); |
803 | if (likely(publ)) { | 770 | if (likely(publ)) { |
@@ -827,13 +794,10 @@ void tipc_nametbl_subscribe(struct subscription *s) | |||
827 | 794 | ||
828 | write_lock_bh(&tipc_nametbl_lock); | 795 | write_lock_bh(&tipc_nametbl_lock); |
829 | seq = nametbl_find_seq(type); | 796 | seq = nametbl_find_seq(type); |
830 | if (!seq) { | 797 | if (!seq) |
831 | seq = tipc_nameseq_create(type, &table.types[hash(type)]); | 798 | seq = tipc_nameseq_create(type, &table.types[hash(type)]); |
832 | } | 799 | if (seq) { |
833 | if (seq){ | ||
834 | spin_lock_bh(&seq->lock); | 800 | spin_lock_bh(&seq->lock); |
835 | dbg("tipc_nametbl_subscribe:found %p for {%u,%u,%u}\n", | ||
836 | seq, type, s->seq.lower, s->seq.upper); | ||
837 | tipc_nameseq_subscribe(seq, s); | 801 | tipc_nameseq_subscribe(seq, s); |
838 | spin_unlock_bh(&seq->lock); | 802 | spin_unlock_bh(&seq->lock); |
839 | } else { | 803 | } else { |
@@ -853,7 +817,7 @@ void tipc_nametbl_unsubscribe(struct subscription *s) | |||
853 | 817 | ||
854 | write_lock_bh(&tipc_nametbl_lock); | 818 | write_lock_bh(&tipc_nametbl_lock); |
855 | seq = nametbl_find_seq(s->seq.type); | 819 | seq = nametbl_find_seq(s->seq.type); |
856 | if (seq != NULL){ | 820 | if (seq != NULL) { |
857 | spin_lock_bh(&seq->lock); | 821 | spin_lock_bh(&seq->lock); |
858 | list_del_init(&s->nameseq_list); | 822 | list_del_init(&s->nameseq_list); |
859 | spin_unlock_bh(&seq->lock); | 823 | spin_unlock_bh(&seq->lock); |
@@ -886,7 +850,7 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth, | |||
886 | } | 850 | } |
887 | 851 | ||
888 | do { | 852 | do { |
889 | sprintf (portIdStr, "<%u.%u.%u:%u>", | 853 | sprintf(portIdStr, "<%u.%u.%u:%u>", |
890 | tipc_zone(publ->node), tipc_cluster(publ->node), | 854 | tipc_zone(publ->node), tipc_cluster(publ->node), |
891 | tipc_node(publ->node), publ->ref); | 855 | tipc_node(publ->node), publ->ref); |
892 | tipc_printf(buf, "%-26s ", portIdStr); | 856 | tipc_printf(buf, "%-26s ", portIdStr); |
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 139882d4ed00..d228bd682655 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h | |||
@@ -46,7 +46,7 @@ struct port_list; | |||
46 | * TIPC name types reserved for internal TIPC use (both current and planned) | 46 | * TIPC name types reserved for internal TIPC use (both current and planned) |
47 | */ | 47 | */ |
48 | 48 | ||
49 | #define TIPC_ZM_SRV 3 /* zone master service name type */ | 49 | #define TIPC_ZM_SRV 3 /* zone master service name type */ |
50 | 50 | ||
51 | 51 | ||
52 | /** | 52 | /** |
diff --git a/net/tipc/net.c b/net/tipc/net.c index 1a621cfd6604..9bacfd00b91e 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c | |||
@@ -35,18 +35,10 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "bearer.h" | ||
39 | #include "net.h" | 38 | #include "net.h" |
40 | #include "zone.h" | ||
41 | #include "addr.h" | ||
42 | #include "name_table.h" | ||
43 | #include "name_distr.h" | 39 | #include "name_distr.h" |
44 | #include "subscr.h" | 40 | #include "subscr.h" |
45 | #include "link.h" | ||
46 | #include "msg.h" | ||
47 | #include "port.h" | 41 | #include "port.h" |
48 | #include "bcast.h" | ||
49 | #include "discover.h" | ||
50 | #include "config.h" | 42 | #include "config.h" |
51 | 43 | ||
52 | /* | 44 | /* |
@@ -116,46 +108,25 @@ | |||
116 | */ | 108 | */ |
117 | 109 | ||
118 | DEFINE_RWLOCK(tipc_net_lock); | 110 | DEFINE_RWLOCK(tipc_net_lock); |
119 | static struct _zone *tipc_zones[256] = { NULL, }; | 111 | struct network tipc_net; |
120 | struct network tipc_net = { tipc_zones }; | ||
121 | 112 | ||
122 | struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref) | 113 | static int net_start(void) |
123 | { | 114 | { |
124 | return tipc_zone_select_remote_node(tipc_net.zones[tipc_zone(addr)], addr, ref); | 115 | tipc_net.nodes = kcalloc(tipc_max_nodes + 1, |
125 | } | 116 | sizeof(*tipc_net.nodes), GFP_ATOMIC); |
126 | 117 | tipc_net.highest_node = 0; | |
127 | u32 tipc_net_select_router(u32 addr, u32 ref) | ||
128 | { | ||
129 | return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref); | ||
130 | } | ||
131 | |||
132 | void tipc_net_remove_as_router(u32 router) | ||
133 | { | ||
134 | u32 z_num; | ||
135 | |||
136 | for (z_num = 1; z_num <= tipc_max_zones; z_num++) { | ||
137 | if (!tipc_net.zones[z_num]) | ||
138 | continue; | ||
139 | tipc_zone_remove_as_router(tipc_net.zones[z_num], router); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | void tipc_net_send_external_routes(u32 dest) | ||
144 | { | ||
145 | u32 z_num; | ||
146 | 118 | ||
147 | for (z_num = 1; z_num <= tipc_max_zones; z_num++) { | 119 | return tipc_net.nodes ? 0 : -ENOMEM; |
148 | if (tipc_net.zones[z_num]) | ||
149 | tipc_zone_send_external_routes(tipc_net.zones[z_num], dest); | ||
150 | } | ||
151 | } | 120 | } |
152 | 121 | ||
153 | static void net_stop(void) | 122 | static void net_stop(void) |
154 | { | 123 | { |
155 | u32 z_num; | 124 | u32 n_num; |
156 | 125 | ||
157 | for (z_num = 1; z_num <= tipc_max_zones; z_num++) | 126 | for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) |
158 | tipc_zone_delete(tipc_net.zones[z_num]); | 127 | tipc_node_delete(tipc_net.nodes[n_num]); |
128 | kfree(tipc_net.nodes); | ||
129 | tipc_net.nodes = NULL; | ||
159 | } | 130 | } |
160 | 131 | ||
161 | static void net_route_named_msg(struct sk_buff *buf) | 132 | static void net_route_named_msg(struct sk_buff *buf) |
@@ -165,22 +136,18 @@ static void net_route_named_msg(struct sk_buff *buf) | |||
165 | u32 dport; | 136 | u32 dport; |
166 | 137 | ||
167 | if (!msg_named(msg)) { | 138 | if (!msg_named(msg)) { |
168 | msg_dbg(msg, "tipc_net->drop_nam:"); | ||
169 | buf_discard(buf); | 139 | buf_discard(buf); |
170 | return; | 140 | return; |
171 | } | 141 | } |
172 | 142 | ||
173 | dnode = addr_domain(msg_lookup_scope(msg)); | 143 | dnode = addr_domain(msg_lookup_scope(msg)); |
174 | dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode); | 144 | dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode); |
175 | dbg("tipc_net->lookup<%u,%u>-><%u,%x>\n", | ||
176 | msg_nametype(msg), msg_nameinst(msg), dport, dnode); | ||
177 | if (dport) { | 145 | if (dport) { |
178 | msg_set_destnode(msg, dnode); | 146 | msg_set_destnode(msg, dnode); |
179 | msg_set_destport(msg, dport); | 147 | msg_set_destport(msg, dport); |
180 | tipc_net_route_msg(buf); | 148 | tipc_net_route_msg(buf); |
181 | return; | 149 | return; |
182 | } | 150 | } |
183 | msg_dbg(msg, "tipc_net->rej:NO NAME: "); | ||
184 | tipc_reject_msg(buf, TIPC_ERR_NO_NAME); | 151 | tipc_reject_msg(buf, TIPC_ERR_NO_NAME); |
185 | } | 152 | } |
186 | 153 | ||
@@ -196,18 +163,14 @@ void tipc_net_route_msg(struct sk_buff *buf) | |||
196 | msg_incr_reroute_cnt(msg); | 163 | msg_incr_reroute_cnt(msg); |
197 | if (msg_reroute_cnt(msg) > 6) { | 164 | if (msg_reroute_cnt(msg) > 6) { |
198 | if (msg_errcode(msg)) { | 165 | if (msg_errcode(msg)) { |
199 | msg_dbg(msg, "NET>DISC>:"); | ||
200 | buf_discard(buf); | 166 | buf_discard(buf); |
201 | } else { | 167 | } else { |
202 | msg_dbg(msg, "NET>REJ>:"); | ||
203 | tipc_reject_msg(buf, msg_destport(msg) ? | 168 | tipc_reject_msg(buf, msg_destport(msg) ? |
204 | TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME); | 169 | TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME); |
205 | } | 170 | } |
206 | return; | 171 | return; |
207 | } | 172 | } |
208 | 173 | ||
209 | msg_dbg(msg, "tipc_net->rout: "); | ||
210 | |||
211 | /* Handle message for this node */ | 174 | /* Handle message for this node */ |
212 | dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); | 175 | dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); |
213 | if (tipc_in_scope(dnode, tipc_own_addr)) { | 176 | if (tipc_in_scope(dnode, tipc_own_addr)) { |
@@ -221,9 +184,6 @@ void tipc_net_route_msg(struct sk_buff *buf) | |||
221 | return; | 184 | return; |
222 | } | 185 | } |
223 | switch (msg_user(msg)) { | 186 | switch (msg_user(msg)) { |
224 | case ROUTE_DISTRIBUTOR: | ||
225 | tipc_cltr_recv_routing_table(buf); | ||
226 | break; | ||
227 | case NAME_DISTRIBUTOR: | 187 | case NAME_DISTRIBUTOR: |
228 | tipc_named_recv(buf); | 188 | tipc_named_recv(buf); |
229 | break; | 189 | break; |
@@ -231,14 +191,12 @@ void tipc_net_route_msg(struct sk_buff *buf) | |||
231 | tipc_port_recv_proto_msg(buf); | 191 | tipc_port_recv_proto_msg(buf); |
232 | break; | 192 | break; |
233 | default: | 193 | default: |
234 | msg_dbg(msg,"DROP/NET/<REC<"); | ||
235 | buf_discard(buf); | 194 | buf_discard(buf); |
236 | } | 195 | } |
237 | return; | 196 | return; |
238 | } | 197 | } |
239 | 198 | ||
240 | /* Handle message for another node */ | 199 | /* Handle message for another node */ |
241 | msg_dbg(msg, "NET>SEND>: "); | ||
242 | skb_trim(buf, msg_size(msg)); | 200 | skb_trim(buf, msg_size(msg)); |
243 | tipc_link_send(buf, dnode, msg_link_selector(msg)); | 201 | tipc_link_send(buf, dnode, msg_link_selector(msg)); |
244 | } | 202 | } |
@@ -259,10 +217,12 @@ int tipc_net_start(u32 addr) | |||
259 | tipc_named_reinit(); | 217 | tipc_named_reinit(); |
260 | tipc_port_reinit(); | 218 | tipc_port_reinit(); |
261 | 219 | ||
262 | if ((res = tipc_cltr_init()) || | 220 | res = net_start(); |
263 | (res = tipc_bclink_init())) { | 221 | if (res) |
222 | return res; | ||
223 | res = tipc_bclink_init(); | ||
224 | if (res) | ||
264 | return res; | 225 | return res; |
265 | } | ||
266 | 226 | ||
267 | tipc_k_signal((Handler)tipc_subscr_start, 0); | 227 | tipc_k_signal((Handler)tipc_subscr_start, 0); |
268 | tipc_k_signal((Handler)tipc_cfg_init, 0); | 228 | tipc_k_signal((Handler)tipc_cfg_init, 0); |
diff --git a/net/tipc/net.h b/net/tipc/net.h index de2b9ad8f646..4ae59ad04893 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h | |||
@@ -37,26 +37,26 @@ | |||
37 | #ifndef _TIPC_NET_H | 37 | #ifndef _TIPC_NET_H |
38 | #define _TIPC_NET_H | 38 | #define _TIPC_NET_H |
39 | 39 | ||
40 | struct _zone; | 40 | struct tipc_node; |
41 | 41 | ||
42 | /** | 42 | /** |
43 | * struct network - TIPC network structure | 43 | * struct network - TIPC network structure |
44 | * @zones: array of pointers to all zones within network | 44 | * @nodes: array of pointers to all nodes within cluster |
45 | * @highest_node: id of highest numbered node within cluster | ||
46 | * @links: number of (unicast) links to cluster | ||
45 | */ | 47 | */ |
46 | 48 | ||
47 | struct network { | 49 | struct network { |
48 | struct _zone **zones; | 50 | struct tipc_node **nodes; |
51 | u32 highest_node; | ||
52 | u32 links; | ||
49 | }; | 53 | }; |
50 | 54 | ||
51 | 55 | ||
52 | extern struct network tipc_net; | 56 | extern struct network tipc_net; |
53 | extern rwlock_t tipc_net_lock; | 57 | extern rwlock_t tipc_net_lock; |
54 | 58 | ||
55 | void tipc_net_remove_as_router(u32 router); | ||
56 | void tipc_net_send_external_routes(u32 dest); | ||
57 | void tipc_net_route_msg(struct sk_buff *buf); | 59 | void tipc_net_route_msg(struct sk_buff *buf); |
58 | struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref); | ||
59 | u32 tipc_net_select_router(u32 addr, u32 ref); | ||
60 | 60 | ||
61 | int tipc_net_start(u32 addr); | 61 | int tipc_net_start(u32 addr); |
62 | void tipc_net_stop(void); | 62 | void tipc_net_stop(void); |
diff --git a/net/tipc/node.c b/net/tipc/node.c index b4d87eb2dc5d..3af53e327f49 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -37,25 +37,14 @@ | |||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "config.h" | 38 | #include "config.h" |
39 | #include "node.h" | 39 | #include "node.h" |
40 | #include "cluster.h" | ||
41 | #include "net.h" | ||
42 | #include "addr.h" | ||
43 | #include "node_subscr.h" | ||
44 | #include "link.h" | ||
45 | #include "port.h" | ||
46 | #include "bearer.h" | ||
47 | #include "name_distr.h" | 40 | #include "name_distr.h" |
48 | 41 | ||
49 | void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str); | ||
50 | static void node_lost_contact(struct tipc_node *n_ptr); | 42 | static void node_lost_contact(struct tipc_node *n_ptr); |
51 | static void node_established_contact(struct tipc_node *n_ptr); | 43 | static void node_established_contact(struct tipc_node *n_ptr); |
52 | 44 | ||
53 | /* sorted list of nodes within cluster */ | ||
54 | static struct tipc_node *tipc_nodes = NULL; | ||
55 | |||
56 | static DEFINE_SPINLOCK(node_create_lock); | 45 | static DEFINE_SPINLOCK(node_create_lock); |
57 | 46 | ||
58 | u32 tipc_own_tag = 0; | 47 | u32 tipc_own_tag; |
59 | 48 | ||
60 | /** | 49 | /** |
61 | * tipc_node_create - create neighboring node | 50 | * tipc_node_create - create neighboring node |
@@ -69,65 +58,51 @@ u32 tipc_own_tag = 0; | |||
69 | 58 | ||
70 | struct tipc_node *tipc_node_create(u32 addr) | 59 | struct tipc_node *tipc_node_create(u32 addr) |
71 | { | 60 | { |
72 | struct cluster *c_ptr; | ||
73 | struct tipc_node *n_ptr; | 61 | struct tipc_node *n_ptr; |
74 | struct tipc_node **curr_node; | 62 | u32 n_num; |
75 | 63 | ||
76 | spin_lock_bh(&node_create_lock); | 64 | spin_lock_bh(&node_create_lock); |
77 | 65 | ||
78 | for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) { | 66 | n_ptr = tipc_node_find(addr); |
79 | if (addr < n_ptr->addr) | 67 | if (n_ptr) { |
80 | break; | 68 | spin_unlock_bh(&node_create_lock); |
81 | if (addr == n_ptr->addr) { | 69 | return n_ptr; |
82 | spin_unlock_bh(&node_create_lock); | ||
83 | return n_ptr; | ||
84 | } | ||
85 | } | 70 | } |
86 | 71 | ||
87 | n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC); | 72 | n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC); |
88 | if (!n_ptr) { | 73 | if (!n_ptr) { |
89 | spin_unlock_bh(&node_create_lock); | 74 | spin_unlock_bh(&node_create_lock); |
90 | warn("Node creation failed, no memory\n"); | 75 | warn("Node creation failed, no memory\n"); |
91 | return NULL; | 76 | return NULL; |
92 | } | 77 | } |
93 | 78 | ||
94 | c_ptr = tipc_cltr_find(addr); | ||
95 | if (!c_ptr) { | ||
96 | c_ptr = tipc_cltr_create(addr); | ||
97 | } | ||
98 | if (!c_ptr) { | ||
99 | spin_unlock_bh(&node_create_lock); | ||
100 | kfree(n_ptr); | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | n_ptr->addr = addr; | 79 | n_ptr->addr = addr; |
105 | spin_lock_init(&n_ptr->lock); | 80 | spin_lock_init(&n_ptr->lock); |
106 | INIT_LIST_HEAD(&n_ptr->nsub); | 81 | INIT_LIST_HEAD(&n_ptr->nsub); |
107 | n_ptr->owner = c_ptr; | 82 | |
108 | tipc_cltr_attach_node(c_ptr, n_ptr); | 83 | n_num = tipc_node(addr); |
109 | n_ptr->last_router = -1; | 84 | tipc_net.nodes[n_num] = n_ptr; |
110 | 85 | if (n_num > tipc_net.highest_node) | |
111 | /* Insert node into ordered list */ | 86 | tipc_net.highest_node = n_num; |
112 | for (curr_node = &tipc_nodes; *curr_node; | 87 | |
113 | curr_node = &(*curr_node)->next) { | ||
114 | if (addr < (*curr_node)->addr) { | ||
115 | n_ptr->next = *curr_node; | ||
116 | break; | ||
117 | } | ||
118 | } | ||
119 | (*curr_node) = n_ptr; | ||
120 | spin_unlock_bh(&node_create_lock); | 88 | spin_unlock_bh(&node_create_lock); |
121 | return n_ptr; | 89 | return n_ptr; |
122 | } | 90 | } |
123 | 91 | ||
124 | void tipc_node_delete(struct tipc_node *n_ptr) | 92 | void tipc_node_delete(struct tipc_node *n_ptr) |
125 | { | 93 | { |
94 | u32 n_num; | ||
95 | |||
126 | if (!n_ptr) | 96 | if (!n_ptr) |
127 | return; | 97 | return; |
128 | 98 | ||
129 | dbg("node %x deleted\n", n_ptr->addr); | 99 | n_num = tipc_node(n_ptr->addr); |
100 | tipc_net.nodes[n_num] = NULL; | ||
130 | kfree(n_ptr); | 101 | kfree(n_ptr); |
102 | |||
103 | while (!tipc_net.nodes[tipc_net.highest_node]) | ||
104 | if (--tipc_net.highest_node == 0) | ||
105 | break; | ||
131 | } | 106 | } |
132 | 107 | ||
133 | 108 | ||
@@ -147,7 +122,6 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr) | |||
147 | l_ptr->name, l_ptr->b_ptr->net_plane); | 122 | l_ptr->name, l_ptr->b_ptr->net_plane); |
148 | 123 | ||
149 | if (!active[0]) { | 124 | if (!active[0]) { |
150 | dbg(" link %x into %x/%x\n", l_ptr, &active[0], &active[1]); | ||
151 | active[0] = active[1] = l_ptr; | 125 | active[0] = active[1] = l_ptr; |
152 | node_established_contact(n_ptr); | 126 | node_established_contact(n_ptr); |
153 | return; | 127 | return; |
@@ -236,14 +210,9 @@ int tipc_node_has_redundant_links(struct tipc_node *n_ptr) | |||
236 | return n_ptr->working_links > 1; | 210 | return n_ptr->working_links > 1; |
237 | } | 211 | } |
238 | 212 | ||
239 | static int tipc_node_has_active_routes(struct tipc_node *n_ptr) | ||
240 | { | ||
241 | return n_ptr && (n_ptr->last_router >= 0); | ||
242 | } | ||
243 | |||
244 | int tipc_node_is_up(struct tipc_node *n_ptr) | 213 | int tipc_node_is_up(struct tipc_node *n_ptr) |
245 | { | 214 | { |
246 | return tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr); | 215 | return tipc_node_has_active_links(n_ptr); |
247 | } | 216 | } |
248 | 217 | ||
249 | struct tipc_node *tipc_node_attach_link(struct link *l_ptr) | 218 | struct tipc_node *tipc_node_attach_link(struct link *l_ptr) |
@@ -264,7 +233,7 @@ struct tipc_node *tipc_node_attach_link(struct link *l_ptr) | |||
264 | 233 | ||
265 | if (!n_ptr->links[bearer_id]) { | 234 | if (!n_ptr->links[bearer_id]) { |
266 | n_ptr->links[bearer_id] = l_ptr; | 235 | n_ptr->links[bearer_id] = l_ptr; |
267 | tipc_net.zones[tipc_zone(l_ptr->addr)]->links++; | 236 | tipc_net.links++; |
268 | n_ptr->link_cnt++; | 237 | n_ptr->link_cnt++; |
269 | return n_ptr; | 238 | return n_ptr; |
270 | } | 239 | } |
@@ -278,7 +247,7 @@ struct tipc_node *tipc_node_attach_link(struct link *l_ptr) | |||
278 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr) | 247 | void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr) |
279 | { | 248 | { |
280 | n_ptr->links[l_ptr->b_ptr->identity] = NULL; | 249 | n_ptr->links[l_ptr->b_ptr->identity] = NULL; |
281 | tipc_net.zones[tipc_zone(l_ptr->addr)]->links--; | 250 | tipc_net.links--; |
282 | n_ptr->link_cnt--; | 251 | n_ptr->link_cnt--; |
283 | } | 252 | } |
284 | 253 | ||
@@ -330,48 +299,16 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr) | |||
330 | 299 | ||
331 | static void node_established_contact(struct tipc_node *n_ptr) | 300 | static void node_established_contact(struct tipc_node *n_ptr) |
332 | { | 301 | { |
333 | struct cluster *c_ptr; | 302 | tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); |
334 | |||
335 | dbg("node_established_contact:-> %x\n", n_ptr->addr); | ||
336 | if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) { | ||
337 | tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr); | ||
338 | } | ||
339 | 303 | ||
340 | /* Syncronize broadcast acks */ | 304 | /* Syncronize broadcast acks */ |
341 | n_ptr->bclink.acked = tipc_bclink_get_last_sent(); | 305 | n_ptr->bclink.acked = tipc_bclink_get_last_sent(); |
342 | 306 | ||
343 | if (is_slave(tipc_own_addr)) | ||
344 | return; | ||
345 | if (!in_own_cluster(n_ptr->addr)) { | ||
346 | /* Usage case 1 (see above) */ | ||
347 | c_ptr = tipc_cltr_find(tipc_own_addr); | ||
348 | if (!c_ptr) | ||
349 | c_ptr = tipc_cltr_create(tipc_own_addr); | ||
350 | if (c_ptr) | ||
351 | tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1, | ||
352 | tipc_max_nodes); | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | c_ptr = n_ptr->owner; | ||
357 | if (is_slave(n_ptr->addr)) { | ||
358 | /* Usage case 2 (see above) */ | ||
359 | tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1, tipc_max_nodes); | ||
360 | tipc_cltr_send_local_routes(c_ptr, n_ptr->addr); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | if (n_ptr->bclink.supported) { | 307 | if (n_ptr->bclink.supported) { |
365 | tipc_nmap_add(&tipc_cltr_bcast_nodes, n_ptr->addr); | 308 | tipc_nmap_add(&tipc_bcast_nmap, n_ptr->addr); |
366 | if (n_ptr->addr < tipc_own_addr) | 309 | if (n_ptr->addr < tipc_own_addr) |
367 | tipc_own_tag++; | 310 | tipc_own_tag++; |
368 | } | 311 | } |
369 | |||
370 | /* Case 3 (see above) */ | ||
371 | tipc_net_send_external_routes(n_ptr->addr); | ||
372 | tipc_cltr_send_slave_routes(c_ptr, n_ptr->addr); | ||
373 | tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, LOWEST_SLAVE, | ||
374 | tipc_highest_allowed_slave); | ||
375 | } | 312 | } |
376 | 313 | ||
377 | static void node_cleanup_finished(unsigned long node_addr) | 314 | static void node_cleanup_finished(unsigned long node_addr) |
@@ -390,7 +327,6 @@ static void node_cleanup_finished(unsigned long node_addr) | |||
390 | 327 | ||
391 | static void node_lost_contact(struct tipc_node *n_ptr) | 328 | static void node_lost_contact(struct tipc_node *n_ptr) |
392 | { | 329 | { |
393 | struct cluster *c_ptr; | ||
394 | struct tipc_node_subscr *ns, *tns; | 330 | struct tipc_node_subscr *ns, *tns; |
395 | char addr_string[16]; | 331 | char addr_string[16]; |
396 | u32 i; | 332 | u32 i; |
@@ -398,7 +334,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) | |||
398 | /* Clean up broadcast reception remains */ | 334 | /* Clean up broadcast reception remains */ |
399 | n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0; | 335 | n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0; |
400 | while (n_ptr->bclink.deferred_head) { | 336 | while (n_ptr->bclink.deferred_head) { |
401 | struct sk_buff* buf = n_ptr->bclink.deferred_head; | 337 | struct sk_buff *buf = n_ptr->bclink.deferred_head; |
402 | n_ptr->bclink.deferred_head = buf->next; | 338 | n_ptr->bclink.deferred_head = buf->next; |
403 | buf_discard(buf); | 339 | buf_discard(buf); |
404 | } | 340 | } |
@@ -406,41 +342,14 @@ static void node_lost_contact(struct tipc_node *n_ptr) | |||
406 | buf_discard(n_ptr->bclink.defragm); | 342 | buf_discard(n_ptr->bclink.defragm); |
407 | n_ptr->bclink.defragm = NULL; | 343 | n_ptr->bclink.defragm = NULL; |
408 | } | 344 | } |
409 | if (in_own_cluster(n_ptr->addr) && n_ptr->bclink.supported) { | ||
410 | tipc_bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000)); | ||
411 | } | ||
412 | 345 | ||
413 | /* Update routing tables */ | 346 | if (n_ptr->bclink.supported) { |
414 | if (is_slave(tipc_own_addr)) { | 347 | tipc_bclink_acknowledge(n_ptr, |
415 | tipc_net_remove_as_router(n_ptr->addr); | 348 | mod(n_ptr->bclink.acked + 10000)); |
416 | } else { | 349 | tipc_nmap_remove(&tipc_bcast_nmap, n_ptr->addr); |
417 | if (!in_own_cluster(n_ptr->addr)) { | 350 | if (n_ptr->addr < tipc_own_addr) |
418 | /* Case 4 (see above) */ | 351 | tipc_own_tag--; |
419 | c_ptr = tipc_cltr_find(tipc_own_addr); | ||
420 | tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1, | ||
421 | tipc_max_nodes); | ||
422 | } else { | ||
423 | /* Case 5 (see above) */ | ||
424 | c_ptr = tipc_cltr_find(n_ptr->addr); | ||
425 | if (is_slave(n_ptr->addr)) { | ||
426 | tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1, | ||
427 | tipc_max_nodes); | ||
428 | } else { | ||
429 | if (n_ptr->bclink.supported) { | ||
430 | tipc_nmap_remove(&tipc_cltr_bcast_nodes, | ||
431 | n_ptr->addr); | ||
432 | if (n_ptr->addr < tipc_own_addr) | ||
433 | tipc_own_tag--; | ||
434 | } | ||
435 | tipc_net_remove_as_router(n_ptr->addr); | ||
436 | tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, | ||
437 | LOWEST_SLAVE, | ||
438 | tipc_highest_allowed_slave); | ||
439 | } | ||
440 | } | ||
441 | } | 352 | } |
442 | if (tipc_node_has_active_routes(n_ptr)) | ||
443 | return; | ||
444 | 353 | ||
445 | info("Lost contact with %s\n", | 354 | info("Lost contact with %s\n", |
446 | tipc_addr_string_fill(addr_string, n_ptr->addr)); | 355 | tipc_addr_string_fill(addr_string, n_ptr->addr)); |
@@ -469,125 +378,6 @@ static void node_lost_contact(struct tipc_node *n_ptr) | |||
469 | tipc_k_signal((Handler)node_cleanup_finished, n_ptr->addr); | 378 | tipc_k_signal((Handler)node_cleanup_finished, n_ptr->addr); |
470 | } | 379 | } |
471 | 380 | ||
472 | /** | ||
473 | * tipc_node_select_next_hop - find the next-hop node for a message | ||
474 | * | ||
475 | * Called by when cluster local lookup has failed. | ||
476 | */ | ||
477 | |||
478 | struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector) | ||
479 | { | ||
480 | struct tipc_node *n_ptr; | ||
481 | u32 router_addr; | ||
482 | |||
483 | if (!tipc_addr_domain_valid(addr)) | ||
484 | return NULL; | ||
485 | |||
486 | /* Look for direct link to destination processsor */ | ||
487 | n_ptr = tipc_node_find(addr); | ||
488 | if (n_ptr && tipc_node_has_active_links(n_ptr)) | ||
489 | return n_ptr; | ||
490 | |||
491 | /* Cluster local system nodes *must* have direct links */ | ||
492 | if (!is_slave(addr) && in_own_cluster(addr)) | ||
493 | return NULL; | ||
494 | |||
495 | /* Look for cluster local router with direct link to node */ | ||
496 | router_addr = tipc_node_select_router(n_ptr, selector); | ||
497 | if (router_addr) | ||
498 | return tipc_node_select(router_addr, selector); | ||
499 | |||
500 | /* Slave nodes can only be accessed within own cluster via a | ||
501 | known router with direct link -- if no router was found,give up */ | ||
502 | if (is_slave(addr)) | ||
503 | return NULL; | ||
504 | |||
505 | /* Inter zone/cluster -- find any direct link to remote cluster */ | ||
506 | addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); | ||
507 | n_ptr = tipc_net_select_remote_node(addr, selector); | ||
508 | if (n_ptr && tipc_node_has_active_links(n_ptr)) | ||
509 | return n_ptr; | ||
510 | |||
511 | /* Last resort -- look for any router to anywhere in remote zone */ | ||
512 | router_addr = tipc_net_select_router(addr, selector); | ||
513 | if (router_addr) | ||
514 | return tipc_node_select(router_addr, selector); | ||
515 | |||
516 | return NULL; | ||
517 | } | ||
518 | |||
519 | /** | ||
520 | * tipc_node_select_router - select router to reach specified node | ||
521 | * | ||
522 | * Uses a deterministic and fair algorithm for selecting router node. | ||
523 | */ | ||
524 | |||
525 | u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref) | ||
526 | { | ||
527 | u32 ulim; | ||
528 | u32 mask; | ||
529 | u32 start; | ||
530 | u32 r; | ||
531 | |||
532 | if (!n_ptr) | ||
533 | return 0; | ||
534 | |||
535 | if (n_ptr->last_router < 0) | ||
536 | return 0; | ||
537 | ulim = ((n_ptr->last_router + 1) * 32) - 1; | ||
538 | |||
539 | /* Start entry must be random */ | ||
540 | mask = tipc_max_nodes; | ||
541 | while (mask > ulim) | ||
542 | mask >>= 1; | ||
543 | start = ref & mask; | ||
544 | r = start; | ||
545 | |||
546 | /* Lookup upwards with wrap-around */ | ||
547 | do { | ||
548 | if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1) | ||
549 | break; | ||
550 | } while (++r <= ulim); | ||
551 | if (r > ulim) { | ||
552 | r = 1; | ||
553 | do { | ||
554 | if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1) | ||
555 | break; | ||
556 | } while (++r < start); | ||
557 | assert(r != start); | ||
558 | } | ||
559 | assert(r && (r <= ulim)); | ||
560 | return tipc_addr(own_zone(), own_cluster(), r); | ||
561 | } | ||
562 | |||
563 | void tipc_node_add_router(struct tipc_node *n_ptr, u32 router) | ||
564 | { | ||
565 | u32 r_num = tipc_node(router); | ||
566 | |||
567 | n_ptr->routers[r_num / 32] = | ||
568 | ((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]); | ||
569 | n_ptr->last_router = tipc_max_nodes / 32; | ||
570 | while ((--n_ptr->last_router >= 0) && | ||
571 | !n_ptr->routers[n_ptr->last_router]); | ||
572 | } | ||
573 | |||
574 | void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router) | ||
575 | { | ||
576 | u32 r_num = tipc_node(router); | ||
577 | |||
578 | if (n_ptr->last_router < 0) | ||
579 | return; /* No routes */ | ||
580 | |||
581 | n_ptr->routers[r_num / 32] = | ||
582 | ((~(1 << (r_num % 32))) & (n_ptr->routers[r_num / 32])); | ||
583 | n_ptr->last_router = tipc_max_nodes / 32; | ||
584 | while ((--n_ptr->last_router >= 0) && | ||
585 | !n_ptr->routers[n_ptr->last_router]); | ||
586 | |||
587 | if (!tipc_node_is_up(n_ptr)) | ||
588 | node_lost_contact(n_ptr); | ||
589 | } | ||
590 | |||
591 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) | 381 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) |
592 | { | 382 | { |
593 | u32 domain; | 383 | u32 domain; |
@@ -595,6 +385,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) | |||
595 | struct tipc_node *n_ptr; | 385 | struct tipc_node *n_ptr; |
596 | struct tipc_node_info node_info; | 386 | struct tipc_node_info node_info; |
597 | u32 payload_size; | 387 | u32 payload_size; |
388 | u32 n_num; | ||
598 | 389 | ||
599 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) | 390 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) |
600 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | 391 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); |
@@ -605,15 +396,15 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) | |||
605 | " (network address)"); | 396 | " (network address)"); |
606 | 397 | ||
607 | read_lock_bh(&tipc_net_lock); | 398 | read_lock_bh(&tipc_net_lock); |
608 | if (!tipc_nodes) { | 399 | if (!tipc_net.nodes) { |
609 | read_unlock_bh(&tipc_net_lock); | 400 | read_unlock_bh(&tipc_net_lock); |
610 | return tipc_cfg_reply_none(); | 401 | return tipc_cfg_reply_none(); |
611 | } | 402 | } |
612 | 403 | ||
613 | /* For now, get space for all other nodes | 404 | /* For now, get space for all other nodes */ |
614 | (will need to modify this when slave nodes are supported */ | ||
615 | 405 | ||
616 | payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1); | 406 | payload_size = TLV_SPACE(sizeof(node_info)) * |
407 | (tipc_net.highest_node - 1); | ||
617 | if (payload_size > 32768u) { | 408 | if (payload_size > 32768u) { |
618 | read_unlock_bh(&tipc_net_lock); | 409 | read_unlock_bh(&tipc_net_lock); |
619 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | 410 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED |
@@ -627,8 +418,9 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) | |||
627 | 418 | ||
628 | /* Add TLVs for all nodes in scope */ | 419 | /* Add TLVs for all nodes in scope */ |
629 | 420 | ||
630 | for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) { | 421 | for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) { |
631 | if (!tipc_in_scope(domain, n_ptr->addr)) | 422 | n_ptr = tipc_net.nodes[n_num]; |
423 | if (!n_ptr || !tipc_in_scope(domain, n_ptr->addr)) | ||
632 | continue; | 424 | continue; |
633 | node_info.addr = htonl(n_ptr->addr); | 425 | node_info.addr = htonl(n_ptr->addr); |
634 | node_info.up = htonl(tipc_node_is_up(n_ptr)); | 426 | node_info.up = htonl(tipc_node_is_up(n_ptr)); |
@@ -647,6 +439,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) | |||
647 | struct tipc_node *n_ptr; | 439 | struct tipc_node *n_ptr; |
648 | struct tipc_link_info link_info; | 440 | struct tipc_link_info link_info; |
649 | u32 payload_size; | 441 | u32 payload_size; |
442 | u32 n_num; | ||
650 | 443 | ||
651 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) | 444 | if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) |
652 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); | 445 | return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); |
@@ -663,8 +456,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) | |||
663 | 456 | ||
664 | /* Get space for all unicast links + multicast link */ | 457 | /* Get space for all unicast links + multicast link */ |
665 | 458 | ||
666 | payload_size = TLV_SPACE(sizeof(link_info)) * | 459 | payload_size = TLV_SPACE(sizeof(link_info)) * (tipc_net.links + 1); |
667 | (tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1); | ||
668 | if (payload_size > 32768u) { | 460 | if (payload_size > 32768u) { |
669 | read_unlock_bh(&tipc_net_lock); | 461 | read_unlock_bh(&tipc_net_lock); |
670 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED | 462 | return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED |
@@ -685,10 +477,11 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) | |||
685 | 477 | ||
686 | /* Add TLVs for any other links in scope */ | 478 | /* Add TLVs for any other links in scope */ |
687 | 479 | ||
688 | for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) { | 480 | for (n_num = 1; n_num <= tipc_net.highest_node; n_num++) { |
689 | u32 i; | 481 | u32 i; |
690 | 482 | ||
691 | if (!tipc_in_scope(domain, n_ptr->addr)) | 483 | n_ptr = tipc_net.nodes[n_num]; |
484 | if (!n_ptr || !tipc_in_scope(domain, n_ptr->addr)) | ||
692 | continue; | 485 | continue; |
693 | tipc_node_lock(n_ptr); | 486 | tipc_node_lock(n_ptr); |
694 | for (i = 0; i < MAX_BEARERS; i++) { | 487 | for (i = 0; i < MAX_BEARERS; i++) { |
diff --git a/net/tipc/node.h b/net/tipc/node.h index fff331b2d26c..206a8efa410e 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
@@ -39,14 +39,13 @@ | |||
39 | 39 | ||
40 | #include "node_subscr.h" | 40 | #include "node_subscr.h" |
41 | #include "addr.h" | 41 | #include "addr.h" |
42 | #include "cluster.h" | 42 | #include "net.h" |
43 | #include "bearer.h" | 43 | #include "bearer.h" |
44 | 44 | ||
45 | /** | 45 | /** |
46 | * struct tipc_node - TIPC node structure | 46 | * struct tipc_node - TIPC node structure |
47 | * @addr: network address of node | 47 | * @addr: network address of node |
48 | * @lock: spinlock governing access to structure | 48 | * @lock: spinlock governing access to structure |
49 | * @owner: pointer to cluster that node belongs to | ||
50 | * @next: pointer to next node in sorted list of cluster's nodes | 49 | * @next: pointer to next node in sorted list of cluster's nodes |
51 | * @nsub: list of "node down" subscriptions monitoring node | 50 | * @nsub: list of "node down" subscriptions monitoring node |
52 | * @active_links: pointers to active links to node | 51 | * @active_links: pointers to active links to node |
@@ -55,8 +54,6 @@ | |||
55 | * @cleanup_required: non-zero if cleaning up after a prior loss of contact | 54 | * @cleanup_required: non-zero if cleaning up after a prior loss of contact |
56 | * @link_cnt: number of links to node | 55 | * @link_cnt: number of links to node |
57 | * @permit_changeover: non-zero if node has redundant links to this system | 56 | * @permit_changeover: non-zero if node has redundant links to this system |
58 | * @routers: bitmap (used for multicluster communication) | ||
59 | * @last_router: (used for multicluster communication) | ||
60 | * @bclink: broadcast-related info | 57 | * @bclink: broadcast-related info |
61 | * @supported: non-zero if node supports TIPC b'cast capability | 58 | * @supported: non-zero if node supports TIPC b'cast capability |
62 | * @acked: sequence # of last outbound b'cast message acknowledged by node | 59 | * @acked: sequence # of last outbound b'cast message acknowledged by node |
@@ -72,7 +69,6 @@ | |||
72 | struct tipc_node { | 69 | struct tipc_node { |
73 | u32 addr; | 70 | u32 addr; |
74 | spinlock_t lock; | 71 | spinlock_t lock; |
75 | struct cluster *owner; | ||
76 | struct tipc_node *next; | 72 | struct tipc_node *next; |
77 | struct list_head nsub; | 73 | struct list_head nsub; |
78 | struct link *active_links[2]; | 74 | struct link *active_links[2]; |
@@ -81,8 +77,6 @@ struct tipc_node { | |||
81 | int working_links; | 77 | int working_links; |
82 | int cleanup_required; | 78 | int cleanup_required; |
83 | int permit_changeover; | 79 | int permit_changeover; |
84 | u32 routers[512/32]; | ||
85 | int last_router; | ||
86 | struct { | 80 | struct { |
87 | int supported; | 81 | int supported; |
88 | u32 acked; | 82 | u32 acked; |
@@ -106,34 +100,17 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr); | |||
106 | void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr); | 100 | void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr); |
107 | int tipc_node_has_active_links(struct tipc_node *n_ptr); | 101 | int tipc_node_has_active_links(struct tipc_node *n_ptr); |
108 | int tipc_node_has_redundant_links(struct tipc_node *n_ptr); | 102 | int tipc_node_has_redundant_links(struct tipc_node *n_ptr); |
109 | u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref); | ||
110 | struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector); | ||
111 | int tipc_node_is_up(struct tipc_node *n_ptr); | 103 | int tipc_node_is_up(struct tipc_node *n_ptr); |
112 | void tipc_node_add_router(struct tipc_node *n_ptr, u32 router); | ||
113 | void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router); | ||
114 | struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); | 104 | struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space); |
115 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); | 105 | struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space); |
116 | 106 | ||
117 | static inline struct tipc_node *tipc_node_find(u32 addr) | 107 | static inline struct tipc_node *tipc_node_find(u32 addr) |
118 | { | 108 | { |
119 | if (likely(in_own_cluster(addr))) | 109 | if (likely(in_own_cluster(addr))) |
120 | return tipc_local_nodes[tipc_node(addr)]; | 110 | return tipc_net.nodes[tipc_node(addr)]; |
121 | else if (tipc_addr_domain_valid(addr)) { | ||
122 | struct cluster *c_ptr = tipc_cltr_find(addr); | ||
123 | |||
124 | if (c_ptr) | ||
125 | return c_ptr->nodes[tipc_node(addr)]; | ||
126 | } | ||
127 | return NULL; | 111 | return NULL; |
128 | } | 112 | } |
129 | 113 | ||
130 | static inline struct tipc_node *tipc_node_select(u32 addr, u32 selector) | ||
131 | { | ||
132 | if (likely(in_own_cluster(addr))) | ||
133 | return tipc_local_nodes[tipc_node(addr)]; | ||
134 | return tipc_node_select_next_hop(addr, selector); | ||
135 | } | ||
136 | |||
137 | static inline void tipc_node_lock(struct tipc_node *n_ptr) | 114 | static inline void tipc_node_lock(struct tipc_node *n_ptr) |
138 | { | 115 | { |
139 | spin_lock_bh(&n_ptr->lock); | 116 | spin_lock_bh(&n_ptr->lock); |
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index 19194d476a9e..018a55332d91 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c | |||
@@ -35,10 +35,8 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "dbg.h" | ||
39 | #include "node_subscr.h" | 38 | #include "node_subscr.h" |
40 | #include "node.h" | 39 | #include "node.h" |
41 | #include "addr.h" | ||
42 | 40 | ||
43 | /** | 41 | /** |
44 | * tipc_nodesub_subscribe - create "node down" subscription for specified node | 42 | * tipc_nodesub_subscribe - create "node down" subscription for specified node |
diff --git a/net/tipc/port.c b/net/tipc/port.c index 82092eaa1536..067bab2a0b98 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
@@ -36,15 +36,8 @@ | |||
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "config.h" | 38 | #include "config.h" |
39 | #include "dbg.h" | ||
40 | #include "port.h" | 39 | #include "port.h" |
41 | #include "addr.h" | ||
42 | #include "link.h" | ||
43 | #include "node.h" | ||
44 | #include "name_table.h" | 40 | #include "name_table.h" |
45 | #include "user_reg.h" | ||
46 | #include "msg.h" | ||
47 | #include "bcast.h" | ||
48 | 41 | ||
49 | /* Connection management: */ | 42 | /* Connection management: */ |
50 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ | 43 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ |
@@ -53,16 +46,16 @@ | |||
53 | 46 | ||
54 | #define MAX_REJECT_SIZE 1024 | 47 | #define MAX_REJECT_SIZE 1024 |
55 | 48 | ||
56 | static struct sk_buff *msg_queue_head = NULL; | 49 | static struct sk_buff *msg_queue_head; |
57 | static struct sk_buff *msg_queue_tail = NULL; | 50 | static struct sk_buff *msg_queue_tail; |
58 | 51 | ||
59 | DEFINE_SPINLOCK(tipc_port_list_lock); | 52 | DEFINE_SPINLOCK(tipc_port_list_lock); |
60 | static DEFINE_SPINLOCK(queue_lock); | 53 | static DEFINE_SPINLOCK(queue_lock); |
61 | 54 | ||
62 | static LIST_HEAD(ports); | 55 | static LIST_HEAD(ports); |
63 | static void port_handle_node_down(unsigned long ref); | 56 | static void port_handle_node_down(unsigned long ref); |
64 | static struct sk_buff* port_build_self_abort_msg(struct port *,u32 err); | 57 | static struct sk_buff *port_build_self_abort_msg(struct port *, u32 err); |
65 | static struct sk_buff* port_build_peer_abort_msg(struct port *,u32 err); | 58 | static struct sk_buff *port_build_peer_abort_msg(struct port *, u32 err); |
66 | static void port_timeout(unsigned long ref); | 59 | static void port_timeout(unsigned long ref); |
67 | 60 | ||
68 | 61 | ||
@@ -94,7 +87,7 @@ static void port_incr_out_seqno(struct port *p_ptr) | |||
94 | * tipc_multicast - send a multicast message to local and remote destinations | 87 | * tipc_multicast - send a multicast message to local and remote destinations |
95 | */ | 88 | */ |
96 | 89 | ||
97 | int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain, | 90 | int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, |
98 | u32 num_sect, struct iovec const *msg_sect) | 91 | u32 num_sect, struct iovec const *msg_sect) |
99 | { | 92 | { |
100 | struct tipc_msg *hdr; | 93 | struct tipc_msg *hdr; |
@@ -138,9 +131,8 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain, | |||
138 | } | 131 | } |
139 | } | 132 | } |
140 | res = tipc_bclink_send_msg(buf); | 133 | res = tipc_bclink_send_msg(buf); |
141 | if ((res < 0) && (dports.count != 0)) { | 134 | if ((res < 0) && (dports.count != 0)) |
142 | buf_discard(ibuf); | 135 | buf_discard(ibuf); |
143 | } | ||
144 | } else { | 136 | } else { |
145 | ibuf = buf; | 137 | ibuf = buf; |
146 | } | 138 | } |
@@ -162,7 +154,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain, | |||
162 | 154 | ||
163 | void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) | 155 | void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) |
164 | { | 156 | { |
165 | struct tipc_msg* msg; | 157 | struct tipc_msg *msg; |
166 | struct port_list dports = {0, NULL, }; | 158 | struct port_list dports = {0, NULL, }; |
167 | struct port_list *item = dp; | 159 | struct port_list *item = dp; |
168 | int cnt = 0; | 160 | int cnt = 0; |
@@ -195,13 +187,11 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp) | |||
195 | 187 | ||
196 | if (b == NULL) { | 188 | if (b == NULL) { |
197 | warn("Unable to deliver multicast message(s)\n"); | 189 | warn("Unable to deliver multicast message(s)\n"); |
198 | msg_dbg(msg, "LOST:"); | ||
199 | goto exit; | 190 | goto exit; |
200 | } | 191 | } |
201 | if ((index == 0) && (cnt != 0)) { | 192 | if ((index == 0) && (cnt != 0)) |
202 | item = item->next; | 193 | item = item->next; |
203 | } | 194 | msg_set_destport(buf_msg(b), item->ports[index]); |
204 | msg_set_destport(buf_msg(b),item->ports[index]); | ||
205 | tipc_port_recv_msg(b); | 195 | tipc_port_recv_msg(b); |
206 | } | 196 | } |
207 | } | 197 | } |
@@ -277,10 +267,7 @@ int tipc_deleteport(u32 ref) | |||
277 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 267 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
278 | tipc_nodesub_unsubscribe(&p_ptr->subscription); | 268 | tipc_nodesub_unsubscribe(&p_ptr->subscription); |
279 | } | 269 | } |
280 | if (p_ptr->user_port) { | 270 | kfree(p_ptr->user_port); |
281 | tipc_reg_remove_port(p_ptr->user_port); | ||
282 | kfree(p_ptr->user_port); | ||
283 | } | ||
284 | 271 | ||
285 | spin_lock_bh(&tipc_port_list_lock); | 272 | spin_lock_bh(&tipc_port_list_lock); |
286 | list_del(&p_ptr->port_list); | 273 | list_del(&p_ptr->port_list); |
@@ -288,7 +275,6 @@ int tipc_deleteport(u32 ref) | |||
288 | spin_unlock_bh(&tipc_port_list_lock); | 275 | spin_unlock_bh(&tipc_port_list_lock); |
289 | k_term_timer(&p_ptr->timer); | 276 | k_term_timer(&p_ptr->timer); |
290 | kfree(p_ptr); | 277 | kfree(p_ptr); |
291 | dbg("Deleted port %u\n", ref); | ||
292 | tipc_net_route_msg(buf); | 278 | tipc_net_route_msg(buf); |
293 | return 0; | 279 | return 0; |
294 | } | 280 | } |
@@ -374,7 +360,6 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode, | |||
374 | msg_set_orignode(msg, orignode); | 360 | msg_set_orignode(msg, orignode); |
375 | msg_set_transp_seqno(msg, seqno); | 361 | msg_set_transp_seqno(msg, seqno); |
376 | msg_set_msgcnt(msg, ack); | 362 | msg_set_msgcnt(msg, ack); |
377 | msg_dbg(msg, "PORT>SEND>:"); | ||
378 | } | 363 | } |
379 | return buf; | 364 | return buf; |
380 | } | 365 | } |
@@ -392,7 +377,6 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) | |||
392 | data_sz = MAX_REJECT_SIZE; | 377 | data_sz = MAX_REJECT_SIZE; |
393 | if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE)) | 378 | if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE)) |
394 | imp++; | 379 | imp++; |
395 | msg_dbg(msg, "port->rej: "); | ||
396 | 380 | ||
397 | /* discard rejected message if it shouldn't be returned to sender */ | 381 | /* discard rejected message if it shouldn't be returned to sender */ |
398 | if (msg_errcode(msg) || msg_dest_droppable(msg)) { | 382 | if (msg_errcode(msg) || msg_dest_droppable(msg)) { |
@@ -498,7 +482,7 @@ static void port_timeout(unsigned long ref) | |||
498 | static void port_handle_node_down(unsigned long ref) | 482 | static void port_handle_node_down(unsigned long ref) |
499 | { | 483 | { |
500 | struct port *p_ptr = tipc_port_lock(ref); | 484 | struct port *p_ptr = tipc_port_lock(ref); |
501 | struct sk_buff* buf = NULL; | 485 | struct sk_buff *buf = NULL; |
502 | 486 | ||
503 | if (!p_ptr) | 487 | if (!p_ptr) |
504 | return; | 488 | return; |
@@ -555,8 +539,6 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf) | |||
555 | struct sk_buff *r_buf = NULL; | 539 | struct sk_buff *r_buf = NULL; |
556 | struct sk_buff *abort_buf = NULL; | 540 | struct sk_buff *abort_buf = NULL; |
557 | 541 | ||
558 | msg_dbg(msg, "PORT<RECV<:"); | ||
559 | |||
560 | if (!p_ptr) { | 542 | if (!p_ptr) { |
561 | err = TIPC_ERR_NO_PORT; | 543 | err = TIPC_ERR_NO_PORT; |
562 | } else if (p_ptr->publ.connected) { | 544 | } else if (p_ptr->publ.connected) { |
@@ -636,8 +618,7 @@ static void port_print(struct port *p_ptr, struct print_buf *buf, int full_id) | |||
636 | tipc_printf(buf, " via {%u,%u}", | 618 | tipc_printf(buf, " via {%u,%u}", |
637 | p_ptr->publ.conn_type, | 619 | p_ptr->publ.conn_type, |
638 | p_ptr->publ.conn_instance); | 620 | p_ptr->publ.conn_instance); |
639 | } | 621 | } else if (p_ptr->publ.published) { |
640 | else if (p_ptr->publ.published) { | ||
641 | tipc_printf(buf, " bound to"); | 622 | tipc_printf(buf, " bound to"); |
642 | list_for_each_entry(publ, &p_ptr->publications, pport_list) { | 623 | list_for_each_entry(publ, &p_ptr->publications, pport_list) { |
643 | if (publ->lower == publ->upper) | 624 | if (publ->lower == publ->upper) |
@@ -940,12 +921,10 @@ void tipc_acknowledge(u32 ref, u32 ack) | |||
940 | } | 921 | } |
941 | 922 | ||
942 | /* | 923 | /* |
943 | * tipc_createport(): user level call. Will add port to | 924 | * tipc_createport(): user level call. |
944 | * registry if non-zero user_ref. | ||
945 | */ | 925 | */ |
946 | 926 | ||
947 | int tipc_createport(u32 user_ref, | 927 | int tipc_createport(void *usr_handle, |
948 | void *usr_handle, | ||
949 | unsigned int importance, | 928 | unsigned int importance, |
950 | tipc_msg_err_event error_cb, | 929 | tipc_msg_err_event error_cb, |
951 | tipc_named_msg_err_event named_error_cb, | 930 | tipc_named_msg_err_event named_error_cb, |
@@ -972,7 +951,6 @@ int tipc_createport(u32 user_ref, | |||
972 | } | 951 | } |
973 | 952 | ||
974 | p_ptr->user_port = up_ptr; | 953 | p_ptr->user_port = up_ptr; |
975 | up_ptr->user_ref = user_ref; | ||
976 | up_ptr->usr_handle = usr_handle; | 954 | up_ptr->usr_handle = usr_handle; |
977 | up_ptr->ref = p_ptr->publ.ref; | 955 | up_ptr->ref = p_ptr->publ.ref; |
978 | up_ptr->err_cb = error_cb; | 956 | up_ptr->err_cb = error_cb; |
@@ -982,20 +960,11 @@ int tipc_createport(u32 user_ref, | |||
982 | up_ptr->named_msg_cb = named_msg_cb; | 960 | up_ptr->named_msg_cb = named_msg_cb; |
983 | up_ptr->conn_msg_cb = conn_msg_cb; | 961 | up_ptr->conn_msg_cb = conn_msg_cb; |
984 | up_ptr->continue_event_cb = continue_event_cb; | 962 | up_ptr->continue_event_cb = continue_event_cb; |
985 | INIT_LIST_HEAD(&up_ptr->uport_list); | ||
986 | tipc_reg_add_port(up_ptr); | ||
987 | *portref = p_ptr->publ.ref; | 963 | *portref = p_ptr->publ.ref; |
988 | tipc_port_unlock(p_ptr); | 964 | tipc_port_unlock(p_ptr); |
989 | return 0; | 965 | return 0; |
990 | } | 966 | } |
991 | 967 | ||
992 | int tipc_ownidentity(u32 ref, struct tipc_portid *id) | ||
993 | { | ||
994 | id->ref = ref; | ||
995 | id->node = tipc_own_addr; | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | int tipc_portimportance(u32 ref, unsigned int *importance) | 968 | int tipc_portimportance(u32 ref, unsigned int *importance) |
1000 | { | 969 | { |
1001 | struct port *p_ptr; | 970 | struct port *p_ptr; |
@@ -1035,9 +1004,6 @@ int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq) | |||
1035 | if (!p_ptr) | 1004 | if (!p_ptr) |
1036 | return -EINVAL; | 1005 | return -EINVAL; |
1037 | 1006 | ||
1038 | dbg("tipc_publ %u, p_ptr = %x, conn = %x, scope = %x, " | ||
1039 | "lower = %u, upper = %u\n", | ||
1040 | ref, p_ptr, p_ptr->publ.connected, scope, seq->lower, seq->upper); | ||
1041 | if (p_ptr->publ.connected) | 1007 | if (p_ptr->publ.connected) |
1042 | goto exit; | 1008 | goto exit; |
1043 | if (seq->lower > seq->upper) | 1009 | if (seq->lower > seq->upper) |
@@ -1123,17 +1089,14 @@ int tipc_connect2port(u32 ref, struct tipc_portid const *peer) | |||
1123 | msg_set_origport(msg, p_ptr->publ.ref); | 1089 | msg_set_origport(msg, p_ptr->publ.ref); |
1124 | msg_set_transp_seqno(msg, 42); | 1090 | msg_set_transp_seqno(msg, 42); |
1125 | msg_set_type(msg, TIPC_CONN_MSG); | 1091 | msg_set_type(msg, TIPC_CONN_MSG); |
1126 | if (!may_route(peer->node)) | 1092 | msg_set_hdr_sz(msg, SHORT_H_SIZE); |
1127 | msg_set_hdr_sz(msg, SHORT_H_SIZE); | ||
1128 | else | ||
1129 | msg_set_hdr_sz(msg, LONG_H_SIZE); | ||
1130 | 1093 | ||
1131 | p_ptr->probing_interval = PROBING_INTERVAL; | 1094 | p_ptr->probing_interval = PROBING_INTERVAL; |
1132 | p_ptr->probing_state = CONFIRMED; | 1095 | p_ptr->probing_state = CONFIRMED; |
1133 | p_ptr->publ.connected = 1; | 1096 | p_ptr->publ.connected = 1; |
1134 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 1097 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
1135 | 1098 | ||
1136 | tipc_nodesub_subscribe(&p_ptr->subscription,peer->node, | 1099 | tipc_nodesub_subscribe(&p_ptr->subscription, peer->node, |
1137 | (void *)(unsigned long)ref, | 1100 | (void *)(unsigned long)ref, |
1138 | (net_ev_handler)port_handle_node_down); | 1101 | (net_ev_handler)port_handle_node_down); |
1139 | res = 0; | 1102 | res = 0; |
@@ -1271,16 +1234,11 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect) | |||
1271 | } | 1234 | } |
1272 | 1235 | ||
1273 | /** | 1236 | /** |
1274 | * tipc_forward2name - forward message sections to port name | 1237 | * tipc_send2name - send message sections to port name |
1275 | */ | 1238 | */ |
1276 | 1239 | ||
1277 | static int tipc_forward2name(u32 ref, | 1240 | int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain, |
1278 | struct tipc_name const *name, | 1241 | unsigned int num_sect, struct iovec const *msg_sect) |
1279 | u32 domain, | ||
1280 | u32 num_sect, | ||
1281 | struct iovec const *msg_sect, | ||
1282 | struct tipc_portid const *orig, | ||
1283 | unsigned int importance) | ||
1284 | { | 1242 | { |
1285 | struct port *p_ptr; | 1243 | struct port *p_ptr; |
1286 | struct tipc_msg *msg; | 1244 | struct tipc_msg *msg; |
@@ -1294,14 +1252,12 @@ static int tipc_forward2name(u32 ref, | |||
1294 | 1252 | ||
1295 | msg = &p_ptr->publ.phdr; | 1253 | msg = &p_ptr->publ.phdr; |
1296 | msg_set_type(msg, TIPC_NAMED_MSG); | 1254 | msg_set_type(msg, TIPC_NAMED_MSG); |
1297 | msg_set_orignode(msg, orig->node); | 1255 | msg_set_orignode(msg, tipc_own_addr); |
1298 | msg_set_origport(msg, orig->ref); | 1256 | msg_set_origport(msg, ref); |
1299 | msg_set_hdr_sz(msg, LONG_H_SIZE); | 1257 | msg_set_hdr_sz(msg, LONG_H_SIZE); |
1300 | msg_set_nametype(msg, name->type); | 1258 | msg_set_nametype(msg, name->type); |
1301 | msg_set_nameinst(msg, name->instance); | 1259 | msg_set_nameinst(msg, name->instance); |
1302 | msg_set_lookup_scope(msg, tipc_addr_scope(domain)); | 1260 | msg_set_lookup_scope(msg, tipc_addr_scope(domain)); |
1303 | if (importance <= TIPC_CRITICAL_IMPORTANCE) | ||
1304 | msg_set_importance(msg,importance); | ||
1305 | destport = tipc_nametbl_translate(name->type, name->instance, &destnode); | 1261 | destport = tipc_nametbl_translate(name->type, name->instance, &destnode); |
1306 | msg_set_destnode(msg, destnode); | 1262 | msg_set_destnode(msg, destnode); |
1307 | msg_set_destport(msg, destport); | 1263 | msg_set_destport(msg, destport); |
@@ -1325,33 +1281,11 @@ static int tipc_forward2name(u32 ref, | |||
1325 | } | 1281 | } |
1326 | 1282 | ||
1327 | /** | 1283 | /** |
1328 | * tipc_send2name - send message sections to port name | 1284 | * tipc_send2port - send message sections to port identity |
1329 | */ | ||
1330 | |||
1331 | int tipc_send2name(u32 ref, | ||
1332 | struct tipc_name const *name, | ||
1333 | unsigned int domain, | ||
1334 | unsigned int num_sect, | ||
1335 | struct iovec const *msg_sect) | ||
1336 | { | ||
1337 | struct tipc_portid orig; | ||
1338 | |||
1339 | orig.ref = ref; | ||
1340 | orig.node = tipc_own_addr; | ||
1341 | return tipc_forward2name(ref, name, domain, num_sect, msg_sect, &orig, | ||
1342 | TIPC_PORT_IMPORTANCE); | ||
1343 | } | ||
1344 | |||
1345 | /** | ||
1346 | * tipc_forward2port - forward message sections to port identity | ||
1347 | */ | 1285 | */ |
1348 | 1286 | ||
1349 | static int tipc_forward2port(u32 ref, | 1287 | int tipc_send2port(u32 ref, struct tipc_portid const *dest, |
1350 | struct tipc_portid const *dest, | 1288 | unsigned int num_sect, struct iovec const *msg_sect) |
1351 | unsigned int num_sect, | ||
1352 | struct iovec const *msg_sect, | ||
1353 | struct tipc_portid const *orig, | ||
1354 | unsigned int importance) | ||
1355 | { | 1289 | { |
1356 | struct port *p_ptr; | 1290 | struct port *p_ptr; |
1357 | struct tipc_msg *msg; | 1291 | struct tipc_msg *msg; |
@@ -1363,13 +1297,11 @@ static int tipc_forward2port(u32 ref, | |||
1363 | 1297 | ||
1364 | msg = &p_ptr->publ.phdr; | 1298 | msg = &p_ptr->publ.phdr; |
1365 | msg_set_type(msg, TIPC_DIRECT_MSG); | 1299 | msg_set_type(msg, TIPC_DIRECT_MSG); |
1366 | msg_set_orignode(msg, orig->node); | 1300 | msg_set_orignode(msg, tipc_own_addr); |
1367 | msg_set_origport(msg, orig->ref); | 1301 | msg_set_origport(msg, ref); |
1368 | msg_set_destnode(msg, dest->node); | 1302 | msg_set_destnode(msg, dest->node); |
1369 | msg_set_destport(msg, dest->ref); | 1303 | msg_set_destport(msg, dest->ref); |
1370 | msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); | 1304 | msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); |
1371 | if (importance <= TIPC_CRITICAL_IMPORTANCE) | ||
1372 | msg_set_importance(msg, importance); | ||
1373 | p_ptr->sent++; | 1305 | p_ptr->sent++; |
1374 | if (dest->node == tipc_own_addr) | 1306 | if (dest->node == tipc_own_addr) |
1375 | return tipc_port_recv_sections(p_ptr, num_sect, msg_sect); | 1307 | return tipc_port_recv_sections(p_ptr, num_sect, msg_sect); |
@@ -1384,31 +1316,11 @@ static int tipc_forward2port(u32 ref, | |||
1384 | } | 1316 | } |
1385 | 1317 | ||
1386 | /** | 1318 | /** |
1387 | * tipc_send2port - send message sections to port identity | 1319 | * tipc_send_buf2port - send message buffer to port identity |
1388 | */ | 1320 | */ |
1389 | 1321 | ||
1390 | int tipc_send2port(u32 ref, | 1322 | int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest, |
1391 | struct tipc_portid const *dest, | 1323 | struct sk_buff *buf, unsigned int dsz) |
1392 | unsigned int num_sect, | ||
1393 | struct iovec const *msg_sect) | ||
1394 | { | ||
1395 | struct tipc_portid orig; | ||
1396 | |||
1397 | orig.ref = ref; | ||
1398 | orig.node = tipc_own_addr; | ||
1399 | return tipc_forward2port(ref, dest, num_sect, msg_sect, &orig, | ||
1400 | TIPC_PORT_IMPORTANCE); | ||
1401 | } | ||
1402 | |||
1403 | /** | ||
1404 | * tipc_forward_buf2port - forward message buffer to port identity | ||
1405 | */ | ||
1406 | static int tipc_forward_buf2port(u32 ref, | ||
1407 | struct tipc_portid const *dest, | ||
1408 | struct sk_buff *buf, | ||
1409 | unsigned int dsz, | ||
1410 | struct tipc_portid const *orig, | ||
1411 | unsigned int importance) | ||
1412 | { | 1324 | { |
1413 | struct port *p_ptr; | 1325 | struct port *p_ptr; |
1414 | struct tipc_msg *msg; | 1326 | struct tipc_msg *msg; |
@@ -1420,20 +1332,17 @@ static int tipc_forward_buf2port(u32 ref, | |||
1420 | 1332 | ||
1421 | msg = &p_ptr->publ.phdr; | 1333 | msg = &p_ptr->publ.phdr; |
1422 | msg_set_type(msg, TIPC_DIRECT_MSG); | 1334 | msg_set_type(msg, TIPC_DIRECT_MSG); |
1423 | msg_set_orignode(msg, orig->node); | 1335 | msg_set_orignode(msg, tipc_own_addr); |
1424 | msg_set_origport(msg, orig->ref); | 1336 | msg_set_origport(msg, ref); |
1425 | msg_set_destnode(msg, dest->node); | 1337 | msg_set_destnode(msg, dest->node); |
1426 | msg_set_destport(msg, dest->ref); | 1338 | msg_set_destport(msg, dest->ref); |
1427 | msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); | 1339 | msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); |
1428 | if (importance <= TIPC_CRITICAL_IMPORTANCE) | ||
1429 | msg_set_importance(msg, importance); | ||
1430 | msg_set_size(msg, DIR_MSG_H_SIZE + dsz); | 1340 | msg_set_size(msg, DIR_MSG_H_SIZE + dsz); |
1431 | if (skb_cow(buf, DIR_MSG_H_SIZE)) | 1341 | if (skb_cow(buf, DIR_MSG_H_SIZE)) |
1432 | return -ENOMEM; | 1342 | return -ENOMEM; |
1433 | 1343 | ||
1434 | skb_push(buf, DIR_MSG_H_SIZE); | 1344 | skb_push(buf, DIR_MSG_H_SIZE); |
1435 | skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE); | 1345 | skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE); |
1436 | msg_dbg(msg, "buf2port: "); | ||
1437 | p_ptr->sent++; | 1346 | p_ptr->sent++; |
1438 | if (dest->node == tipc_own_addr) | 1347 | if (dest->node == tipc_own_addr) |
1439 | return tipc_port_recv_msg(buf); | 1348 | return tipc_port_recv_msg(buf); |
@@ -1445,20 +1354,3 @@ static int tipc_forward_buf2port(u32 ref, | |||
1445 | return -ELINKCONG; | 1354 | return -ELINKCONG; |
1446 | } | 1355 | } |
1447 | 1356 | ||
1448 | /** | ||
1449 | * tipc_send_buf2port - send message buffer to port identity | ||
1450 | */ | ||
1451 | |||
1452 | int tipc_send_buf2port(u32 ref, | ||
1453 | struct tipc_portid const *dest, | ||
1454 | struct sk_buff *buf, | ||
1455 | unsigned int dsz) | ||
1456 | { | ||
1457 | struct tipc_portid orig; | ||
1458 | |||
1459 | orig.ref = ref; | ||
1460 | orig.node = tipc_own_addr; | ||
1461 | return tipc_forward_buf2port(ref, dest, buf, dsz, &orig, | ||
1462 | TIPC_PORT_IMPORTANCE); | ||
1463 | } | ||
1464 | |||
diff --git a/net/tipc/port.h b/net/tipc/port.h index 73bbf442b346..8e84b989949c 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h | |||
@@ -37,24 +37,52 @@ | |||
37 | #ifndef _TIPC_PORT_H | 37 | #ifndef _TIPC_PORT_H |
38 | #define _TIPC_PORT_H | 38 | #define _TIPC_PORT_H |
39 | 39 | ||
40 | #include "core.h" | ||
41 | #include "ref.h" | 40 | #include "ref.h" |
42 | #include "net.h" | 41 | #include "net.h" |
43 | #include "msg.h" | 42 | #include "msg.h" |
44 | #include "dbg.h" | ||
45 | #include "node_subscr.h" | 43 | #include "node_subscr.h" |
46 | 44 | ||
45 | #define TIPC_FLOW_CONTROL_WIN 512 | ||
46 | |||
47 | typedef void (*tipc_msg_err_event) (void *usr_handle, u32 portref, | ||
48 | struct sk_buff **buf, unsigned char const *data, | ||
49 | unsigned int size, int reason, | ||
50 | struct tipc_portid const *attmpt_destid); | ||
51 | |||
52 | typedef void (*tipc_named_msg_err_event) (void *usr_handle, u32 portref, | ||
53 | struct sk_buff **buf, unsigned char const *data, | ||
54 | unsigned int size, int reason, | ||
55 | struct tipc_name_seq const *attmpt_dest); | ||
56 | |||
57 | typedef void (*tipc_conn_shutdown_event) (void *usr_handle, u32 portref, | ||
58 | struct sk_buff **buf, unsigned char const *data, | ||
59 | unsigned int size, int reason); | ||
60 | |||
61 | typedef void (*tipc_msg_event) (void *usr_handle, u32 portref, | ||
62 | struct sk_buff **buf, unsigned char const *data, | ||
63 | unsigned int size, unsigned int importance, | ||
64 | struct tipc_portid const *origin); | ||
65 | |||
66 | typedef void (*tipc_named_msg_event) (void *usr_handle, u32 portref, | ||
67 | struct sk_buff **buf, unsigned char const *data, | ||
68 | unsigned int size, unsigned int importance, | ||
69 | struct tipc_portid const *orig, | ||
70 | struct tipc_name_seq const *dest); | ||
71 | |||
72 | typedef void (*tipc_conn_msg_event) (void *usr_handle, u32 portref, | ||
73 | struct sk_buff **buf, unsigned char const *data, | ||
74 | unsigned int size); | ||
75 | |||
76 | typedef void (*tipc_continue_event) (void *usr_handle, u32 portref); | ||
77 | |||
47 | /** | 78 | /** |
48 | * struct user_port - TIPC user port (used with native API) | 79 | * struct user_port - TIPC user port (used with native API) |
49 | * @user_ref: id of user who created user port | ||
50 | * @usr_handle: user-specified field | 80 | * @usr_handle: user-specified field |
51 | * @ref: object reference to associated TIPC port | 81 | * @ref: object reference to associated TIPC port |
52 | * <various callback routines> | 82 | * <various callback routines> |
53 | * @uport_list: adjacent user ports in list of ports held by user | ||
54 | */ | 83 | */ |
55 | 84 | ||
56 | struct user_port { | 85 | struct user_port { |
57 | u32 user_ref; | ||
58 | void *usr_handle; | 86 | void *usr_handle; |
59 | u32 ref; | 87 | u32 ref; |
60 | tipc_msg_err_event err_cb; | 88 | tipc_msg_err_event err_cb; |
@@ -64,7 +92,34 @@ struct user_port { | |||
64 | tipc_named_msg_event named_msg_cb; | 92 | tipc_named_msg_event named_msg_cb; |
65 | tipc_conn_msg_event conn_msg_cb; | 93 | tipc_conn_msg_event conn_msg_cb; |
66 | tipc_continue_event continue_event_cb; | 94 | tipc_continue_event continue_event_cb; |
67 | struct list_head uport_list; | 95 | }; |
96 | |||
97 | /** | ||
98 | * struct tipc_port - TIPC port info available to socket API | ||
99 | * @usr_handle: pointer to additional user-defined information about port | ||
100 | * @lock: pointer to spinlock for controlling access to port | ||
101 | * @connected: non-zero if port is currently connected to a peer port | ||
102 | * @conn_type: TIPC type used when connection was established | ||
103 | * @conn_instance: TIPC instance used when connection was established | ||
104 | * @conn_unacked: number of unacknowledged messages received from peer port | ||
105 | * @published: non-zero if port has one or more associated names | ||
106 | * @congested: non-zero if cannot send because of link or port congestion | ||
107 | * @max_pkt: maximum packet size "hint" used when building messages sent by port | ||
108 | * @ref: unique reference to port in TIPC object registry | ||
109 | * @phdr: preformatted message header used when sending messages | ||
110 | */ | ||
111 | struct tipc_port { | ||
112 | void *usr_handle; | ||
113 | spinlock_t *lock; | ||
114 | int connected; | ||
115 | u32 conn_type; | ||
116 | u32 conn_instance; | ||
117 | u32 conn_unacked; | ||
118 | int published; | ||
119 | u32 congested; | ||
120 | u32 max_pkt; | ||
121 | u32 ref; | ||
122 | struct tipc_msg phdr; | ||
68 | }; | 123 | }; |
69 | 124 | ||
70 | /** | 125 | /** |
@@ -109,11 +164,76 @@ struct port { | |||
109 | extern spinlock_t tipc_port_list_lock; | 164 | extern spinlock_t tipc_port_list_lock; |
110 | struct port_list; | 165 | struct port_list; |
111 | 166 | ||
167 | /* | ||
168 | * TIPC port manipulation routines | ||
169 | */ | ||
170 | struct tipc_port *tipc_createport_raw(void *usr_handle, | ||
171 | u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), | ||
172 | void (*wakeup)(struct tipc_port *), const u32 importance); | ||
173 | |||
174 | int tipc_reject_msg(struct sk_buff *buf, u32 err); | ||
175 | |||
176 | int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode); | ||
177 | |||
178 | void tipc_acknowledge(u32 port_ref, u32 ack); | ||
179 | |||
180 | int tipc_createport(void *usr_handle, | ||
181 | unsigned int importance, tipc_msg_err_event error_cb, | ||
182 | tipc_named_msg_err_event named_error_cb, | ||
183 | tipc_conn_shutdown_event conn_error_cb, tipc_msg_event msg_cb, | ||
184 | tipc_named_msg_event named_msg_cb, | ||
185 | tipc_conn_msg_event conn_msg_cb, | ||
186 | tipc_continue_event continue_event_cb, u32 *portref); | ||
187 | |||
188 | int tipc_deleteport(u32 portref); | ||
189 | |||
190 | int tipc_portimportance(u32 portref, unsigned int *importance); | ||
191 | int tipc_set_portimportance(u32 portref, unsigned int importance); | ||
192 | |||
193 | int tipc_portunreliable(u32 portref, unsigned int *isunreliable); | ||
194 | int tipc_set_portunreliable(u32 portref, unsigned int isunreliable); | ||
195 | |||
196 | int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable); | ||
197 | int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable); | ||
198 | |||
199 | int tipc_publish(u32 portref, unsigned int scope, | ||
200 | struct tipc_name_seq const *name_seq); | ||
201 | int tipc_withdraw(u32 portref, unsigned int scope, | ||
202 | struct tipc_name_seq const *name_seq); | ||
203 | |||
204 | int tipc_connect2port(u32 portref, struct tipc_portid const *port); | ||
205 | |||
206 | int tipc_disconnect(u32 portref); | ||
207 | |||
208 | int tipc_shutdown(u32 ref); | ||
209 | |||
210 | |||
211 | /* | ||
212 | * The following routines require that the port be locked on entry | ||
213 | */ | ||
214 | int tipc_disconnect_port(struct tipc_port *tp_ptr); | ||
215 | |||
216 | /* | ||
217 | * TIPC messaging routines | ||
218 | */ | ||
219 | int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect); | ||
220 | |||
221 | int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain, | ||
222 | unsigned int num_sect, struct iovec const *msg_sect); | ||
223 | |||
224 | int tipc_send2port(u32 portref, struct tipc_portid const *dest, | ||
225 | unsigned int num_sect, struct iovec const *msg_sect); | ||
226 | |||
227 | int tipc_send_buf2port(u32 portref, struct tipc_portid const *dest, | ||
228 | struct sk_buff *buf, unsigned int dsz); | ||
229 | |||
230 | int tipc_multicast(u32 portref, struct tipc_name_seq const *seq, | ||
231 | unsigned int section_count, struct iovec const *msg); | ||
232 | |||
112 | int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr, | 233 | int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr, |
113 | struct iovec const *msg_sect, u32 num_sect, | 234 | struct iovec const *msg_sect, u32 num_sect, |
114 | int err); | 235 | int err); |
115 | struct sk_buff *tipc_port_get_ports(void); | 236 | struct sk_buff *tipc_port_get_ports(void); |
116 | struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space); | ||
117 | void tipc_port_recv_proto_msg(struct sk_buff *buf); | 237 | void tipc_port_recv_proto_msg(struct sk_buff *buf); |
118 | void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp); | 238 | void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp); |
119 | void tipc_port_reinit(void); | 239 | void tipc_port_reinit(void); |
@@ -138,7 +258,7 @@ static inline void tipc_port_unlock(struct port *p_ptr) | |||
138 | spin_unlock_bh(p_ptr->publ.lock); | 258 | spin_unlock_bh(p_ptr->publ.lock); |
139 | } | 259 | } |
140 | 260 | ||
141 | static inline struct port* tipc_port_deref(u32 ref) | 261 | static inline struct port *tipc_port_deref(u32 ref) |
142 | { | 262 | { |
143 | return (struct port *)tipc_ref_deref(ref); | 263 | return (struct port *)tipc_ref_deref(ref); |
144 | } | 264 | } |
@@ -196,7 +316,6 @@ static inline int tipc_port_recv_msg(struct sk_buff *buf) | |||
196 | err = TIPC_ERR_NO_PORT; | 316 | err = TIPC_ERR_NO_PORT; |
197 | } | 317 | } |
198 | reject: | 318 | reject: |
199 | dbg("port->rejecting, err = %x..\n",err); | ||
200 | return tipc_reject_msg(buf, err); | 319 | return tipc_reject_msg(buf, err); |
201 | } | 320 | } |
202 | 321 | ||
diff --git a/net/tipc/ref.c b/net/tipc/ref.c index ab8ad32d8c20..83116892528b 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c | |||
@@ -89,7 +89,7 @@ struct ref_table { | |||
89 | * have a reference value of 0 (although this is unlikely). | 89 | * have a reference value of 0 (although this is unlikely). |
90 | */ | 90 | */ |
91 | 91 | ||
92 | static struct ref_table tipc_ref_table = { NULL }; | 92 | static struct ref_table tipc_ref_table; |
93 | 93 | ||
94 | static DEFINE_RWLOCK(ref_table_lock); | 94 | static DEFINE_RWLOCK(ref_table_lock); |
95 | 95 | ||
@@ -178,14 +178,12 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) | |||
178 | next_plus_upper = entry->ref; | 178 | next_plus_upper = entry->ref; |
179 | tipc_ref_table.first_free = next_plus_upper & index_mask; | 179 | tipc_ref_table.first_free = next_plus_upper & index_mask; |
180 | ref = (next_plus_upper & ~index_mask) + index; | 180 | ref = (next_plus_upper & ~index_mask) + index; |
181 | } | 181 | } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { |
182 | else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { | ||
183 | index = tipc_ref_table.init_point++; | 182 | index = tipc_ref_table.init_point++; |
184 | entry = &(tipc_ref_table.entries[index]); | 183 | entry = &(tipc_ref_table.entries[index]); |
185 | spin_lock_init(&entry->lock); | 184 | spin_lock_init(&entry->lock); |
186 | ref = tipc_ref_table.start_mask + index; | 185 | ref = tipc_ref_table.start_mask + index; |
187 | } | 186 | } else { |
188 | else { | ||
189 | ref = 0; | 187 | ref = 0; |
190 | } | 188 | } |
191 | write_unlock_bh(&ref_table_lock); | 189 | write_unlock_bh(&ref_table_lock); |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e9f0d5004483..2b02a3a80313 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -34,25 +34,13 @@ | |||
34 | * POSSIBILITY OF SUCH DAMAGE. | 34 | * POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/net.h> | ||
40 | #include <linux/socket.h> | ||
41 | #include <linux/errno.h> | ||
42 | #include <linux/mm.h> | ||
43 | #include <linux/poll.h> | ||
44 | #include <linux/fcntl.h> | ||
45 | #include <linux/gfp.h> | ||
46 | #include <asm/string.h> | ||
47 | #include <asm/atomic.h> | ||
48 | #include <net/sock.h> | 37 | #include <net/sock.h> |
49 | 38 | ||
50 | #include <linux/tipc.h> | 39 | #include <linux/tipc.h> |
51 | #include <linux/tipc_config.h> | 40 | #include <linux/tipc_config.h> |
52 | #include <net/tipc/tipc_msg.h> | ||
53 | #include <net/tipc/tipc_port.h> | ||
54 | 41 | ||
55 | #include "core.h" | 42 | #include "core.h" |
43 | #include "port.h" | ||
56 | 44 | ||
57 | #define SS_LISTENING -1 /* socket is listening */ | 45 | #define SS_LISTENING -1 /* socket is listening */ |
58 | #define SS_READY -2 /* socket is connectionless */ | 46 | #define SS_READY -2 /* socket is connectionless */ |
@@ -80,7 +68,7 @@ static const struct proto_ops msg_ops; | |||
80 | 68 | ||
81 | static struct proto tipc_proto; | 69 | static struct proto tipc_proto; |
82 | 70 | ||
83 | static int sockets_enabled = 0; | 71 | static int sockets_enabled; |
84 | 72 | ||
85 | static atomic_t tipc_queue_size = ATOMIC_INIT(0); | 73 | static atomic_t tipc_queue_size = ATOMIC_INIT(0); |
86 | 74 | ||
@@ -387,7 +375,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) | |||
387 | * | 375 | * |
388 | * NOTE: This routine doesn't need to take the socket lock since it only | 376 | * NOTE: This routine doesn't need to take the socket lock since it only |
389 | * accesses socket information that is unchanging (or which changes in | 377 | * accesses socket information that is unchanging (or which changes in |
390 | * a completely predictable manner). | 378 | * a completely predictable manner). |
391 | */ | 379 | */ |
392 | 380 | ||
393 | static int get_name(struct socket *sock, struct sockaddr *uaddr, | 381 | static int get_name(struct socket *sock, struct sockaddr *uaddr, |
@@ -404,7 +392,8 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr, | |||
404 | addr->addr.id.ref = tsock->peer_name.ref; | 392 | addr->addr.id.ref = tsock->peer_name.ref; |
405 | addr->addr.id.node = tsock->peer_name.node; | 393 | addr->addr.id.node = tsock->peer_name.node; |
406 | } else { | 394 | } else { |
407 | tipc_ownidentity(tsock->p->ref, &addr->addr.id); | 395 | addr->addr.id.ref = tsock->p->ref; |
396 | addr->addr.id.node = tipc_own_addr; | ||
408 | } | 397 | } |
409 | 398 | ||
410 | *uaddr_len = sizeof(*addr); | 399 | *uaddr_len = sizeof(*addr); |
@@ -574,37 +563,35 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, | |||
574 | 563 | ||
575 | do { | 564 | do { |
576 | if (dest->addrtype == TIPC_ADDR_NAME) { | 565 | if (dest->addrtype == TIPC_ADDR_NAME) { |
577 | if ((res = dest_name_check(dest, m))) | 566 | res = dest_name_check(dest, m); |
567 | if (res) | ||
578 | break; | 568 | break; |
579 | res = tipc_send2name(tport->ref, | 569 | res = tipc_send2name(tport->ref, |
580 | &dest->addr.name.name, | 570 | &dest->addr.name.name, |
581 | dest->addr.name.domain, | 571 | dest->addr.name.domain, |
582 | m->msg_iovlen, | 572 | m->msg_iovlen, |
583 | m->msg_iov); | 573 | m->msg_iov); |
584 | } | 574 | } else if (dest->addrtype == TIPC_ADDR_ID) { |
585 | else if (dest->addrtype == TIPC_ADDR_ID) { | ||
586 | res = tipc_send2port(tport->ref, | 575 | res = tipc_send2port(tport->ref, |
587 | &dest->addr.id, | 576 | &dest->addr.id, |
588 | m->msg_iovlen, | 577 | m->msg_iovlen, |
589 | m->msg_iov); | 578 | m->msg_iov); |
590 | } | 579 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { |
591 | else if (dest->addrtype == TIPC_ADDR_MCAST) { | ||
592 | if (needs_conn) { | 580 | if (needs_conn) { |
593 | res = -EOPNOTSUPP; | 581 | res = -EOPNOTSUPP; |
594 | break; | 582 | break; |
595 | } | 583 | } |
596 | if ((res = dest_name_check(dest, m))) | 584 | res = dest_name_check(dest, m); |
585 | if (res) | ||
597 | break; | 586 | break; |
598 | res = tipc_multicast(tport->ref, | 587 | res = tipc_multicast(tport->ref, |
599 | &dest->addr.nameseq, | 588 | &dest->addr.nameseq, |
600 | 0, | ||
601 | m->msg_iovlen, | 589 | m->msg_iovlen, |
602 | m->msg_iov); | 590 | m->msg_iov); |
603 | } | 591 | } |
604 | if (likely(res != -ELINKCONG)) { | 592 | if (likely(res != -ELINKCONG)) { |
605 | if (needs_conn && (res >= 0)) { | 593 | if (needs_conn && (res >= 0)) |
606 | sock->state = SS_CONNECTING; | 594 | sock->state = SS_CONNECTING; |
607 | } | ||
608 | break; | 595 | break; |
609 | } | 596 | } |
610 | if (m->msg_flags & MSG_DONTWAIT) { | 597 | if (m->msg_flags & MSG_DONTWAIT) { |
@@ -663,9 +650,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, | |||
663 | } | 650 | } |
664 | 651 | ||
665 | res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov); | 652 | res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov); |
666 | if (likely(res != -ELINKCONG)) { | 653 | if (likely(res != -ELINKCONG)) |
667 | break; | 654 | break; |
668 | } | ||
669 | if (m->msg_flags & MSG_DONTWAIT) { | 655 | if (m->msg_flags & MSG_DONTWAIT) { |
670 | res = -EWOULDBLOCK; | 656 | res = -EWOULDBLOCK; |
671 | break; | 657 | break; |
@@ -764,7 +750,8 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, | |||
764 | bytes_to_send = curr_left; | 750 | bytes_to_send = curr_left; |
765 | my_iov.iov_base = curr_start; | 751 | my_iov.iov_base = curr_start; |
766 | my_iov.iov_len = bytes_to_send; | 752 | my_iov.iov_len = bytes_to_send; |
767 | if ((res = send_packet(NULL, sock, &my_msg, 0)) < 0) { | 753 | res = send_packet(NULL, sock, &my_msg, 0); |
754 | if (res < 0) { | ||
768 | if (bytes_sent) | 755 | if (bytes_sent) |
769 | res = bytes_sent; | 756 | res = bytes_sent; |
770 | goto exit; | 757 | goto exit; |
@@ -824,8 +811,8 @@ static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | |||
824 | addr->addrtype = TIPC_ADDR_ID; | 811 | addr->addrtype = TIPC_ADDR_ID; |
825 | addr->addr.id.ref = msg_origport(msg); | 812 | addr->addr.id.ref = msg_origport(msg); |
826 | addr->addr.id.node = msg_orignode(msg); | 813 | addr->addr.id.node = msg_orignode(msg); |
827 | addr->addr.name.domain = 0; /* could leave uninitialized */ | 814 | addr->addr.name.domain = 0; /* could leave uninitialized */ |
828 | addr->scope = 0; /* could leave uninitialized */ | 815 | addr->scope = 0; /* could leave uninitialized */ |
829 | m->msg_namelen = sizeof(struct sockaddr_tipc); | 816 | m->msg_namelen = sizeof(struct sockaddr_tipc); |
830 | } | 817 | } |
831 | } | 818 | } |
@@ -859,12 +846,15 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | |||
859 | if (unlikely(err)) { | 846 | if (unlikely(err)) { |
860 | anc_data[0] = err; | 847 | anc_data[0] = err; |
861 | anc_data[1] = msg_data_sz(msg); | 848 | anc_data[1] = msg_data_sz(msg); |
862 | if ((res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data))) | 849 | res = put_cmsg(m, SOL_TIPC, TIPC_ERRINFO, 8, anc_data); |
863 | return res; | 850 | if (res) |
864 | if (anc_data[1] && | ||
865 | (res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1], | ||
866 | msg_data(msg)))) | ||
867 | return res; | 851 | return res; |
852 | if (anc_data[1]) { | ||
853 | res = put_cmsg(m, SOL_TIPC, TIPC_RETDATA, anc_data[1], | ||
854 | msg_data(msg)); | ||
855 | if (res) | ||
856 | return res; | ||
857 | } | ||
868 | } | 858 | } |
869 | 859 | ||
870 | /* Optionally capture message destination object */ | 860 | /* Optionally capture message destination object */ |
@@ -892,9 +882,11 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | |||
892 | default: | 882 | default: |
893 | has_name = 0; | 883 | has_name = 0; |
894 | } | 884 | } |
895 | if (has_name && | 885 | if (has_name) { |
896 | (res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data))) | 886 | res = put_cmsg(m, SOL_TIPC, TIPC_DESTNAME, 12, anc_data); |
897 | return res; | 887 | if (res) |
888 | return res; | ||
889 | } | ||
898 | 890 | ||
899 | return 0; | 891 | return 0; |
900 | } | 892 | } |
@@ -1227,42 +1219,25 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
1227 | */ | 1219 | */ |
1228 | 1220 | ||
1229 | if (sock->state == SS_READY) { | 1221 | if (sock->state == SS_READY) { |
1230 | if (msg_connected(msg)) { | 1222 | if (msg_connected(msg)) |
1231 | msg_dbg(msg, "dispatch filter 1\n"); | ||
1232 | return TIPC_ERR_NO_PORT; | 1223 | return TIPC_ERR_NO_PORT; |
1233 | } | ||
1234 | } else { | 1224 | } else { |
1235 | if (msg_mcast(msg)) { | 1225 | if (msg_mcast(msg)) |
1236 | msg_dbg(msg, "dispatch filter 2\n"); | ||
1237 | return TIPC_ERR_NO_PORT; | 1226 | return TIPC_ERR_NO_PORT; |
1238 | } | ||
1239 | if (sock->state == SS_CONNECTED) { | 1227 | if (sock->state == SS_CONNECTED) { |
1240 | if (!msg_connected(msg)) { | 1228 | if (!msg_connected(msg)) |
1241 | msg_dbg(msg, "dispatch filter 3\n"); | ||
1242 | return TIPC_ERR_NO_PORT; | 1229 | return TIPC_ERR_NO_PORT; |
1243 | } | 1230 | } else if (sock->state == SS_CONNECTING) { |
1244 | } | 1231 | if (!msg_connected(msg) && (msg_errcode(msg) == 0)) |
1245 | else if (sock->state == SS_CONNECTING) { | ||
1246 | if (!msg_connected(msg) && (msg_errcode(msg) == 0)) { | ||
1247 | msg_dbg(msg, "dispatch filter 4\n"); | ||
1248 | return TIPC_ERR_NO_PORT; | 1232 | return TIPC_ERR_NO_PORT; |
1249 | } | 1233 | } else if (sock->state == SS_LISTENING) { |
1250 | } | 1234 | if (msg_connected(msg) || msg_errcode(msg)) |
1251 | else if (sock->state == SS_LISTENING) { | ||
1252 | if (msg_connected(msg) || msg_errcode(msg)) { | ||
1253 | msg_dbg(msg, "dispatch filter 5\n"); | ||
1254 | return TIPC_ERR_NO_PORT; | 1235 | return TIPC_ERR_NO_PORT; |
1255 | } | 1236 | } else if (sock->state == SS_DISCONNECTING) { |
1256 | } | ||
1257 | else if (sock->state == SS_DISCONNECTING) { | ||
1258 | msg_dbg(msg, "dispatch filter 6\n"); | ||
1259 | return TIPC_ERR_NO_PORT; | 1237 | return TIPC_ERR_NO_PORT; |
1260 | } | 1238 | } else /* (sock->state == SS_UNCONNECTED) */ { |
1261 | else /* (sock->state == SS_UNCONNECTED) */ { | 1239 | if (msg_connected(msg) || msg_errcode(msg)) |
1262 | if (msg_connected(msg) || msg_errcode(msg)) { | ||
1263 | msg_dbg(msg, "dispatch filter 7\n"); | ||
1264 | return TIPC_ERR_NO_PORT; | 1240 | return TIPC_ERR_NO_PORT; |
1265 | } | ||
1266 | } | 1241 | } |
1267 | } | 1242 | } |
1268 | 1243 | ||
@@ -1281,7 +1256,6 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
1281 | 1256 | ||
1282 | /* Enqueue message (finally!) */ | 1257 | /* Enqueue message (finally!) */ |
1283 | 1258 | ||
1284 | msg_dbg(msg, "<DISP<: "); | ||
1285 | TIPC_SKB_CB(buf)->handle = msg_data(msg); | 1259 | TIPC_SKB_CB(buf)->handle = msg_data(msg); |
1286 | atomic_inc(&tipc_queue_size); | 1260 | atomic_inc(&tipc_queue_size); |
1287 | __skb_queue_tail(&sk->sk_receive_queue, buf); | 1261 | __skb_queue_tail(&sk->sk_receive_queue, buf); |
@@ -1442,9 +1416,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1442 | m.msg_name = dest; | 1416 | m.msg_name = dest; |
1443 | m.msg_namelen = destlen; | 1417 | m.msg_namelen = destlen; |
1444 | res = send_msg(NULL, sock, &m, 0); | 1418 | res = send_msg(NULL, sock, &m, 0); |
1445 | if (res < 0) { | 1419 | if (res < 0) |
1446 | goto exit; | 1420 | goto exit; |
1447 | } | ||
1448 | 1421 | ||
1449 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ | 1422 | /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ |
1450 | 1423 | ||
@@ -1466,11 +1439,10 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1466 | advance_rx_queue(sk); | 1439 | advance_rx_queue(sk); |
1467 | } | 1440 | } |
1468 | } else { | 1441 | } else { |
1469 | if (sock->state == SS_CONNECTED) { | 1442 | if (sock->state == SS_CONNECTED) |
1470 | res = -EISCONN; | 1443 | res = -EISCONN; |
1471 | } else { | 1444 | else |
1472 | res = -ECONNREFUSED; | 1445 | res = -ECONNREFUSED; |
1473 | } | ||
1474 | } | 1446 | } |
1475 | } else { | 1447 | } else { |
1476 | if (res == 0) | 1448 | if (res == 0) |
@@ -1589,7 +1561,6 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) | |||
1589 | * Respond to 'SYN+' by queuing it on new socket. | 1561 | * Respond to 'SYN+' by queuing it on new socket. |
1590 | */ | 1562 | */ |
1591 | 1563 | ||
1592 | msg_dbg(msg,"<ACC<: "); | ||
1593 | if (!msg_data_sz(msg)) { | 1564 | if (!msg_data_sz(msg)) { |
1594 | struct msghdr m = {NULL,}; | 1565 | struct msghdr m = {NULL,}; |
1595 | 1566 | ||
@@ -1697,7 +1668,8 @@ static int setsockopt(struct socket *sock, | |||
1697 | return -ENOPROTOOPT; | 1668 | return -ENOPROTOOPT; |
1698 | if (ol < sizeof(value)) | 1669 | if (ol < sizeof(value)) |
1699 | return -EINVAL; | 1670 | return -EINVAL; |
1700 | if ((res = get_user(value, (u32 __user *)ov))) | 1671 | res = get_user(value, (u32 __user *)ov); |
1672 | if (res) | ||
1701 | return res; | 1673 | return res; |
1702 | 1674 | ||
1703 | lock_sock(sk); | 1675 | lock_sock(sk); |
@@ -1755,7 +1727,8 @@ static int getsockopt(struct socket *sock, | |||
1755 | return put_user(0, ol); | 1727 | return put_user(0, ol); |
1756 | if (lvl != SOL_TIPC) | 1728 | if (lvl != SOL_TIPC) |
1757 | return -ENOPROTOOPT; | 1729 | return -ENOPROTOOPT; |
1758 | if ((res = get_user(len, ol))) | 1730 | res = get_user(len, ol); |
1731 | if (res) | ||
1759 | return res; | 1732 | return res; |
1760 | 1733 | ||
1761 | lock_sock(sk); | 1734 | lock_sock(sk); |
@@ -1774,10 +1747,10 @@ static int getsockopt(struct socket *sock, | |||
1774 | value = jiffies_to_msecs(tipc_sk(sk)->conn_timeout); | 1747 | value = jiffies_to_msecs(tipc_sk(sk)->conn_timeout); |
1775 | /* no need to set "res", since already 0 at this point */ | 1748 | /* no need to set "res", since already 0 at this point */ |
1776 | break; | 1749 | break; |
1777 | case TIPC_NODE_RECVQ_DEPTH: | 1750 | case TIPC_NODE_RECVQ_DEPTH: |
1778 | value = (u32)atomic_read(&tipc_queue_size); | 1751 | value = (u32)atomic_read(&tipc_queue_size); |
1779 | break; | 1752 | break; |
1780 | case TIPC_SOCK_RECVQ_DEPTH: | 1753 | case TIPC_SOCK_RECVQ_DEPTH: |
1781 | value = skb_queue_len(&sk->sk_receive_queue); | 1754 | value = skb_queue_len(&sk->sk_receive_queue); |
1782 | break; | 1755 | break; |
1783 | default: | 1756 | default: |
@@ -1786,20 +1759,16 @@ static int getsockopt(struct socket *sock, | |||
1786 | 1759 | ||
1787 | release_sock(sk); | 1760 | release_sock(sk); |
1788 | 1761 | ||
1789 | if (res) { | 1762 | if (res) |
1790 | /* "get" failed */ | 1763 | return res; /* "get" failed */ |
1791 | } | ||
1792 | else if (len < sizeof(value)) { | ||
1793 | res = -EINVAL; | ||
1794 | } | ||
1795 | else if (copy_to_user(ov, &value, sizeof(value))) { | ||
1796 | res = -EFAULT; | ||
1797 | } | ||
1798 | else { | ||
1799 | res = put_user(sizeof(value), ol); | ||
1800 | } | ||
1801 | 1764 | ||
1802 | return res; | 1765 | if (len < sizeof(value)) |
1766 | return -EINVAL; | ||
1767 | |||
1768 | if (copy_to_user(ov, &value, sizeof(value))) | ||
1769 | return -EFAULT; | ||
1770 | |||
1771 | return put_user(sizeof(value), ol); | ||
1803 | } | 1772 | } |
1804 | 1773 | ||
1805 | /** | 1774 | /** |
@@ -1807,7 +1776,7 @@ static int getsockopt(struct socket *sock, | |||
1807 | */ | 1776 | */ |
1808 | 1777 | ||
1809 | static const struct proto_ops msg_ops = { | 1778 | static const struct proto_ops msg_ops = { |
1810 | .owner = THIS_MODULE, | 1779 | .owner = THIS_MODULE, |
1811 | .family = AF_TIPC, | 1780 | .family = AF_TIPC, |
1812 | .release = release, | 1781 | .release = release, |
1813 | .bind = bind, | 1782 | .bind = bind, |
@@ -1828,7 +1797,7 @@ static const struct proto_ops msg_ops = { | |||
1828 | }; | 1797 | }; |
1829 | 1798 | ||
1830 | static const struct proto_ops packet_ops = { | 1799 | static const struct proto_ops packet_ops = { |
1831 | .owner = THIS_MODULE, | 1800 | .owner = THIS_MODULE, |
1832 | .family = AF_TIPC, | 1801 | .family = AF_TIPC, |
1833 | .release = release, | 1802 | .release = release, |
1834 | .bind = bind, | 1803 | .bind = bind, |
@@ -1849,7 +1818,7 @@ static const struct proto_ops packet_ops = { | |||
1849 | }; | 1818 | }; |
1850 | 1819 | ||
1851 | static const struct proto_ops stream_ops = { | 1820 | static const struct proto_ops stream_ops = { |
1852 | .owner = THIS_MODULE, | 1821 | .owner = THIS_MODULE, |
1853 | .family = AF_TIPC, | 1822 | .family = AF_TIPC, |
1854 | .release = release, | 1823 | .release = release, |
1855 | .bind = bind, | 1824 | .bind = bind, |
@@ -1870,7 +1839,7 @@ static const struct proto_ops stream_ops = { | |||
1870 | }; | 1839 | }; |
1871 | 1840 | ||
1872 | static const struct net_proto_family tipc_family_ops = { | 1841 | static const struct net_proto_family tipc_family_ops = { |
1873 | .owner = THIS_MODULE, | 1842 | .owner = THIS_MODULE, |
1874 | .family = AF_TIPC, | 1843 | .family = AF_TIPC, |
1875 | .create = tipc_create | 1844 | .create = tipc_create |
1876 | }; | 1845 | }; |
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 33313961d010..ca04479c3d42 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
@@ -35,10 +35,8 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "dbg.h" | ||
39 | #include "name_table.h" | 38 | #include "name_table.h" |
40 | #include "port.h" | 39 | #include "port.h" |
41 | #include "ref.h" | ||
42 | #include "subscr.h" | 40 | #include "subscr.h" |
43 | 41 | ||
44 | /** | 42 | /** |
@@ -66,14 +64,13 @@ struct subscriber { | |||
66 | */ | 64 | */ |
67 | 65 | ||
68 | struct top_srv { | 66 | struct top_srv { |
69 | u32 user_ref; | ||
70 | u32 setup_port; | 67 | u32 setup_port; |
71 | atomic_t subscription_count; | 68 | atomic_t subscription_count; |
72 | struct list_head subscriber_list; | 69 | struct list_head subscriber_list; |
73 | spinlock_t lock; | 70 | spinlock_t lock; |
74 | }; | 71 | }; |
75 | 72 | ||
76 | static struct top_srv topsrv = { 0 }; | 73 | static struct top_srv topsrv; |
77 | 74 | ||
78 | /** | 75 | /** |
79 | * htohl - convert value to endianness used by destination | 76 | * htohl - convert value to endianness used by destination |
@@ -252,8 +249,6 @@ static void subscr_terminate(struct subscriber *subscriber) | |||
252 | k_cancel_timer(&sub->timer); | 249 | k_cancel_timer(&sub->timer); |
253 | k_term_timer(&sub->timer); | 250 | k_term_timer(&sub->timer); |
254 | } | 251 | } |
255 | dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n", | ||
256 | sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber); | ||
257 | subscr_del(sub); | 252 | subscr_del(sub); |
258 | } | 253 | } |
259 | 254 | ||
@@ -310,8 +305,6 @@ static void subscr_cancel(struct tipc_subscr *s, | |||
310 | k_term_timer(&sub->timer); | 305 | k_term_timer(&sub->timer); |
311 | spin_lock_bh(subscriber->lock); | 306 | spin_lock_bh(subscriber->lock); |
312 | } | 307 | } |
313 | dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n", | ||
314 | sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber); | ||
315 | subscr_del(sub); | 308 | subscr_del(sub); |
316 | } | 309 | } |
317 | 310 | ||
@@ -496,8 +489,7 @@ static void subscr_named_msg_event(void *usr_handle, | |||
496 | 489 | ||
497 | /* Create server port & establish connection to subscriber */ | 490 | /* Create server port & establish connection to subscriber */ |
498 | 491 | ||
499 | tipc_createport(topsrv.user_ref, | 492 | tipc_createport(subscriber, |
500 | subscriber, | ||
501 | importance, | 493 | importance, |
502 | NULL, | 494 | NULL, |
503 | NULL, | 495 | NULL, |
@@ -544,21 +536,14 @@ static void subscr_named_msg_event(void *usr_handle, | |||
544 | int tipc_subscr_start(void) | 536 | int tipc_subscr_start(void) |
545 | { | 537 | { |
546 | struct tipc_name_seq seq = {TIPC_TOP_SRV, TIPC_TOP_SRV, TIPC_TOP_SRV}; | 538 | struct tipc_name_seq seq = {TIPC_TOP_SRV, TIPC_TOP_SRV, TIPC_TOP_SRV}; |
547 | int res = -1; | 539 | int res; |
548 | 540 | ||
549 | memset(&topsrv, 0, sizeof (topsrv)); | 541 | memset(&topsrv, 0, sizeof(topsrv)); |
550 | spin_lock_init(&topsrv.lock); | 542 | spin_lock_init(&topsrv.lock); |
551 | INIT_LIST_HEAD(&topsrv.subscriber_list); | 543 | INIT_LIST_HEAD(&topsrv.subscriber_list); |
552 | 544 | ||
553 | spin_lock_bh(&topsrv.lock); | 545 | spin_lock_bh(&topsrv.lock); |
554 | res = tipc_attach(&topsrv.user_ref, NULL, NULL); | 546 | res = tipc_createport(NULL, |
555 | if (res) { | ||
556 | spin_unlock_bh(&topsrv.lock); | ||
557 | return res; | ||
558 | } | ||
559 | |||
560 | res = tipc_createport(topsrv.user_ref, | ||
561 | NULL, | ||
562 | TIPC_CRITICAL_IMPORTANCE, | 547 | TIPC_CRITICAL_IMPORTANCE, |
563 | NULL, | 548 | NULL, |
564 | NULL, | 549 | NULL, |
@@ -572,16 +557,17 @@ int tipc_subscr_start(void) | |||
572 | goto failed; | 557 | goto failed; |
573 | 558 | ||
574 | res = tipc_nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq); | 559 | res = tipc_nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq); |
575 | if (res) | 560 | if (res) { |
561 | tipc_deleteport(topsrv.setup_port); | ||
562 | topsrv.setup_port = 0; | ||
576 | goto failed; | 563 | goto failed; |
564 | } | ||
577 | 565 | ||
578 | spin_unlock_bh(&topsrv.lock); | 566 | spin_unlock_bh(&topsrv.lock); |
579 | return 0; | 567 | return 0; |
580 | 568 | ||
581 | failed: | 569 | failed: |
582 | err("Failed to create subscription service\n"); | 570 | err("Failed to create subscription service\n"); |
583 | tipc_detach(topsrv.user_ref); | ||
584 | topsrv.user_ref = 0; | ||
585 | spin_unlock_bh(&topsrv.lock); | 571 | spin_unlock_bh(&topsrv.lock); |
586 | return res; | 572 | return res; |
587 | } | 573 | } |
@@ -592,8 +578,10 @@ void tipc_subscr_stop(void) | |||
592 | struct subscriber *subscriber_temp; | 578 | struct subscriber *subscriber_temp; |
593 | spinlock_t *subscriber_lock; | 579 | spinlock_t *subscriber_lock; |
594 | 580 | ||
595 | if (topsrv.user_ref) { | 581 | if (topsrv.setup_port) { |
596 | tipc_deleteport(topsrv.setup_port); | 582 | tipc_deleteport(topsrv.setup_port); |
583 | topsrv.setup_port = 0; | ||
584 | |||
597 | list_for_each_entry_safe(subscriber, subscriber_temp, | 585 | list_for_each_entry_safe(subscriber, subscriber_temp, |
598 | &topsrv.subscriber_list, | 586 | &topsrv.subscriber_list, |
599 | subscriber_list) { | 587 | subscriber_list) { |
@@ -602,7 +590,5 @@ void tipc_subscr_stop(void) | |||
602 | subscr_terminate(subscriber); | 590 | subscr_terminate(subscriber); |
603 | spin_unlock_bh(subscriber_lock); | 591 | spin_unlock_bh(subscriber_lock); |
604 | } | 592 | } |
605 | tipc_detach(topsrv.user_ref); | ||
606 | topsrv.user_ref = 0; | ||
607 | } | 593 | } |
608 | } | 594 | } |
diff --git a/net/tipc/user_reg.c b/net/tipc/user_reg.c deleted file mode 100644 index 506928803162..000000000000 --- a/net/tipc/user_reg.c +++ /dev/null | |||
@@ -1,264 +0,0 @@ | |||
1 | /* | ||
2 | * net/tipc/user_reg.c: TIPC user registry code | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2004-2005, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #include "core.h" | ||
38 | #include "user_reg.h" | ||
39 | |||
40 | /* | ||
41 | * TIPC user registry keeps track of users of the tipc_port interface. | ||
42 | * | ||
43 | * The registry utilizes an array of "TIPC user" entries; | ||
44 | * a user's ID is the index of their associated array entry. | ||
45 | * Array entry 0 is not used, so userid 0 is not valid; | ||
46 | * TIPC sometimes uses this value to denote an anonymous user. | ||
47 | * The list of free entries is initially chained from last entry to entry 1. | ||
48 | */ | ||
49 | |||
50 | /** | ||
51 | * struct tipc_user - registered TIPC user info | ||
52 | * @next: index of next free registry entry (or -1 for an allocated entry) | ||
53 | * @callback: ptr to routine to call when TIPC mode changes (NULL if none) | ||
54 | * @usr_handle: user-defined value passed to callback routine | ||
55 | * @ports: list of user ports owned by the user | ||
56 | */ | ||
57 | |||
58 | struct tipc_user { | ||
59 | int next; | ||
60 | tipc_mode_event callback; | ||
61 | void *usr_handle; | ||
62 | struct list_head ports; | ||
63 | }; | ||
64 | |||
65 | #define MAX_USERID 64 | ||
66 | #define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user)) | ||
67 | |||
68 | static struct tipc_user *users = NULL; | ||
69 | static u32 next_free_user = MAX_USERID + 1; | ||
70 | static DEFINE_SPINLOCK(reg_lock); | ||
71 | |||
72 | /** | ||
73 | * reg_init - create TIPC user registry (but don't activate it) | ||
74 | * | ||
75 | * If registry has been pre-initialized it is left "as is". | ||
76 | * NOTE: This routine may be called when TIPC is inactive. | ||
77 | */ | ||
78 | |||
79 | static int reg_init(void) | ||
80 | { | ||
81 | u32 i; | ||
82 | |||
83 | spin_lock_bh(®_lock); | ||
84 | if (!users) { | ||
85 | users = kzalloc(USER_LIST_SIZE, GFP_ATOMIC); | ||
86 | if (users) { | ||
87 | for (i = 1; i <= MAX_USERID; i++) { | ||
88 | users[i].next = i - 1; | ||
89 | } | ||
90 | next_free_user = MAX_USERID; | ||
91 | } | ||
92 | } | ||
93 | spin_unlock_bh(®_lock); | ||
94 | return users ? 0 : -ENOMEM; | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * reg_callback - inform TIPC user about current operating mode | ||
99 | */ | ||
100 | |||
101 | static void reg_callback(struct tipc_user *user_ptr) | ||
102 | { | ||
103 | tipc_mode_event cb; | ||
104 | void *arg; | ||
105 | |||
106 | spin_lock_bh(®_lock); | ||
107 | cb = user_ptr->callback; | ||
108 | arg = user_ptr->usr_handle; | ||
109 | spin_unlock_bh(®_lock); | ||
110 | |||
111 | if (cb) | ||
112 | cb(arg, tipc_mode, tipc_own_addr); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * tipc_reg_start - activate TIPC user registry | ||
117 | */ | ||
118 | |||
119 | int tipc_reg_start(void) | ||
120 | { | ||
121 | u32 u; | ||
122 | int res; | ||
123 | |||
124 | if ((res = reg_init())) | ||
125 | return res; | ||
126 | |||
127 | for (u = 1; u <= MAX_USERID; u++) { | ||
128 | if (users[u].callback) | ||
129 | tipc_k_signal((Handler)reg_callback, | ||
130 | (unsigned long)&users[u]); | ||
131 | } | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * tipc_reg_stop - shut down & delete TIPC user registry | ||
137 | */ | ||
138 | |||
139 | void tipc_reg_stop(void) | ||
140 | { | ||
141 | int id; | ||
142 | |||
143 | if (!users) | ||
144 | return; | ||
145 | |||
146 | for (id = 1; id <= MAX_USERID; id++) { | ||
147 | if (users[id].callback) | ||
148 | reg_callback(&users[id]); | ||
149 | } | ||
150 | kfree(users); | ||
151 | users = NULL; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * tipc_attach - register a TIPC user | ||
156 | * | ||
157 | * NOTE: This routine may be called when TIPC is inactive. | ||
158 | */ | ||
159 | |||
160 | int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle) | ||
161 | { | ||
162 | struct tipc_user *user_ptr; | ||
163 | |||
164 | if ((tipc_mode == TIPC_NOT_RUNNING) && !cb) | ||
165 | return -ENOPROTOOPT; | ||
166 | if (!users) | ||
167 | reg_init(); | ||
168 | |||
169 | spin_lock_bh(®_lock); | ||
170 | if (!next_free_user) { | ||
171 | spin_unlock_bh(®_lock); | ||
172 | return -EBUSY; | ||
173 | } | ||
174 | user_ptr = &users[next_free_user]; | ||
175 | *userid = next_free_user; | ||
176 | next_free_user = user_ptr->next; | ||
177 | user_ptr->next = -1; | ||
178 | spin_unlock_bh(®_lock); | ||
179 | |||
180 | user_ptr->callback = cb; | ||
181 | user_ptr->usr_handle = usr_handle; | ||
182 | INIT_LIST_HEAD(&user_ptr->ports); | ||
183 | atomic_inc(&tipc_user_count); | ||
184 | |||
185 | if (cb && (tipc_mode != TIPC_NOT_RUNNING)) | ||
186 | tipc_k_signal((Handler)reg_callback, (unsigned long)user_ptr); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * tipc_detach - deregister a TIPC user | ||
192 | */ | ||
193 | |||
194 | void tipc_detach(u32 userid) | ||
195 | { | ||
196 | struct tipc_user *user_ptr; | ||
197 | struct list_head ports_temp; | ||
198 | struct user_port *up_ptr, *temp_up_ptr; | ||
199 | |||
200 | if ((userid == 0) || (userid > MAX_USERID)) | ||
201 | return; | ||
202 | |||
203 | spin_lock_bh(®_lock); | ||
204 | if ((!users) || (users[userid].next >= 0)) { | ||
205 | spin_unlock_bh(®_lock); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | user_ptr = &users[userid]; | ||
210 | user_ptr->callback = NULL; | ||
211 | INIT_LIST_HEAD(&ports_temp); | ||
212 | list_splice(&user_ptr->ports, &ports_temp); | ||
213 | user_ptr->next = next_free_user; | ||
214 | next_free_user = userid; | ||
215 | spin_unlock_bh(®_lock); | ||
216 | |||
217 | atomic_dec(&tipc_user_count); | ||
218 | |||
219 | list_for_each_entry_safe(up_ptr, temp_up_ptr, &ports_temp, uport_list) { | ||
220 | tipc_deleteport(up_ptr->ref); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * tipc_reg_add_port - register a user's driver port | ||
226 | */ | ||
227 | |||
228 | int tipc_reg_add_port(struct user_port *up_ptr) | ||
229 | { | ||
230 | struct tipc_user *user_ptr; | ||
231 | |||
232 | if (up_ptr->user_ref == 0) | ||
233 | return 0; | ||
234 | if (up_ptr->user_ref > MAX_USERID) | ||
235 | return -EINVAL; | ||
236 | if ((tipc_mode == TIPC_NOT_RUNNING) || !users ) | ||
237 | return -ENOPROTOOPT; | ||
238 | |||
239 | spin_lock_bh(®_lock); | ||
240 | user_ptr = &users[up_ptr->user_ref]; | ||
241 | list_add(&up_ptr->uport_list, &user_ptr->ports); | ||
242 | spin_unlock_bh(®_lock); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * tipc_reg_remove_port - deregister a user's driver port | ||
248 | */ | ||
249 | |||
250 | int tipc_reg_remove_port(struct user_port *up_ptr) | ||
251 | { | ||
252 | if (up_ptr->user_ref == 0) | ||
253 | return 0; | ||
254 | if (up_ptr->user_ref > MAX_USERID) | ||
255 | return -EINVAL; | ||
256 | if (!users ) | ||
257 | return -ENOPROTOOPT; | ||
258 | |||
259 | spin_lock_bh(®_lock); | ||
260 | list_del_init(&up_ptr->uport_list); | ||
261 | spin_unlock_bh(®_lock); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
diff --git a/net/tipc/user_reg.h b/net/tipc/user_reg.h deleted file mode 100644 index 81dc12e2882f..000000000000 --- a/net/tipc/user_reg.h +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | /* | ||
2 | * net/tipc/user_reg.h: Include file for TIPC user registry code | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2005, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #ifndef _TIPC_USER_REG_H | ||
38 | #define _TIPC_USER_REG_H | ||
39 | |||
40 | #include "port.h" | ||
41 | |||
42 | int tipc_reg_start(void); | ||
43 | void tipc_reg_stop(void); | ||
44 | |||
45 | int tipc_reg_add_port(struct user_port *up_ptr); | ||
46 | int tipc_reg_remove_port(struct user_port *up_ptr); | ||
47 | |||
48 | #endif | ||
diff --git a/net/tipc/zone.c b/net/tipc/zone.c deleted file mode 100644 index 83f8b5e91fc8..000000000000 --- a/net/tipc/zone.c +++ /dev/null | |||
@@ -1,162 +0,0 @@ | |||
1 | /* | ||
2 | * net/tipc/zone.c: TIPC zone management routines | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2005, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #include "core.h" | ||
38 | #include "zone.h" | ||
39 | #include "net.h" | ||
40 | #include "addr.h" | ||
41 | #include "node_subscr.h" | ||
42 | #include "cluster.h" | ||
43 | #include "node.h" | ||
44 | |||
45 | struct _zone *tipc_zone_create(u32 addr) | ||
46 | { | ||
47 | struct _zone *z_ptr; | ||
48 | u32 z_num; | ||
49 | |||
50 | if (!tipc_addr_domain_valid(addr)) { | ||
51 | err("Zone creation failed, invalid domain 0x%x\n", addr); | ||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | z_ptr = kzalloc(sizeof(*z_ptr), GFP_ATOMIC); | ||
56 | if (!z_ptr) { | ||
57 | warn("Zone creation failed, insufficient memory\n"); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
61 | z_num = tipc_zone(addr); | ||
62 | z_ptr->addr = tipc_addr(z_num, 0, 0); | ||
63 | tipc_net.zones[z_num] = z_ptr; | ||
64 | return z_ptr; | ||
65 | } | ||
66 | |||
67 | void tipc_zone_delete(struct _zone *z_ptr) | ||
68 | { | ||
69 | u32 c_num; | ||
70 | |||
71 | if (!z_ptr) | ||
72 | return; | ||
73 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { | ||
74 | tipc_cltr_delete(z_ptr->clusters[c_num]); | ||
75 | } | ||
76 | kfree(z_ptr); | ||
77 | } | ||
78 | |||
79 | void tipc_zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr) | ||
80 | { | ||
81 | u32 c_num = tipc_cluster(c_ptr->addr); | ||
82 | |||
83 | assert(c_ptr->addr); | ||
84 | assert(c_num <= tipc_max_clusters); | ||
85 | assert(z_ptr->clusters[c_num] == NULL); | ||
86 | z_ptr->clusters[c_num] = c_ptr; | ||
87 | } | ||
88 | |||
89 | void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router) | ||
90 | { | ||
91 | u32 c_num; | ||
92 | |||
93 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { | ||
94 | if (z_ptr->clusters[c_num]) { | ||
95 | tipc_cltr_remove_as_router(z_ptr->clusters[c_num], | ||
96 | router); | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest) | ||
102 | { | ||
103 | u32 c_num; | ||
104 | |||
105 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { | ||
106 | if (z_ptr->clusters[c_num]) { | ||
107 | if (in_own_cluster(z_ptr->addr)) | ||
108 | continue; | ||
109 | tipc_cltr_send_ext_routes(z_ptr->clusters[c_num], dest); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref) | ||
115 | { | ||
116 | struct cluster *c_ptr; | ||
117 | struct tipc_node *n_ptr; | ||
118 | u32 c_num; | ||
119 | |||
120 | if (!z_ptr) | ||
121 | return NULL; | ||
122 | c_ptr = z_ptr->clusters[tipc_cluster(addr)]; | ||
123 | if (!c_ptr) | ||
124 | return NULL; | ||
125 | n_ptr = tipc_cltr_select_node(c_ptr, ref); | ||
126 | if (n_ptr) | ||
127 | return n_ptr; | ||
128 | |||
129 | /* Links to any other clusters within this zone ? */ | ||
130 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { | ||
131 | c_ptr = z_ptr->clusters[c_num]; | ||
132 | if (!c_ptr) | ||
133 | return NULL; | ||
134 | n_ptr = tipc_cltr_select_node(c_ptr, ref); | ||
135 | if (n_ptr) | ||
136 | return n_ptr; | ||
137 | } | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref) | ||
142 | { | ||
143 | struct cluster *c_ptr; | ||
144 | u32 c_num; | ||
145 | u32 router; | ||
146 | |||
147 | if (!z_ptr) | ||
148 | return 0; | ||
149 | c_ptr = z_ptr->clusters[tipc_cluster(addr)]; | ||
150 | router = c_ptr ? tipc_cltr_select_router(c_ptr, ref) : 0; | ||
151 | if (router) | ||
152 | return router; | ||
153 | |||
154 | /* Links to any other clusters within the zone? */ | ||
155 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { | ||
156 | c_ptr = z_ptr->clusters[c_num]; | ||
157 | router = c_ptr ? tipc_cltr_select_router(c_ptr, ref) : 0; | ||
158 | if (router) | ||
159 | return router; | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
diff --git a/net/tipc/zone.h b/net/tipc/zone.h deleted file mode 100644 index bd1c20ce9d06..000000000000 --- a/net/tipc/zone.h +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | /* | ||
2 | * net/tipc/zone.h: Include file for TIPC zone management routines | ||
3 | * | ||
4 | * Copyright (c) 2000-2006, Ericsson AB | ||
5 | * Copyright (c) 2005-2006, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #ifndef _TIPC_ZONE_H | ||
38 | #define _TIPC_ZONE_H | ||
39 | |||
40 | #include "node_subscr.h" | ||
41 | #include "net.h" | ||
42 | |||
43 | |||
44 | /** | ||
45 | * struct _zone - TIPC zone structure | ||
46 | * @addr: network address of zone | ||
47 | * @clusters: array of pointers to all clusters within zone | ||
48 | * @links: number of (unicast) links to zone | ||
49 | */ | ||
50 | |||
51 | struct _zone { | ||
52 | u32 addr; | ||
53 | struct cluster *clusters[2]; /* currently limited to just 1 cluster */ | ||
54 | u32 links; | ||
55 | }; | ||
56 | |||
57 | struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref); | ||
58 | u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref); | ||
59 | void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router); | ||
60 | void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest); | ||
61 | struct _zone *tipc_zone_create(u32 addr); | ||
62 | void tipc_zone_delete(struct _zone *z_ptr); | ||
63 | void tipc_zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr); | ||
64 | |||
65 | static inline struct _zone *tipc_zone_find(u32 addr) | ||
66 | { | ||
67 | return tipc_net.zones[tipc_zone(addr)]; | ||
68 | } | ||
69 | |||
70 | #endif | ||
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2268e6798124..417d7a6c36cf 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -316,7 +316,8 @@ static void unix_write_space(struct sock *sk) | |||
316 | if (unix_writable(sk)) { | 316 | if (unix_writable(sk)) { |
317 | wq = rcu_dereference(sk->sk_wq); | 317 | wq = rcu_dereference(sk->sk_wq); |
318 | if (wq_has_sleeper(wq)) | 318 | if (wq_has_sleeper(wq)) |
319 | wake_up_interruptible_sync(&wq->wait); | 319 | wake_up_interruptible_sync_poll(&wq->wait, |
320 | POLLOUT | POLLWRNORM | POLLWRBAND); | ||
320 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); | 321 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); |
321 | } | 322 | } |
322 | rcu_read_unlock(); | 323 | rcu_read_unlock(); |
@@ -1736,7 +1737,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1736 | goto out_unlock; | 1737 | goto out_unlock; |
1737 | } | 1738 | } |
1738 | 1739 | ||
1739 | wake_up_interruptible_sync(&u->peer_wait); | 1740 | wake_up_interruptible_sync_poll(&u->peer_wait, |
1741 | POLLOUT | POLLWRNORM | POLLWRBAND); | ||
1740 | 1742 | ||
1741 | if (msg->msg_name) | 1743 | if (msg->msg_name) |
1742 | unix_copy_addr(msg, skb->sk); | 1744 | unix_copy_addr(msg, skb->sk); |
@@ -2099,13 +2101,12 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, | |||
2099 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) | 2101 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) |
2100 | mask |= POLLERR; | 2102 | mask |= POLLERR; |
2101 | if (sk->sk_shutdown & RCV_SHUTDOWN) | 2103 | if (sk->sk_shutdown & RCV_SHUTDOWN) |
2102 | mask |= POLLRDHUP; | 2104 | mask |= POLLRDHUP | POLLIN | POLLRDNORM; |
2103 | if (sk->sk_shutdown == SHUTDOWN_MASK) | 2105 | if (sk->sk_shutdown == SHUTDOWN_MASK) |
2104 | mask |= POLLHUP; | 2106 | mask |= POLLHUP; |
2105 | 2107 | ||
2106 | /* readable? */ | 2108 | /* readable? */ |
2107 | if (!skb_queue_empty(&sk->sk_receive_queue) || | 2109 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
2108 | (sk->sk_shutdown & RCV_SHUTDOWN)) | ||
2109 | mask |= POLLIN | POLLRDNORM; | 2110 | mask |= POLLIN | POLLRDNORM; |
2110 | 2111 | ||
2111 | /* Connection-based need to check for termination and startup */ | 2112 | /* Connection-based need to check for termination and startup */ |
@@ -2117,20 +2118,19 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, | |||
2117 | return mask; | 2118 | return mask; |
2118 | } | 2119 | } |
2119 | 2120 | ||
2120 | /* writable? */ | 2121 | /* No write status requested, avoid expensive OUT tests. */ |
2121 | writable = unix_writable(sk); | 2122 | if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT))) |
2122 | if (writable) { | 2123 | return mask; |
2123 | other = unix_peer_get(sk); | ||
2124 | if (other) { | ||
2125 | if (unix_peer(other) != sk) { | ||
2126 | sock_poll_wait(file, &unix_sk(other)->peer_wait, | ||
2127 | wait); | ||
2128 | if (unix_recvq_full(other)) | ||
2129 | writable = 0; | ||
2130 | } | ||
2131 | 2124 | ||
2132 | sock_put(other); | 2125 | writable = unix_writable(sk); |
2126 | other = unix_peer_get(sk); | ||
2127 | if (other) { | ||
2128 | if (unix_peer(other) != sk) { | ||
2129 | sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); | ||
2130 | if (unix_recvq_full(other)) | ||
2131 | writable = 0; | ||
2133 | } | 2132 | } |
2133 | sock_put(other); | ||
2134 | } | 2134 | } |
2135 | 2135 | ||
2136 | if (writable) | 2136 | if (writable) |
diff --git a/net/wanrouter/Makefile b/net/wanrouter/Makefile index 9f188ab3dcd0..4da14bc48078 100644 --- a/net/wanrouter/Makefile +++ b/net/wanrouter/Makefile | |||
@@ -4,4 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_WAN_ROUTER) += wanrouter.o | 5 | obj-$(CONFIG_WAN_ROUTER) += wanrouter.o |
6 | 6 | ||
7 | wanrouter-objs := wanproc.o wanmain.o | 7 | wanrouter-y := wanproc.o wanmain.o |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index e77e508126fa..55a28ab21db9 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 9c21ebf9780e..e9a5f8ca4c27 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
8 | |||
7 | #include <linux/if.h> | 9 | #include <linux/if.h> |
8 | #include <linux/module.h> | 10 | #include <linux/module.h> |
9 | #include <linux/err.h> | 11 | #include <linux/err.h> |
@@ -216,8 +218,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
216 | rdev->wiphy.debugfsdir, | 218 | rdev->wiphy.debugfsdir, |
217 | rdev->wiphy.debugfsdir->d_parent, | 219 | rdev->wiphy.debugfsdir->d_parent, |
218 | newname)) | 220 | newname)) |
219 | printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", | 221 | pr_err("failed to rename debugfs dir to %s!\n", newname); |
220 | newname); | ||
221 | 222 | ||
222 | nl80211_notify_dev_rename(rdev); | 223 | nl80211_notify_dev_rename(rdev); |
223 | 224 | ||
@@ -331,6 +332,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
331 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); | 332 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); |
332 | WARN_ON(ops->add_station && !ops->del_station); | 333 | WARN_ON(ops->add_station && !ops->del_station); |
333 | WARN_ON(ops->add_mpath && !ops->del_mpath); | 334 | WARN_ON(ops->add_mpath && !ops->del_mpath); |
335 | WARN_ON(ops->join_mesh && !ops->leave_mesh); | ||
334 | 336 | ||
335 | alloc_size = sizeof(*rdev) + sizeof_priv; | 337 | alloc_size = sizeof(*rdev) + sizeof_priv; |
336 | 338 | ||
@@ -699,8 +701,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
699 | 701 | ||
700 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, | 702 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, |
701 | "phy80211")) { | 703 | "phy80211")) { |
702 | printk(KERN_ERR "wireless: failed to add phy80211 " | 704 | pr_err("failed to add phy80211 symlink to netdev!\n"); |
703 | "symlink to netdev!\n"); | ||
704 | } | 705 | } |
705 | wdev->netdev = dev; | 706 | wdev->netdev = dev; |
706 | wdev->sme_state = CFG80211_SME_IDLE; | 707 | wdev->sme_state = CFG80211_SME_IDLE; |
@@ -752,6 +753,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
752 | cfg80211_mlme_down(rdev, dev); | 753 | cfg80211_mlme_down(rdev, dev); |
753 | wdev_unlock(wdev); | 754 | wdev_unlock(wdev); |
754 | break; | 755 | break; |
756 | case NL80211_IFTYPE_MESH_POINT: | ||
757 | cfg80211_leave_mesh(rdev, dev); | ||
758 | break; | ||
755 | default: | 759 | default: |
756 | break; | 760 | break; |
757 | } | 761 | } |
@@ -775,20 +779,37 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
775 | } | 779 | } |
776 | cfg80211_lock_rdev(rdev); | 780 | cfg80211_lock_rdev(rdev); |
777 | mutex_lock(&rdev->devlist_mtx); | 781 | mutex_lock(&rdev->devlist_mtx); |
778 | #ifdef CONFIG_CFG80211_WEXT | ||
779 | wdev_lock(wdev); | 782 | wdev_lock(wdev); |
780 | switch (wdev->iftype) { | 783 | switch (wdev->iftype) { |
784 | #ifdef CONFIG_CFG80211_WEXT | ||
781 | case NL80211_IFTYPE_ADHOC: | 785 | case NL80211_IFTYPE_ADHOC: |
782 | cfg80211_ibss_wext_join(rdev, wdev); | 786 | cfg80211_ibss_wext_join(rdev, wdev); |
783 | break; | 787 | break; |
784 | case NL80211_IFTYPE_STATION: | 788 | case NL80211_IFTYPE_STATION: |
785 | cfg80211_mgd_wext_connect(rdev, wdev); | 789 | cfg80211_mgd_wext_connect(rdev, wdev); |
786 | break; | 790 | break; |
791 | #endif | ||
792 | #ifdef CONFIG_MAC80211_MESH | ||
793 | case NL80211_IFTYPE_MESH_POINT: | ||
794 | { | ||
795 | /* backward compat code... */ | ||
796 | struct mesh_setup setup; | ||
797 | memcpy(&setup, &default_mesh_setup, | ||
798 | sizeof(setup)); | ||
799 | /* back compat only needed for mesh_id */ | ||
800 | setup.mesh_id = wdev->ssid; | ||
801 | setup.mesh_id_len = wdev->mesh_id_up_len; | ||
802 | if (wdev->mesh_id_up_len) | ||
803 | __cfg80211_join_mesh(rdev, dev, | ||
804 | &setup, | ||
805 | &default_mesh_config); | ||
806 | break; | ||
807 | } | ||
808 | #endif | ||
787 | default: | 809 | default: |
788 | break; | 810 | break; |
789 | } | 811 | } |
790 | wdev_unlock(wdev); | 812 | wdev_unlock(wdev); |
791 | #endif | ||
792 | rdev->opencount++; | 813 | rdev->opencount++; |
793 | mutex_unlock(&rdev->devlist_mtx); | 814 | mutex_unlock(&rdev->devlist_mtx); |
794 | cfg80211_unlock_rdev(rdev); | 815 | cfg80211_unlock_rdev(rdev); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 6583cca0e2ee..26a0a084e16b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -285,6 +285,20 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | |||
285 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 285 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
286 | struct wireless_dev *wdev); | 286 | struct wireless_dev *wdev); |
287 | 287 | ||
288 | /* mesh */ | ||
289 | extern const struct mesh_config default_mesh_config; | ||
290 | extern const struct mesh_setup default_mesh_setup; | ||
291 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
292 | struct net_device *dev, | ||
293 | const struct mesh_setup *setup, | ||
294 | const struct mesh_config *conf); | ||
295 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
296 | struct net_device *dev, | ||
297 | const struct mesh_setup *setup, | ||
298 | const struct mesh_config *conf); | ||
299 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
300 | struct net_device *dev); | ||
301 | |||
288 | /* MLME */ | 302 | /* MLME */ |
289 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 303 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
290 | struct net_device *dev, | 304 | struct net_device *dev, |
@@ -341,9 +355,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); | |||
341 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); | 355 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
342 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 356 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
343 | struct net_device *dev, | 357 | struct net_device *dev, |
344 | struct ieee80211_channel *chan, | 358 | struct ieee80211_channel *chan, bool offchan, |
345 | enum nl80211_channel_type channel_type, | 359 | enum nl80211_channel_type channel_type, |
346 | bool channel_type_valid, | 360 | bool channel_type_valid, unsigned int wait, |
347 | const u8 *buf, size_t len, u64 *cookie); | 361 | const u8 *buf, size_t len, u64 *cookie); |
348 | 362 | ||
349 | /* SME */ | 363 | /* SME */ |
diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c index 97d411f74507..3268fac5ab22 100644 --- a/net/wireless/lib80211.c +++ b/net/wireless/lib80211.c | |||
@@ -13,6 +13,8 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
17 | |||
16 | #include <linux/module.h> | 18 | #include <linux/module.h> |
17 | #include <linux/ctype.h> | 19 | #include <linux/ctype.h> |
18 | #include <linux/ieee80211.h> | 20 | #include <linux/ieee80211.h> |
@@ -224,8 +226,8 @@ int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops) | |||
224 | return -EINVAL; | 226 | return -EINVAL; |
225 | 227 | ||
226 | found: | 228 | found: |
227 | printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm " | 229 | printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm '%s'\n", |
228 | "'%s'\n", ops->name); | 230 | ops->name); |
229 | list_del(&alg->list); | 231 | list_del(&alg->list); |
230 | spin_unlock_irqrestore(&lib80211_crypto_lock, flags); | 232 | spin_unlock_irqrestore(&lib80211_crypto_lock, flags); |
231 | kfree(alg); | 233 | kfree(alg); |
@@ -270,7 +272,7 @@ static struct lib80211_crypto_ops lib80211_crypt_null = { | |||
270 | 272 | ||
271 | static int __init lib80211_init(void) | 273 | static int __init lib80211_init(void) |
272 | { | 274 | { |
273 | printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n"); | 275 | pr_info(DRV_DESCRIPTION "\n"); |
274 | return lib80211_register_crypto_ops(&lib80211_crypt_null); | 276 | return lib80211_register_crypto_ops(&lib80211_crypt_null); |
275 | } | 277 | } |
276 | 278 | ||
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index 0fe40510e2cb..7ea4f2b0770e 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c | |||
@@ -10,6 +10,8 @@ | |||
10 | * more details. | 10 | * more details. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | |||
13 | #include <linux/err.h> | 15 | #include <linux/err.h> |
14 | #include <linux/module.h> | 16 | #include <linux/module.h> |
15 | #include <linux/init.h> | 17 | #include <linux/init.h> |
@@ -99,8 +101,7 @@ static void *lib80211_tkip_init(int key_idx) | |||
99 | priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, | 101 | priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, |
100 | CRYPTO_ALG_ASYNC); | 102 | CRYPTO_ALG_ASYNC); |
101 | if (IS_ERR(priv->tx_tfm_arc4)) { | 103 | if (IS_ERR(priv->tx_tfm_arc4)) { |
102 | printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " | 104 | printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n")); |
103 | "crypto API arc4\n"); | ||
104 | priv->tx_tfm_arc4 = NULL; | 105 | priv->tx_tfm_arc4 = NULL; |
105 | goto fail; | 106 | goto fail; |
106 | } | 107 | } |
@@ -108,8 +109,7 @@ static void *lib80211_tkip_init(int key_idx) | |||
108 | priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, | 109 | priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, |
109 | CRYPTO_ALG_ASYNC); | 110 | CRYPTO_ALG_ASYNC); |
110 | if (IS_ERR(priv->tx_tfm_michael)) { | 111 | if (IS_ERR(priv->tx_tfm_michael)) { |
111 | printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " | 112 | printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n")); |
112 | "crypto API michael_mic\n"); | ||
113 | priv->tx_tfm_michael = NULL; | 113 | priv->tx_tfm_michael = NULL; |
114 | goto fail; | 114 | goto fail; |
115 | } | 115 | } |
@@ -117,8 +117,7 @@ static void *lib80211_tkip_init(int key_idx) | |||
117 | priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, | 117 | priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, |
118 | CRYPTO_ALG_ASYNC); | 118 | CRYPTO_ALG_ASYNC); |
119 | if (IS_ERR(priv->rx_tfm_arc4)) { | 119 | if (IS_ERR(priv->rx_tfm_arc4)) { |
120 | printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " | 120 | printk(KERN_DEBUG pr_fmt("could not allocate crypto API arc4\n")); |
121 | "crypto API arc4\n"); | ||
122 | priv->rx_tfm_arc4 = NULL; | 121 | priv->rx_tfm_arc4 = NULL; |
123 | goto fail; | 122 | goto fail; |
124 | } | 123 | } |
@@ -126,8 +125,7 @@ static void *lib80211_tkip_init(int key_idx) | |||
126 | priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, | 125 | priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, |
127 | CRYPTO_ALG_ASYNC); | 126 | CRYPTO_ALG_ASYNC); |
128 | if (IS_ERR(priv->rx_tfm_michael)) { | 127 | if (IS_ERR(priv->rx_tfm_michael)) { |
129 | printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " | 128 | printk(KERN_DEBUG pr_fmt("could not allocate crypto API michael_mic\n")); |
130 | "crypto API michael_mic\n"); | ||
131 | priv->rx_tfm_michael = NULL; | 129 | priv->rx_tfm_michael = NULL; |
132 | goto fail; | 130 | goto fail; |
133 | } | 131 | } |
@@ -536,7 +534,7 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, | |||
536 | struct scatterlist sg[2]; | 534 | struct scatterlist sg[2]; |
537 | 535 | ||
538 | if (tfm_michael == NULL) { | 536 | if (tfm_michael == NULL) { |
539 | printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); | 537 | pr_warn("%s(): tfm_michael == NULL\n", __func__); |
540 | return -1; | 538 | return -1; |
541 | } | 539 | } |
542 | sg_init_table(sg, 2); | 540 | sg_init_table(sg, 2); |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c new file mode 100644 index 000000000000..73e39c171ffb --- /dev/null +++ b/net/wireless/mesh.c | |||
@@ -0,0 +1,142 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <net/cfg80211.h> | ||
3 | #include "core.h" | ||
4 | |||
5 | /* Default values, timeouts in ms */ | ||
6 | #define MESH_TTL 31 | ||
7 | #define MESH_DEFAULT_ELEMENT_TTL 31 | ||
8 | #define MESH_MAX_RETR 3 | ||
9 | #define MESH_RET_T 100 | ||
10 | #define MESH_CONF_T 100 | ||
11 | #define MESH_HOLD_T 100 | ||
12 | |||
13 | #define MESH_PATH_TIMEOUT 5000 | ||
14 | |||
15 | /* | ||
16 | * Minimum interval between two consecutive PREQs originated by the same | ||
17 | * interface | ||
18 | */ | ||
19 | #define MESH_PREQ_MIN_INT 10 | ||
20 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
21 | |||
22 | /* | ||
23 | * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds | ||
24 | * before timing out. This way it will remain ACTIVE and no data frames | ||
25 | * will be unnecessarily held in the pending queue. | ||
26 | */ | ||
27 | #define MESH_PATH_REFRESH_TIME 1000 | ||
28 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
29 | |||
30 | /* Default maximum number of established plinks per interface */ | ||
31 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
32 | |||
33 | #define MESH_MAX_PREQ_RETRIES 4 | ||
34 | |||
35 | |||
36 | const struct mesh_config default_mesh_config = { | ||
37 | .dot11MeshRetryTimeout = MESH_RET_T, | ||
38 | .dot11MeshConfirmTimeout = MESH_CONF_T, | ||
39 | .dot11MeshHoldingTimeout = MESH_HOLD_T, | ||
40 | .dot11MeshMaxRetries = MESH_MAX_RETR, | ||
41 | .dot11MeshTTL = MESH_TTL, | ||
42 | .element_ttl = MESH_DEFAULT_ELEMENT_TTL, | ||
43 | .auto_open_plinks = true, | ||
44 | .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, | ||
45 | .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, | ||
46 | .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, | ||
47 | .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, | ||
48 | .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, | ||
49 | .path_refresh_time = MESH_PATH_REFRESH_TIME, | ||
50 | .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, | ||
51 | }; | ||
52 | |||
53 | const struct mesh_setup default_mesh_setup = { | ||
54 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, | ||
55 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, | ||
56 | .vendor_ie = NULL, | ||
57 | .vendor_ie_len = 0, | ||
58 | }; | ||
59 | |||
60 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
61 | struct net_device *dev, | ||
62 | const struct mesh_setup *setup, | ||
63 | const struct mesh_config *conf) | ||
64 | { | ||
65 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
66 | int err; | ||
67 | |||
68 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); | ||
69 | |||
70 | ASSERT_WDEV_LOCK(wdev); | ||
71 | |||
72 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
73 | return -EOPNOTSUPP; | ||
74 | |||
75 | if (wdev->mesh_id_len) | ||
76 | return -EALREADY; | ||
77 | |||
78 | if (!setup->mesh_id_len) | ||
79 | return -EINVAL; | ||
80 | |||
81 | if (!rdev->ops->join_mesh) | ||
82 | return -EOPNOTSUPP; | ||
83 | |||
84 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | ||
85 | if (!err) { | ||
86 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | ||
87 | wdev->mesh_id_len = setup->mesh_id_len; | ||
88 | } | ||
89 | |||
90 | return err; | ||
91 | } | ||
92 | |||
93 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
94 | struct net_device *dev, | ||
95 | const struct mesh_setup *setup, | ||
96 | const struct mesh_config *conf) | ||
97 | { | ||
98 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
99 | int err; | ||
100 | |||
101 | wdev_lock(wdev); | ||
102 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | ||
103 | wdev_unlock(wdev); | ||
104 | |||
105 | return err; | ||
106 | } | ||
107 | |||
108 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
109 | struct net_device *dev) | ||
110 | { | ||
111 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
112 | int err; | ||
113 | |||
114 | ASSERT_WDEV_LOCK(wdev); | ||
115 | |||
116 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
117 | return -EOPNOTSUPP; | ||
118 | |||
119 | if (!rdev->ops->leave_mesh) | ||
120 | return -EOPNOTSUPP; | ||
121 | |||
122 | if (!wdev->mesh_id_len) | ||
123 | return -ENOTCONN; | ||
124 | |||
125 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | ||
126 | if (!err) | ||
127 | wdev->mesh_id_len = 0; | ||
128 | return err; | ||
129 | } | ||
130 | |||
131 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
132 | struct net_device *dev) | ||
133 | { | ||
134 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
135 | int err; | ||
136 | |||
137 | wdev_lock(wdev); | ||
138 | err = __cfg80211_leave_mesh(rdev, dev); | ||
139 | wdev_unlock(wdev); | ||
140 | |||
141 | return err; | ||
142 | } | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 26838d903b9a..aa5df8865ff7 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -263,6 +263,28 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | |||
263 | } | 263 | } |
264 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 264 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
265 | 265 | ||
266 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, | ||
267 | size_t len) | ||
268 | { | ||
269 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
270 | struct wiphy *wiphy = wdev->wiphy; | ||
271 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
272 | |||
273 | nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC); | ||
274 | } | ||
275 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
276 | |||
277 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, | ||
278 | size_t len) | ||
279 | { | ||
280 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
281 | struct wiphy *wiphy = wdev->wiphy; | ||
282 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
283 | |||
284 | nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC); | ||
285 | } | ||
286 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | ||
287 | |||
266 | static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) | 288 | static void __cfg80211_auth_remove(struct wireless_dev *wdev, const u8 *addr) |
267 | { | 289 | { |
268 | int i; | 290 | int i; |
@@ -864,9 +886,9 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | |||
864 | 886 | ||
865 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 887 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
866 | struct net_device *dev, | 888 | struct net_device *dev, |
867 | struct ieee80211_channel *chan, | 889 | struct ieee80211_channel *chan, bool offchan, |
868 | enum nl80211_channel_type channel_type, | 890 | enum nl80211_channel_type channel_type, |
869 | bool channel_type_valid, | 891 | bool channel_type_valid, unsigned int wait, |
870 | const u8 *buf, size_t len, u64 *cookie) | 892 | const u8 *buf, size_t len, u64 *cookie) |
871 | { | 893 | { |
872 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 894 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -946,8 +968,9 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
946 | return -EINVAL; | 968 | return -EINVAL; |
947 | 969 | ||
948 | /* Transmit the Action frame as requested by user space */ | 970 | /* Transmit the Action frame as requested by user space */ |
949 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type, | 971 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, |
950 | channel_type_valid, buf, len, cookie); | 972 | channel_type, channel_type_valid, |
973 | wait, buf, len, cookie); | ||
951 | } | 974 | } |
952 | 975 | ||
953 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, | 976 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, |
@@ -1028,3 +1051,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, | |||
1028 | nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); | 1051 | nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); |
1029 | } | 1052 | } |
1030 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | 1053 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); |
1054 | |||
1055 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, | ||
1056 | const u8 *peer, u32 num_packets, gfp_t gfp) | ||
1057 | { | ||
1058 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1059 | struct wiphy *wiphy = wdev->wiphy; | ||
1060 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
1061 | |||
1062 | /* Indicate roaming trigger event to user space */ | ||
1063 | nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); | ||
1064 | } | ||
1065 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4e78e3f26798..9b62710891a2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -121,8 +121,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
121 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, | 121 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, |
122 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, | 122 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, |
123 | .len = NL80211_MAX_SUPP_RATES }, | 123 | .len = NL80211_MAX_SUPP_RATES }, |
124 | [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, | ||
124 | 125 | ||
125 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, | 126 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, |
126 | 127 | ||
127 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 128 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
128 | .len = NL80211_HT_CAPABILITY_LEN }, | 129 | .len = NL80211_HT_CAPABILITY_LEN }, |
@@ -163,10 +164,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
163 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, | 164 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, |
164 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, | 165 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, |
165 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, | 166 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, |
166 | |||
167 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | 167 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, |
168 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | 168 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, |
169 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | 169 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, |
170 | [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 }, | ||
171 | [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, | ||
172 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, | ||
173 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, | ||
174 | [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | ||
170 | }; | 175 | }; |
171 | 176 | ||
172 | /* policy for the key attributes */ | 177 | /* policy for the key attributes */ |
@@ -178,6 +183,14 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
178 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 183 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
179 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 184 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
180 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | 185 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, |
186 | [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | ||
187 | }; | ||
188 | |||
189 | /* policy for the key default flags */ | ||
190 | static const struct nla_policy | ||
191 | nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = { | ||
192 | [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG }, | ||
193 | [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, | ||
181 | }; | 194 | }; |
182 | 195 | ||
183 | /* ifidx get helper */ | 196 | /* ifidx get helper */ |
@@ -310,6 +323,7 @@ struct key_parse { | |||
310 | int idx; | 323 | int idx; |
311 | int type; | 324 | int type; |
312 | bool def, defmgmt; | 325 | bool def, defmgmt; |
326 | bool def_uni, def_multi; | ||
313 | }; | 327 | }; |
314 | 328 | ||
315 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | 329 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) |
@@ -323,6 +337,13 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
323 | k->def = !!tb[NL80211_KEY_DEFAULT]; | 337 | k->def = !!tb[NL80211_KEY_DEFAULT]; |
324 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; | 338 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; |
325 | 339 | ||
340 | if (k->def) { | ||
341 | k->def_uni = true; | ||
342 | k->def_multi = true; | ||
343 | } | ||
344 | if (k->defmgmt) | ||
345 | k->def_multi = true; | ||
346 | |||
326 | if (tb[NL80211_KEY_IDX]) | 347 | if (tb[NL80211_KEY_IDX]) |
327 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); | 348 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); |
328 | 349 | ||
@@ -345,6 +366,19 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
345 | return -EINVAL; | 366 | return -EINVAL; |
346 | } | 367 | } |
347 | 368 | ||
369 | if (tb[NL80211_KEY_DEFAULT_TYPES]) { | ||
370 | struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; | ||
371 | int err = nla_parse_nested(kdt, | ||
372 | NUM_NL80211_KEY_DEFAULT_TYPES - 1, | ||
373 | tb[NL80211_KEY_DEFAULT_TYPES], | ||
374 | nl80211_key_default_policy); | ||
375 | if (err) | ||
376 | return err; | ||
377 | |||
378 | k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST]; | ||
379 | k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; | ||
380 | } | ||
381 | |||
348 | return 0; | 382 | return 0; |
349 | } | 383 | } |
350 | 384 | ||
@@ -369,12 +403,32 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | |||
369 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 403 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
370 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 404 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
371 | 405 | ||
406 | if (k->def) { | ||
407 | k->def_uni = true; | ||
408 | k->def_multi = true; | ||
409 | } | ||
410 | if (k->defmgmt) | ||
411 | k->def_multi = true; | ||
412 | |||
372 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | 413 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { |
373 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | 414 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); |
374 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | 415 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) |
375 | return -EINVAL; | 416 | return -EINVAL; |
376 | } | 417 | } |
377 | 418 | ||
419 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) { | ||
420 | struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES]; | ||
421 | int err = nla_parse_nested( | ||
422 | kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1, | ||
423 | info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES], | ||
424 | nl80211_key_default_policy); | ||
425 | if (err) | ||
426 | return err; | ||
427 | |||
428 | k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST]; | ||
429 | k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; | ||
430 | } | ||
431 | |||
378 | return 0; | 432 | return 0; |
379 | } | 433 | } |
380 | 434 | ||
@@ -397,6 +451,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | |||
397 | if (k->def && k->defmgmt) | 451 | if (k->def && k->defmgmt) |
398 | return -EINVAL; | 452 | return -EINVAL; |
399 | 453 | ||
454 | if (k->defmgmt) { | ||
455 | if (k->def_uni || !k->def_multi) | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
400 | if (k->idx != -1) { | 459 | if (k->idx != -1) { |
401 | if (k->defmgmt) { | 460 | if (k->defmgmt) { |
402 | if (k->idx < 4 || k->idx > 5) | 461 | if (k->idx < 4 || k->idx > 5) |
@@ -446,6 +505,8 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
446 | goto error; | 505 | goto error; |
447 | def = 1; | 506 | def = 1; |
448 | result->def = parse.idx; | 507 | result->def = parse.idx; |
508 | if (!parse.def_uni || !parse.def_multi) | ||
509 | goto error; | ||
449 | } else if (parse.defmgmt) | 510 | } else if (parse.defmgmt) |
450 | goto error; | 511 | goto error; |
451 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 512 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
@@ -526,7 +587,6 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
526 | dev->wiphy.rts_threshold); | 587 | dev->wiphy.rts_threshold); |
527 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | 588 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, |
528 | dev->wiphy.coverage_class); | 589 | dev->wiphy.coverage_class); |
529 | |||
530 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 590 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
531 | dev->wiphy.max_scan_ssids); | 591 | dev->wiphy.max_scan_ssids); |
532 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 592 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
@@ -545,6 +605,22 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
545 | if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) | 605 | if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) |
546 | NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); | 606 | NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE); |
547 | 607 | ||
608 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, | ||
609 | dev->wiphy.available_antennas_tx); | ||
610 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | ||
611 | dev->wiphy.available_antennas_rx); | ||
612 | |||
613 | if ((dev->wiphy.available_antennas_tx || | ||
614 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { | ||
615 | u32 tx_ant = 0, rx_ant = 0; | ||
616 | int res; | ||
617 | res = dev->ops->get_antenna(&dev->wiphy, &tx_ant, &rx_ant); | ||
618 | if (!res) { | ||
619 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant); | ||
620 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant); | ||
621 | } | ||
622 | } | ||
623 | |||
548 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 624 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
549 | if (!nl_modes) | 625 | if (!nl_modes) |
550 | goto nla_put_failure; | 626 | goto nla_put_failure; |
@@ -649,19 +725,21 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
649 | CMD(add_beacon, NEW_BEACON); | 725 | CMD(add_beacon, NEW_BEACON); |
650 | CMD(add_station, NEW_STATION); | 726 | CMD(add_station, NEW_STATION); |
651 | CMD(add_mpath, NEW_MPATH); | 727 | CMD(add_mpath, NEW_MPATH); |
652 | CMD(set_mesh_params, SET_MESH_PARAMS); | 728 | CMD(update_mesh_config, SET_MESH_CONFIG); |
653 | CMD(change_bss, SET_BSS); | 729 | CMD(change_bss, SET_BSS); |
654 | CMD(auth, AUTHENTICATE); | 730 | CMD(auth, AUTHENTICATE); |
655 | CMD(assoc, ASSOCIATE); | 731 | CMD(assoc, ASSOCIATE); |
656 | CMD(deauth, DEAUTHENTICATE); | 732 | CMD(deauth, DEAUTHENTICATE); |
657 | CMD(disassoc, DISASSOCIATE); | 733 | CMD(disassoc, DISASSOCIATE); |
658 | CMD(join_ibss, JOIN_IBSS); | 734 | CMD(join_ibss, JOIN_IBSS); |
735 | CMD(join_mesh, JOIN_MESH); | ||
659 | CMD(set_pmksa, SET_PMKSA); | 736 | CMD(set_pmksa, SET_PMKSA); |
660 | CMD(del_pmksa, DEL_PMKSA); | 737 | CMD(del_pmksa, DEL_PMKSA); |
661 | CMD(flush_pmksa, FLUSH_PMKSA); | 738 | CMD(flush_pmksa, FLUSH_PMKSA); |
662 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 739 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
663 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 740 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
664 | CMD(mgmt_tx, FRAME); | 741 | CMD(mgmt_tx, FRAME); |
742 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | ||
665 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 743 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
666 | i++; | 744 | i++; |
667 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 745 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -683,6 +761,14 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
683 | 761 | ||
684 | nla_nest_end(msg, nl_cmds); | 762 | nla_nest_end(msg, nl_cmds); |
685 | 763 | ||
764 | if (dev->ops->remain_on_channel) | ||
765 | NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | ||
766 | dev->wiphy.max_remain_on_channel_duration); | ||
767 | |||
768 | /* for now at least assume all drivers have it */ | ||
769 | if (dev->ops->mgmt_tx) | ||
770 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); | ||
771 | |||
686 | if (mgmt_stypes) { | 772 | if (mgmt_stypes) { |
687 | u16 stypes; | 773 | u16 stypes; |
688 | struct nlattr *nl_ftypes, *nl_ifs; | 774 | struct nlattr *nl_ftypes, *nl_ifs; |
@@ -1024,6 +1110,35 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1024 | goto bad_res; | 1110 | goto bad_res; |
1025 | } | 1111 | } |
1026 | 1112 | ||
1113 | if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && | ||
1114 | info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { | ||
1115 | u32 tx_ant, rx_ant; | ||
1116 | if ((!rdev->wiphy.available_antennas_tx && | ||
1117 | !rdev->wiphy.available_antennas_rx) || | ||
1118 | !rdev->ops->set_antenna) { | ||
1119 | result = -EOPNOTSUPP; | ||
1120 | goto bad_res; | ||
1121 | } | ||
1122 | |||
1123 | tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]); | ||
1124 | rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]); | ||
1125 | |||
1126 | /* reject antenna configurations which don't match the | ||
1127 | * available antenna masks, except for the "all" mask */ | ||
1128 | if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) || | ||
1129 | (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) { | ||
1130 | result = -EINVAL; | ||
1131 | goto bad_res; | ||
1132 | } | ||
1133 | |||
1134 | tx_ant = tx_ant & rdev->wiphy.available_antennas_tx; | ||
1135 | rx_ant = rx_ant & rdev->wiphy.available_antennas_rx; | ||
1136 | |||
1137 | result = rdev->ops->set_antenna(&rdev->wiphy, tx_ant, rx_ant); | ||
1138 | if (result) | ||
1139 | goto bad_res; | ||
1140 | } | ||
1141 | |||
1027 | changed = 0; | 1142 | changed = 0; |
1028 | 1143 | ||
1029 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | 1144 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { |
@@ -1291,11 +1406,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1291 | } | 1406 | } |
1292 | 1407 | ||
1293 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1408 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1409 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1410 | |||
1294 | if (ntype != NL80211_IFTYPE_MESH_POINT) | 1411 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1295 | return -EINVAL; | 1412 | return -EINVAL; |
1296 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1413 | if (netif_running(dev)) |
1297 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1414 | return -EBUSY; |
1298 | change = true; | 1415 | |
1416 | wdev_lock(wdev); | ||
1417 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | ||
1418 | IEEE80211_MAX_MESH_ID_LEN); | ||
1419 | wdev->mesh_id_up_len = | ||
1420 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1421 | memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
1422 | wdev->mesh_id_up_len); | ||
1423 | wdev_unlock(wdev); | ||
1299 | } | 1424 | } |
1300 | 1425 | ||
1301 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1426 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
@@ -1335,6 +1460,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1335 | { | 1460 | { |
1336 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1461 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1337 | struct vif_params params; | 1462 | struct vif_params params; |
1463 | struct net_device *dev; | ||
1338 | int err; | 1464 | int err; |
1339 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1465 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1340 | u32 flags; | 1466 | u32 flags; |
@@ -1354,12 +1480,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1354 | !(rdev->wiphy.interface_modes & (1 << type))) | 1480 | !(rdev->wiphy.interface_modes & (1 << type))) |
1355 | return -EOPNOTSUPP; | 1481 | return -EOPNOTSUPP; |
1356 | 1482 | ||
1357 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
1358 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
1359 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1360 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1361 | } | ||
1362 | |||
1363 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1483 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
1364 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1484 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1365 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1485 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
@@ -1370,11 +1490,27 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1370 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1490 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1371 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 1491 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1372 | &flags); | 1492 | &flags); |
1373 | err = rdev->ops->add_virtual_intf(&rdev->wiphy, | 1493 | dev = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1374 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1494 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1375 | type, err ? NULL : &flags, ¶ms); | 1495 | type, err ? NULL : &flags, ¶ms); |
1496 | if (IS_ERR(dev)) | ||
1497 | return PTR_ERR(dev); | ||
1376 | 1498 | ||
1377 | return err; | 1499 | if (type == NL80211_IFTYPE_MESH_POINT && |
1500 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
1501 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1502 | |||
1503 | wdev_lock(wdev); | ||
1504 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | ||
1505 | IEEE80211_MAX_MESH_ID_LEN); | ||
1506 | wdev->mesh_id_up_len = | ||
1507 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1508 | memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
1509 | wdev->mesh_id_up_len); | ||
1510 | wdev_unlock(wdev); | ||
1511 | } | ||
1512 | |||
1513 | return 0; | ||
1378 | } | 1514 | } |
1379 | 1515 | ||
1380 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1516 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
@@ -1519,8 +1655,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1519 | struct key_parse key; | 1655 | struct key_parse key; |
1520 | int err; | 1656 | int err; |
1521 | struct net_device *dev = info->user_ptr[1]; | 1657 | struct net_device *dev = info->user_ptr[1]; |
1522 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | ||
1523 | u8 key_index); | ||
1524 | 1658 | ||
1525 | err = nl80211_parse_key(info, &key); | 1659 | err = nl80211_parse_key(info, &key); |
1526 | if (err) | 1660 | if (err) |
@@ -1533,27 +1667,61 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1533 | if (!key.def && !key.defmgmt) | 1667 | if (!key.def && !key.defmgmt) |
1534 | return -EINVAL; | 1668 | return -EINVAL; |
1535 | 1669 | ||
1536 | if (key.def) | 1670 | wdev_lock(dev->ieee80211_ptr); |
1537 | func = rdev->ops->set_default_key; | ||
1538 | else | ||
1539 | func = rdev->ops->set_default_mgmt_key; | ||
1540 | 1671 | ||
1541 | if (!func) | 1672 | if (key.def) { |
1542 | return -EOPNOTSUPP; | 1673 | if (!rdev->ops->set_default_key) { |
1674 | err = -EOPNOTSUPP; | ||
1675 | goto out; | ||
1676 | } | ||
1543 | 1677 | ||
1544 | wdev_lock(dev->ieee80211_ptr); | 1678 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1545 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1679 | if (err) |
1546 | if (!err) | 1680 | goto out; |
1547 | err = func(&rdev->wiphy, dev, key.idx); | 1681 | |
1682 | if (!(rdev->wiphy.flags & | ||
1683 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) { | ||
1684 | if (!key.def_uni || !key.def_multi) { | ||
1685 | err = -EOPNOTSUPP; | ||
1686 | goto out; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, | ||
1691 | key.def_uni, key.def_multi); | ||
1692 | |||
1693 | if (err) | ||
1694 | goto out; | ||
1548 | 1695 | ||
1549 | #ifdef CONFIG_CFG80211_WEXT | 1696 | #ifdef CONFIG_CFG80211_WEXT |
1550 | if (!err) { | 1697 | dev->ieee80211_ptr->wext.default_key = key.idx; |
1551 | if (func == rdev->ops->set_default_key) | 1698 | #endif |
1552 | dev->ieee80211_ptr->wext.default_key = key.idx; | 1699 | } else { |
1553 | else | 1700 | if (key.def_uni || !key.def_multi) { |
1554 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | 1701 | err = -EINVAL; |
1555 | } | 1702 | goto out; |
1703 | } | ||
1704 | |||
1705 | if (!rdev->ops->set_default_mgmt_key) { | ||
1706 | err = -EOPNOTSUPP; | ||
1707 | goto out; | ||
1708 | } | ||
1709 | |||
1710 | err = nl80211_key_allowed(dev->ieee80211_ptr); | ||
1711 | if (err) | ||
1712 | goto out; | ||
1713 | |||
1714 | err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, | ||
1715 | dev, key.idx); | ||
1716 | if (err) | ||
1717 | goto out; | ||
1718 | |||
1719 | #ifdef CONFIG_CFG80211_WEXT | ||
1720 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | ||
1556 | #endif | 1721 | #endif |
1722 | } | ||
1723 | |||
1724 | out: | ||
1557 | wdev_unlock(dev->ieee80211_ptr); | 1725 | wdev_unlock(dev->ieee80211_ptr); |
1558 | 1726 | ||
1559 | return err; | 1727 | return err; |
@@ -1841,6 +2009,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1841 | if (sinfo->filled & STATION_INFO_SIGNAL) | 2009 | if (sinfo->filled & STATION_INFO_SIGNAL) |
1842 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, | 2010 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, |
1843 | sinfo->signal); | 2011 | sinfo->signal); |
2012 | if (sinfo->filled & STATION_INFO_SIGNAL_AVG) | ||
2013 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, | ||
2014 | sinfo->signal_avg); | ||
1844 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 2015 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { |
1845 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); | 2016 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); |
1846 | if (!txrate) | 2017 | if (!txrate) |
@@ -2404,6 +2575,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2404 | params.use_short_preamble = -1; | 2575 | params.use_short_preamble = -1; |
2405 | params.use_short_slot_time = -1; | 2576 | params.use_short_slot_time = -1; |
2406 | params.ap_isolate = -1; | 2577 | params.ap_isolate = -1; |
2578 | params.ht_opmode = -1; | ||
2407 | 2579 | ||
2408 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) | 2580 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) |
2409 | params.use_cts_prot = | 2581 | params.use_cts_prot = |
@@ -2422,6 +2594,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2422 | } | 2594 | } |
2423 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) | 2595 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) |
2424 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); | 2596 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); |
2597 | if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE]) | ||
2598 | params.ht_opmode = | ||
2599 | nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); | ||
2425 | 2600 | ||
2426 | if (!rdev->ops->change_bss) | 2601 | if (!rdev->ops->change_bss) |
2427 | return -EOPNOTSUPP; | 2602 | return -EOPNOTSUPP; |
@@ -2506,22 +2681,33 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2506 | return r; | 2681 | return r; |
2507 | } | 2682 | } |
2508 | 2683 | ||
2509 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2684 | static int nl80211_get_mesh_config(struct sk_buff *skb, |
2510 | struct genl_info *info) | 2685 | struct genl_info *info) |
2511 | { | 2686 | { |
2512 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2687 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2513 | struct mesh_config cur_params; | ||
2514 | int err; | ||
2515 | struct net_device *dev = info->user_ptr[1]; | 2688 | struct net_device *dev = info->user_ptr[1]; |
2689 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2690 | struct mesh_config cur_params; | ||
2691 | int err = 0; | ||
2516 | void *hdr; | 2692 | void *hdr; |
2517 | struct nlattr *pinfoattr; | 2693 | struct nlattr *pinfoattr; |
2518 | struct sk_buff *msg; | 2694 | struct sk_buff *msg; |
2519 | 2695 | ||
2520 | if (!rdev->ops->get_mesh_params) | 2696 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) |
2521 | return -EOPNOTSUPP; | 2697 | return -EOPNOTSUPP; |
2522 | 2698 | ||
2523 | /* Get the mesh params */ | 2699 | if (!rdev->ops->get_mesh_config) |
2524 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2700 | return -EOPNOTSUPP; |
2701 | |||
2702 | wdev_lock(wdev); | ||
2703 | /* If not connected, get default parameters */ | ||
2704 | if (!wdev->mesh_id_len) | ||
2705 | memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); | ||
2706 | else | ||
2707 | err = rdev->ops->get_mesh_config(&rdev->wiphy, dev, | ||
2708 | &cur_params); | ||
2709 | wdev_unlock(wdev); | ||
2710 | |||
2525 | if (err) | 2711 | if (err) |
2526 | return err; | 2712 | return err; |
2527 | 2713 | ||
@@ -2530,10 +2716,10 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2530 | if (!msg) | 2716 | if (!msg) |
2531 | return -ENOMEM; | 2717 | return -ENOMEM; |
2532 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 2718 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
2533 | NL80211_CMD_GET_MESH_PARAMS); | 2719 | NL80211_CMD_GET_MESH_CONFIG); |
2534 | if (!hdr) | 2720 | if (!hdr) |
2535 | goto nla_put_failure; | 2721 | goto nla_put_failure; |
2536 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); | 2722 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); |
2537 | if (!pinfoattr) | 2723 | if (!pinfoattr) |
2538 | goto nla_put_failure; | 2724 | goto nla_put_failure; |
2539 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 2725 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
@@ -2549,6 +2735,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2549 | cur_params.dot11MeshMaxRetries); | 2735 | cur_params.dot11MeshMaxRetries); |
2550 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, | 2736 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, |
2551 | cur_params.dot11MeshTTL); | 2737 | cur_params.dot11MeshTTL); |
2738 | NLA_PUT_U8(msg, NL80211_MESHCONF_ELEMENT_TTL, | ||
2739 | cur_params.element_ttl); | ||
2552 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, | 2740 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
2553 | cur_params.auto_open_plinks); | 2741 | cur_params.auto_open_plinks); |
2554 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 2742 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
@@ -2575,14 +2763,6 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2575 | return -ENOBUFS; | 2763 | return -ENOBUFS; |
2576 | } | 2764 | } |
2577 | 2765 | ||
2578 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | ||
2579 | do {\ | ||
2580 | if (table[attr_num]) {\ | ||
2581 | cfg.param = nla_fn(table[attr_num]); \ | ||
2582 | mask |= (1 << (attr_num - 1)); \ | ||
2583 | } \ | ||
2584 | } while (0);\ | ||
2585 | |||
2586 | static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { | 2766 | static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { |
2587 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, | 2767 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, |
2588 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, | 2768 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, |
@@ -2590,6 +2770,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2590 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, | 2770 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, |
2591 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, | 2771 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, |
2592 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, | 2772 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, |
2773 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, | ||
2593 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 2774 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
2594 | 2775 | ||
2595 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 2776 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
@@ -2600,31 +2781,42 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2600 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, | 2781 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, |
2601 | }; | 2782 | }; |
2602 | 2783 | ||
2603 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2784 | static const struct nla_policy |
2785 | nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { | ||
2786 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | ||
2787 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | ||
2788 | [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY, | ||
2789 | .len = IEEE80211_MAX_DATA_LEN }, | ||
2790 | }; | ||
2791 | |||
2792 | static int nl80211_parse_mesh_config(struct genl_info *info, | ||
2793 | struct mesh_config *cfg, | ||
2794 | u32 *mask_out) | ||
2604 | { | 2795 | { |
2605 | u32 mask; | ||
2606 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
2607 | struct net_device *dev = info->user_ptr[1]; | ||
2608 | struct mesh_config cfg; | ||
2609 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2796 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2610 | struct nlattr *parent_attr; | 2797 | u32 mask = 0; |
2611 | 2798 | ||
2612 | parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; | 2799 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ |
2613 | if (!parent_attr) | 2800 | do {\ |
2801 | if (table[attr_num]) {\ | ||
2802 | cfg->param = nla_fn(table[attr_num]); \ | ||
2803 | mask |= (1 << (attr_num - 1)); \ | ||
2804 | } \ | ||
2805 | } while (0);\ | ||
2806 | |||
2807 | |||
2808 | if (!info->attrs[NL80211_ATTR_MESH_CONFIG]) | ||
2614 | return -EINVAL; | 2809 | return -EINVAL; |
2615 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, | 2810 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, |
2616 | parent_attr, nl80211_meshconf_params_policy)) | 2811 | info->attrs[NL80211_ATTR_MESH_CONFIG], |
2812 | nl80211_meshconf_params_policy)) | ||
2617 | return -EINVAL; | 2813 | return -EINVAL; |
2618 | 2814 | ||
2619 | if (!rdev->ops->set_mesh_params) | ||
2620 | return -EOPNOTSUPP; | ||
2621 | |||
2622 | /* This makes sure that there aren't more than 32 mesh config | 2815 | /* This makes sure that there aren't more than 32 mesh config |
2623 | * parameters (otherwise our bitfield scheme would not work.) */ | 2816 | * parameters (otherwise our bitfield scheme would not work.) */ |
2624 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); | 2817 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); |
2625 | 2818 | ||
2626 | /* Fill in the params struct */ | 2819 | /* Fill in the params struct */ |
2627 | mask = 0; | ||
2628 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 2820 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
2629 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 2821 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); |
2630 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 2822 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
@@ -2637,6 +2829,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2637 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 2829 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); |
2638 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 2830 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
2639 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 2831 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
2832 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, | ||
2833 | mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); | ||
2640 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 2834 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
2641 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 2835 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); |
2642 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 2836 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
@@ -2661,12 +2855,82 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2661 | dot11MeshHWMPRootMode, mask, | 2855 | dot11MeshHWMPRootMode, mask, |
2662 | NL80211_MESHCONF_HWMP_ROOTMODE, | 2856 | NL80211_MESHCONF_HWMP_ROOTMODE, |
2663 | nla_get_u8); | 2857 | nla_get_u8); |
2858 | if (mask_out) | ||
2859 | *mask_out = mask; | ||
2664 | 2860 | ||
2665 | /* Apply changes */ | 2861 | return 0; |
2666 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | ||
2667 | } | ||
2668 | 2862 | ||
2669 | #undef FILL_IN_MESH_PARAM_IF_SET | 2863 | #undef FILL_IN_MESH_PARAM_IF_SET |
2864 | } | ||
2865 | |||
2866 | static int nl80211_parse_mesh_setup(struct genl_info *info, | ||
2867 | struct mesh_setup *setup) | ||
2868 | { | ||
2869 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; | ||
2870 | |||
2871 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) | ||
2872 | return -EINVAL; | ||
2873 | if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX, | ||
2874 | info->attrs[NL80211_ATTR_MESH_SETUP], | ||
2875 | nl80211_mesh_setup_params_policy)) | ||
2876 | return -EINVAL; | ||
2877 | |||
2878 | if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL]) | ||
2879 | setup->path_sel_proto = | ||
2880 | (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ? | ||
2881 | IEEE80211_PATH_PROTOCOL_VENDOR : | ||
2882 | IEEE80211_PATH_PROTOCOL_HWMP; | ||
2883 | |||
2884 | if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC]) | ||
2885 | setup->path_metric = | ||
2886 | (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ? | ||
2887 | IEEE80211_PATH_METRIC_VENDOR : | ||
2888 | IEEE80211_PATH_METRIC_AIRTIME; | ||
2889 | |||
2890 | if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) { | ||
2891 | struct nlattr *ieattr = | ||
2892 | tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]; | ||
2893 | if (!is_valid_ie_attr(ieattr)) | ||
2894 | return -EINVAL; | ||
2895 | setup->vendor_ie = nla_data(ieattr); | ||
2896 | setup->vendor_ie_len = nla_len(ieattr); | ||
2897 | } | ||
2898 | |||
2899 | return 0; | ||
2900 | } | ||
2901 | |||
2902 | static int nl80211_update_mesh_config(struct sk_buff *skb, | ||
2903 | struct genl_info *info) | ||
2904 | { | ||
2905 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
2906 | struct net_device *dev = info->user_ptr[1]; | ||
2907 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2908 | struct mesh_config cfg; | ||
2909 | u32 mask; | ||
2910 | int err; | ||
2911 | |||
2912 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | ||
2913 | return -EOPNOTSUPP; | ||
2914 | |||
2915 | if (!rdev->ops->update_mesh_config) | ||
2916 | return -EOPNOTSUPP; | ||
2917 | |||
2918 | err = nl80211_parse_mesh_config(info, &cfg, &mask); | ||
2919 | if (err) | ||
2920 | return err; | ||
2921 | |||
2922 | wdev_lock(wdev); | ||
2923 | if (!wdev->mesh_id_len) | ||
2924 | err = -ENOLINK; | ||
2925 | |||
2926 | if (!err) | ||
2927 | err = rdev->ops->update_mesh_config(&rdev->wiphy, dev, | ||
2928 | mask, &cfg); | ||
2929 | |||
2930 | wdev_unlock(wdev); | ||
2931 | |||
2932 | return err; | ||
2933 | } | ||
2670 | 2934 | ||
2671 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 2935 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) |
2672 | { | 2936 | { |
@@ -3569,6 +3833,34 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
3569 | local_state_change); | 3833 | local_state_change); |
3570 | } | 3834 | } |
3571 | 3835 | ||
3836 | static bool | ||
3837 | nl80211_parse_mcast_rate(struct cfg80211_registered_device *rdev, | ||
3838 | int mcast_rate[IEEE80211_NUM_BANDS], | ||
3839 | int rateval) | ||
3840 | { | ||
3841 | struct wiphy *wiphy = &rdev->wiphy; | ||
3842 | bool found = false; | ||
3843 | int band, i; | ||
3844 | |||
3845 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
3846 | struct ieee80211_supported_band *sband; | ||
3847 | |||
3848 | sband = wiphy->bands[band]; | ||
3849 | if (!sband) | ||
3850 | continue; | ||
3851 | |||
3852 | for (i = 0; i < sband->n_bitrates; i++) { | ||
3853 | if (sband->bitrates[i].bitrate == rateval) { | ||
3854 | mcast_rate[band] = i + 1; | ||
3855 | found = true; | ||
3856 | break; | ||
3857 | } | ||
3858 | } | ||
3859 | } | ||
3860 | |||
3861 | return found; | ||
3862 | } | ||
3863 | |||
3572 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | 3864 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) |
3573 | { | 3865 | { |
3574 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3866 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -3653,6 +3945,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
3653 | } | 3945 | } |
3654 | } | 3946 | } |
3655 | 3947 | ||
3948 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && | ||
3949 | !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate, | ||
3950 | nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) | ||
3951 | return -EINVAL; | ||
3952 | |||
3656 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { | 3953 | if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) { |
3657 | connkeys = nl80211_parse_connkeys(rdev, | 3954 | connkeys = nl80211_parse_connkeys(rdev, |
3658 | info->attrs[NL80211_ATTR_KEYS]); | 3955 | info->attrs[NL80211_ATTR_KEYS]); |
@@ -3987,7 +4284,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
3987 | * We should be on that channel for at least one jiffie, | 4284 | * We should be on that channel for at least one jiffie, |
3988 | * and more than 5 seconds seems excessive. | 4285 | * and more than 5 seconds seems excessive. |
3989 | */ | 4286 | */ |
3990 | if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | 4287 | if (!duration || !msecs_to_jiffies(duration) || |
4288 | duration > rdev->wiphy.max_remain_on_channel_duration) | ||
3991 | return -EINVAL; | 4289 | return -EINVAL; |
3992 | 4290 | ||
3993 | if (!rdev->ops->remain_on_channel) | 4291 | if (!rdev->ops->remain_on_channel) |
@@ -4155,6 +4453,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4155 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 4453 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4156 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 4454 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4157 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 4455 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4456 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | ||
4158 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 4457 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4159 | return -EOPNOTSUPP; | 4458 | return -EOPNOTSUPP; |
4160 | 4459 | ||
@@ -4180,6 +4479,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4180 | void *hdr; | 4479 | void *hdr; |
4181 | u64 cookie; | 4480 | u64 cookie; |
4182 | struct sk_buff *msg; | 4481 | struct sk_buff *msg; |
4482 | unsigned int wait = 0; | ||
4483 | bool offchan; | ||
4183 | 4484 | ||
4184 | if (!info->attrs[NL80211_ATTR_FRAME] || | 4485 | if (!info->attrs[NL80211_ATTR_FRAME] || |
4185 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 4486 | !info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
@@ -4193,9 +4494,16 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4193 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 4494 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && |
4194 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 4495 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4195 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 4496 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
4497 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | ||
4196 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 4498 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4197 | return -EOPNOTSUPP; | 4499 | return -EOPNOTSUPP; |
4198 | 4500 | ||
4501 | if (info->attrs[NL80211_ATTR_DURATION]) { | ||
4502 | if (!rdev->ops->mgmt_tx_cancel_wait) | ||
4503 | return -EINVAL; | ||
4504 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | ||
4505 | } | ||
4506 | |||
4199 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 4507 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
4200 | channel_type = nla_get_u32( | 4508 | channel_type = nla_get_u32( |
4201 | info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | 4509 | info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); |
@@ -4207,6 +4515,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4207 | channel_type_valid = true; | 4515 | channel_type_valid = true; |
4208 | } | 4516 | } |
4209 | 4517 | ||
4518 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; | ||
4519 | |||
4210 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4520 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
4211 | chan = rdev_freq_to_chan(rdev, freq, channel_type); | 4521 | chan = rdev_freq_to_chan(rdev, freq, channel_type); |
4212 | if (chan == NULL) | 4522 | if (chan == NULL) |
@@ -4223,8 +4533,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4223 | err = PTR_ERR(hdr); | 4533 | err = PTR_ERR(hdr); |
4224 | goto free_msg; | 4534 | goto free_msg; |
4225 | } | 4535 | } |
4226 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type, | 4536 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, |
4227 | channel_type_valid, | 4537 | channel_type_valid, wait, |
4228 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4538 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
4229 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4539 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
4230 | &cookie); | 4540 | &cookie); |
@@ -4243,6 +4553,31 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
4243 | return err; | 4553 | return err; |
4244 | } | 4554 | } |
4245 | 4555 | ||
4556 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) | ||
4557 | { | ||
4558 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4559 | struct net_device *dev = info->user_ptr[1]; | ||
4560 | u64 cookie; | ||
4561 | |||
4562 | if (!info->attrs[NL80211_ATTR_COOKIE]) | ||
4563 | return -EINVAL; | ||
4564 | |||
4565 | if (!rdev->ops->mgmt_tx_cancel_wait) | ||
4566 | return -EOPNOTSUPP; | ||
4567 | |||
4568 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | ||
4569 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | ||
4570 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | ||
4571 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
4572 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | ||
4573 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
4574 | return -EOPNOTSUPP; | ||
4575 | |||
4576 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | ||
4577 | |||
4578 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); | ||
4579 | } | ||
4580 | |||
4246 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 4581 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
4247 | { | 4582 | { |
4248 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4583 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -4381,6 +4716,50 @@ out: | |||
4381 | return err; | 4716 | return err; |
4382 | } | 4717 | } |
4383 | 4718 | ||
4719 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | ||
4720 | { | ||
4721 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4722 | struct net_device *dev = info->user_ptr[1]; | ||
4723 | struct mesh_config cfg; | ||
4724 | struct mesh_setup setup; | ||
4725 | int err; | ||
4726 | |||
4727 | /* start with default */ | ||
4728 | memcpy(&cfg, &default_mesh_config, sizeof(cfg)); | ||
4729 | memcpy(&setup, &default_mesh_setup, sizeof(setup)); | ||
4730 | |||
4731 | if (info->attrs[NL80211_ATTR_MESH_CONFIG]) { | ||
4732 | /* and parse parameters if given */ | ||
4733 | err = nl80211_parse_mesh_config(info, &cfg, NULL); | ||
4734 | if (err) | ||
4735 | return err; | ||
4736 | } | ||
4737 | |||
4738 | if (!info->attrs[NL80211_ATTR_MESH_ID] || | ||
4739 | !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) | ||
4740 | return -EINVAL; | ||
4741 | |||
4742 | setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
4743 | setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
4744 | |||
4745 | if (info->attrs[NL80211_ATTR_MESH_SETUP]) { | ||
4746 | /* parse additional setup parameters if given */ | ||
4747 | err = nl80211_parse_mesh_setup(info, &setup); | ||
4748 | if (err) | ||
4749 | return err; | ||
4750 | } | ||
4751 | |||
4752 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | ||
4753 | } | ||
4754 | |||
4755 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | ||
4756 | { | ||
4757 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4758 | struct net_device *dev = info->user_ptr[1]; | ||
4759 | |||
4760 | return cfg80211_leave_mesh(rdev, dev); | ||
4761 | } | ||
4762 | |||
4384 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 4763 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
4385 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 4764 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
4386 | #define NL80211_FLAG_NEED_RTNL 0x04 | 4765 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -4636,19 +5015,19 @@ static struct genl_ops nl80211_ops[] = { | |||
4636 | .flags = GENL_ADMIN_PERM, | 5015 | .flags = GENL_ADMIN_PERM, |
4637 | }, | 5016 | }, |
4638 | { | 5017 | { |
4639 | .cmd = NL80211_CMD_GET_MESH_PARAMS, | 5018 | .cmd = NL80211_CMD_GET_MESH_CONFIG, |
4640 | .doit = nl80211_get_mesh_params, | 5019 | .doit = nl80211_get_mesh_config, |
4641 | .policy = nl80211_policy, | 5020 | .policy = nl80211_policy, |
4642 | /* can be retrieved by unprivileged users */ | 5021 | /* can be retrieved by unprivileged users */ |
4643 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 5022 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
4644 | NL80211_FLAG_NEED_RTNL, | 5023 | NL80211_FLAG_NEED_RTNL, |
4645 | }, | 5024 | }, |
4646 | { | 5025 | { |
4647 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 5026 | .cmd = NL80211_CMD_SET_MESH_CONFIG, |
4648 | .doit = nl80211_set_mesh_params, | 5027 | .doit = nl80211_update_mesh_config, |
4649 | .policy = nl80211_policy, | 5028 | .policy = nl80211_policy, |
4650 | .flags = GENL_ADMIN_PERM, | 5029 | .flags = GENL_ADMIN_PERM, |
4651 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 5030 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
4652 | NL80211_FLAG_NEED_RTNL, | 5031 | NL80211_FLAG_NEED_RTNL, |
4653 | }, | 5032 | }, |
4654 | { | 5033 | { |
@@ -4816,6 +5195,14 @@ static struct genl_ops nl80211_ops[] = { | |||
4816 | NL80211_FLAG_NEED_RTNL, | 5195 | NL80211_FLAG_NEED_RTNL, |
4817 | }, | 5196 | }, |
4818 | { | 5197 | { |
5198 | .cmd = NL80211_CMD_FRAME_WAIT_CANCEL, | ||
5199 | .doit = nl80211_tx_mgmt_cancel_wait, | ||
5200 | .policy = nl80211_policy, | ||
5201 | .flags = GENL_ADMIN_PERM, | ||
5202 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5203 | NL80211_FLAG_NEED_RTNL, | ||
5204 | }, | ||
5205 | { | ||
4819 | .cmd = NL80211_CMD_SET_POWER_SAVE, | 5206 | .cmd = NL80211_CMD_SET_POWER_SAVE, |
4820 | .doit = nl80211_set_power_save, | 5207 | .doit = nl80211_set_power_save, |
4821 | .policy = nl80211_policy, | 5208 | .policy = nl80211_policy, |
@@ -4855,6 +5242,22 @@ static struct genl_ops nl80211_ops[] = { | |||
4855 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 5242 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
4856 | NL80211_FLAG_NEED_RTNL, | 5243 | NL80211_FLAG_NEED_RTNL, |
4857 | }, | 5244 | }, |
5245 | { | ||
5246 | .cmd = NL80211_CMD_JOIN_MESH, | ||
5247 | .doit = nl80211_join_mesh, | ||
5248 | .policy = nl80211_policy, | ||
5249 | .flags = GENL_ADMIN_PERM, | ||
5250 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5251 | NL80211_FLAG_NEED_RTNL, | ||
5252 | }, | ||
5253 | { | ||
5254 | .cmd = NL80211_CMD_LEAVE_MESH, | ||
5255 | .doit = nl80211_leave_mesh, | ||
5256 | .policy = nl80211_policy, | ||
5257 | .flags = GENL_ADMIN_PERM, | ||
5258 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5259 | NL80211_FLAG_NEED_RTNL, | ||
5260 | }, | ||
4858 | }; | 5261 | }; |
4859 | 5262 | ||
4860 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5263 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -5133,6 +5536,22 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | |||
5133 | NL80211_CMD_DISASSOCIATE, gfp); | 5536 | NL80211_CMD_DISASSOCIATE, gfp); |
5134 | } | 5537 | } |
5135 | 5538 | ||
5539 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | ||
5540 | struct net_device *netdev, const u8 *buf, | ||
5541 | size_t len, gfp_t gfp) | ||
5542 | { | ||
5543 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
5544 | NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp); | ||
5545 | } | ||
5546 | |||
5547 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | ||
5548 | struct net_device *netdev, const u8 *buf, | ||
5549 | size_t len, gfp_t gfp) | ||
5550 | { | ||
5551 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
5552 | NL80211_CMD_UNPROT_DISASSOCIATE, gfp); | ||
5553 | } | ||
5554 | |||
5136 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 5555 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
5137 | struct net_device *netdev, int cmd, | 5556 | struct net_device *netdev, int cmd, |
5138 | const u8 *addr, gfp_t gfp) | 5557 | const u8 *addr, gfp_t gfp) |
@@ -5651,6 +6070,51 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
5651 | nlmsg_free(msg); | 6070 | nlmsg_free(msg); |
5652 | } | 6071 | } |
5653 | 6072 | ||
6073 | void | ||
6074 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | ||
6075 | struct net_device *netdev, const u8 *peer, | ||
6076 | u32 num_packets, gfp_t gfp) | ||
6077 | { | ||
6078 | struct sk_buff *msg; | ||
6079 | struct nlattr *pinfoattr; | ||
6080 | void *hdr; | ||
6081 | |||
6082 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
6083 | if (!msg) | ||
6084 | return; | ||
6085 | |||
6086 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
6087 | if (!hdr) { | ||
6088 | nlmsg_free(msg); | ||
6089 | return; | ||
6090 | } | ||
6091 | |||
6092 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
6093 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
6094 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer); | ||
6095 | |||
6096 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
6097 | if (!pinfoattr) | ||
6098 | goto nla_put_failure; | ||
6099 | |||
6100 | NLA_PUT_U32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets); | ||
6101 | |||
6102 | nla_nest_end(msg, pinfoattr); | ||
6103 | |||
6104 | if (genlmsg_end(msg, hdr) < 0) { | ||
6105 | nlmsg_free(msg); | ||
6106 | return; | ||
6107 | } | ||
6108 | |||
6109 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6110 | nl80211_mlme_mcgrp.id, gfp); | ||
6111 | return; | ||
6112 | |||
6113 | nla_put_failure: | ||
6114 | genlmsg_cancel(msg, hdr); | ||
6115 | nlmsg_free(msg); | ||
6116 | } | ||
6117 | |||
5654 | static int nl80211_netlink_notify(struct notifier_block * nb, | 6118 | static int nl80211_netlink_notify(struct notifier_block * nb, |
5655 | unsigned long state, | 6119 | unsigned long state, |
5656 | void *_notify) | 6120 | void *_notify) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 30d2f939150d..e3f7fa886966 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -25,6 +25,12 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev, | |||
25 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | 25 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
26 | struct net_device *netdev, | 26 | struct net_device *netdev, |
27 | const u8 *buf, size_t len, gfp_t gfp); | 27 | const u8 *buf, size_t len, gfp_t gfp); |
28 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | ||
29 | struct net_device *netdev, | ||
30 | const u8 *buf, size_t len, gfp_t gfp); | ||
31 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | ||
32 | struct net_device *netdev, | ||
33 | const u8 *buf, size_t len, gfp_t gfp); | ||
28 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | 34 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, |
29 | struct net_device *netdev, | 35 | struct net_device *netdev, |
30 | const u8 *addr, gfp_t gfp); | 36 | const u8 *addr, gfp_t gfp); |
@@ -87,5 +93,9 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
87 | struct net_device *netdev, | 93 | struct net_device *netdev, |
88 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 94 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
89 | gfp_t gfp); | 95 | gfp_t gfp); |
96 | void | ||
97 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | ||
98 | struct net_device *netdev, const u8 *peer, | ||
99 | u32 num_packets, gfp_t gfp); | ||
90 | 100 | ||
91 | #endif /* __NET_WIRELESS_NL80211_H */ | 101 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 4b9f8912526c..99d41831d76e 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -32,6 +32,9 @@ | |||
32 | * rely on some SHA1 checksum of the regdomain for example. | 32 | * rely on some SHA1 checksum of the regdomain for example. |
33 | * | 33 | * |
34 | */ | 34 | */ |
35 | |||
36 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
37 | |||
35 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
36 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
37 | #include <linux/list.h> | 40 | #include <linux/list.h> |
@@ -48,7 +51,7 @@ | |||
48 | #ifdef CONFIG_CFG80211_REG_DEBUG | 51 | #ifdef CONFIG_CFG80211_REG_DEBUG |
49 | #define REG_DBG_PRINT(format, args...) \ | 52 | #define REG_DBG_PRINT(format, args...) \ |
50 | do { \ | 53 | do { \ |
51 | printk(KERN_DEBUG format , ## args); \ | 54 | printk(KERN_DEBUG pr_fmt(format), ##args); \ |
52 | } while (0) | 55 | } while (0) |
53 | #else | 56 | #else |
54 | #define REG_DBG_PRINT(args...) | 57 | #define REG_DBG_PRINT(args...) |
@@ -96,6 +99,9 @@ struct reg_beacon { | |||
96 | struct ieee80211_channel chan; | 99 | struct ieee80211_channel chan; |
97 | }; | 100 | }; |
98 | 101 | ||
102 | static void reg_todo(struct work_struct *work); | ||
103 | static DECLARE_WORK(reg_work, reg_todo); | ||
104 | |||
99 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 105 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
100 | static const struct ieee80211_regdomain world_regdom = { | 106 | static const struct ieee80211_regdomain world_regdom = { |
101 | .n_reg_rules = 5, | 107 | .n_reg_rules = 5, |
@@ -367,11 +373,10 @@ static int call_crda(const char *alpha2) | |||
367 | }; | 373 | }; |
368 | 374 | ||
369 | if (!is_world_regdom((char *) alpha2)) | 375 | if (!is_world_regdom((char *) alpha2)) |
370 | printk(KERN_INFO "cfg80211: Calling CRDA for country: %c%c\n", | 376 | pr_info("Calling CRDA for country: %c%c\n", |
371 | alpha2[0], alpha2[1]); | 377 | alpha2[0], alpha2[1]); |
372 | else | 378 | else |
373 | printk(KERN_INFO "cfg80211: Calling CRDA to update world " | 379 | pr_info("Calling CRDA to update world regulatory domain\n"); |
374 | "regulatory domain\n"); | ||
375 | 380 | ||
376 | /* query internal regulatory database (if it exists) */ | 381 | /* query internal regulatory database (if it exists) */ |
377 | reg_regdb_query(alpha2); | 382 | reg_regdb_query(alpha2); |
@@ -656,7 +661,8 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
656 | * Follow the driver's regulatory domain, if present, unless a country | 661 | * Follow the driver's regulatory domain, if present, unless a country |
657 | * IE has been processed or a user wants to help complaince further | 662 | * IE has been processed or a user wants to help complaince further |
658 | */ | 663 | */ |
659 | if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | 664 | if (!custom_regd && |
665 | last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
660 | last_request->initiator != NL80211_REGDOM_SET_BY_USER && | 666 | last_request->initiator != NL80211_REGDOM_SET_BY_USER && |
661 | wiphy->regd) | 667 | wiphy->regd) |
662 | regd = wiphy->regd; | 668 | regd = wiphy->regd; |
@@ -711,6 +717,60 @@ int freq_reg_info(struct wiphy *wiphy, | |||
711 | } | 717 | } |
712 | EXPORT_SYMBOL(freq_reg_info); | 718 | EXPORT_SYMBOL(freq_reg_info); |
713 | 719 | ||
720 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
721 | static const char *reg_initiator_name(enum nl80211_reg_initiator initiator) | ||
722 | { | ||
723 | switch (initiator) { | ||
724 | case NL80211_REGDOM_SET_BY_CORE: | ||
725 | return "Set by core"; | ||
726 | case NL80211_REGDOM_SET_BY_USER: | ||
727 | return "Set by user"; | ||
728 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
729 | return "Set by driver"; | ||
730 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | ||
731 | return "Set by country IE"; | ||
732 | default: | ||
733 | WARN_ON(1); | ||
734 | return "Set by bug"; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, | ||
739 | u32 desired_bw_khz, | ||
740 | const struct ieee80211_reg_rule *reg_rule) | ||
741 | { | ||
742 | const struct ieee80211_power_rule *power_rule; | ||
743 | const struct ieee80211_freq_range *freq_range; | ||
744 | char max_antenna_gain[32]; | ||
745 | |||
746 | power_rule = ®_rule->power_rule; | ||
747 | freq_range = ®_rule->freq_range; | ||
748 | |||
749 | if (!power_rule->max_antenna_gain) | ||
750 | snprintf(max_antenna_gain, 32, "N/A"); | ||
751 | else | ||
752 | snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); | ||
753 | |||
754 | REG_DBG_PRINT("Updating information on frequency %d MHz " | ||
755 | "for %d a MHz width channel with regulatory rule:\n", | ||
756 | chan->center_freq, | ||
757 | KHZ_TO_MHZ(desired_bw_khz)); | ||
758 | |||
759 | REG_DBG_PRINT("%d KHz - %d KHz @ KHz), (%s mBi, %d mBm)\n", | ||
760 | freq_range->start_freq_khz, | ||
761 | freq_range->end_freq_khz, | ||
762 | max_antenna_gain, | ||
763 | power_rule->max_eirp); | ||
764 | } | ||
765 | #else | ||
766 | static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, | ||
767 | u32 desired_bw_khz, | ||
768 | const struct ieee80211_reg_rule *reg_rule) | ||
769 | { | ||
770 | return; | ||
771 | } | ||
772 | #endif | ||
773 | |||
714 | /* | 774 | /* |
715 | * Note that right now we assume the desired channel bandwidth | 775 | * Note that right now we assume the desired channel bandwidth |
716 | * is always 20 MHz for each individual channel (HT40 uses 20 MHz | 776 | * is always 20 MHz for each individual channel (HT40 uses 20 MHz |
@@ -720,7 +780,9 @@ EXPORT_SYMBOL(freq_reg_info); | |||
720 | * on the wiphy with the target_bw specified. Then we can simply use | 780 | * on the wiphy with the target_bw specified. Then we can simply use |
721 | * that below for the desired_bw_khz below. | 781 | * that below for the desired_bw_khz below. |
722 | */ | 782 | */ |
723 | static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | 783 | static void handle_channel(struct wiphy *wiphy, |
784 | enum nl80211_reg_initiator initiator, | ||
785 | enum ieee80211_band band, | ||
724 | unsigned int chan_idx) | 786 | unsigned int chan_idx) |
725 | { | 787 | { |
726 | int r; | 788 | int r; |
@@ -748,8 +810,27 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
748 | desired_bw_khz, | 810 | desired_bw_khz, |
749 | ®_rule); | 811 | ®_rule); |
750 | 812 | ||
751 | if (r) | 813 | if (r) { |
814 | /* | ||
815 | * We will disable all channels that do not match our | ||
816 | * recieved regulatory rule unless the hint is coming | ||
817 | * from a Country IE and the Country IE had no information | ||
818 | * about a band. The IEEE 802.11 spec allows for an AP | ||
819 | * to send only a subset of the regulatory rules allowed, | ||
820 | * so an AP in the US that only supports 2.4 GHz may only send | ||
821 | * a country IE with information for the 2.4 GHz band | ||
822 | * while 5 GHz is still supported. | ||
823 | */ | ||
824 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
825 | r == -ERANGE) | ||
826 | return; | ||
827 | |||
828 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); | ||
829 | chan->flags = IEEE80211_CHAN_DISABLED; | ||
752 | return; | 830 | return; |
831 | } | ||
832 | |||
833 | chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule); | ||
753 | 834 | ||
754 | power_rule = ®_rule->power_rule; | 835 | power_rule = ®_rule->power_rule; |
755 | freq_range = ®_rule->freq_range; | 836 | freq_range = ®_rule->freq_range; |
@@ -784,7 +865,9 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
784 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 865 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
785 | } | 866 | } |
786 | 867 | ||
787 | static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) | 868 | static void handle_band(struct wiphy *wiphy, |
869 | enum ieee80211_band band, | ||
870 | enum nl80211_reg_initiator initiator) | ||
788 | { | 871 | { |
789 | unsigned int i; | 872 | unsigned int i; |
790 | struct ieee80211_supported_band *sband; | 873 | struct ieee80211_supported_band *sband; |
@@ -793,24 +876,42 @@ static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) | |||
793 | sband = wiphy->bands[band]; | 876 | sband = wiphy->bands[band]; |
794 | 877 | ||
795 | for (i = 0; i < sband->n_channels; i++) | 878 | for (i = 0; i < sband->n_channels; i++) |
796 | handle_channel(wiphy, band, i); | 879 | handle_channel(wiphy, initiator, band, i); |
797 | } | 880 | } |
798 | 881 | ||
799 | static bool ignore_reg_update(struct wiphy *wiphy, | 882 | static bool ignore_reg_update(struct wiphy *wiphy, |
800 | enum nl80211_reg_initiator initiator) | 883 | enum nl80211_reg_initiator initiator) |
801 | { | 884 | { |
802 | if (!last_request) | 885 | if (!last_request) { |
886 | REG_DBG_PRINT("Ignoring regulatory request %s since " | ||
887 | "last_request is not set\n", | ||
888 | reg_initiator_name(initiator)); | ||
803 | return true; | 889 | return true; |
890 | } | ||
891 | |||
804 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | 892 | if (initiator == NL80211_REGDOM_SET_BY_CORE && |
805 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) | 893 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { |
894 | REG_DBG_PRINT("Ignoring regulatory request %s " | ||
895 | "since the driver uses its own custom " | ||
896 | "regulatory domain ", | ||
897 | reg_initiator_name(initiator)); | ||
806 | return true; | 898 | return true; |
899 | } | ||
900 | |||
807 | /* | 901 | /* |
808 | * wiphy->regd will be set once the device has its own | 902 | * wiphy->regd will be set once the device has its own |
809 | * desired regulatory domain set | 903 | * desired regulatory domain set |
810 | */ | 904 | */ |
811 | if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && | 905 | if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && |
812 | !is_world_regdom(last_request->alpha2)) | 906 | initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && |
907 | !is_world_regdom(last_request->alpha2)) { | ||
908 | REG_DBG_PRINT("Ignoring regulatory request %s " | ||
909 | "since the driver requires its own regulaotry " | ||
910 | "domain to be set first", | ||
911 | reg_initiator_name(initiator)); | ||
813 | return true; | 912 | return true; |
913 | } | ||
914 | |||
814 | return false; | 915 | return false; |
815 | } | 916 | } |
816 | 917 | ||
@@ -1030,7 +1131,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1030 | goto out; | 1131 | goto out; |
1031 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1132 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1032 | if (wiphy->bands[band]) | 1133 | if (wiphy->bands[band]) |
1033 | handle_band(wiphy, band); | 1134 | handle_band(wiphy, band, initiator); |
1034 | } | 1135 | } |
1035 | out: | 1136 | out: |
1036 | reg_process_beacons(wiphy); | 1137 | reg_process_beacons(wiphy); |
@@ -1066,10 +1167,17 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1066 | regd); | 1167 | regd); |
1067 | 1168 | ||
1068 | if (r) { | 1169 | if (r) { |
1170 | REG_DBG_PRINT("Disabling freq %d MHz as custom " | ||
1171 | "regd has no rule that fits a %d MHz " | ||
1172 | "wide channel\n", | ||
1173 | chan->center_freq, | ||
1174 | KHZ_TO_MHZ(desired_bw_khz)); | ||
1069 | chan->flags = IEEE80211_CHAN_DISABLED; | 1175 | chan->flags = IEEE80211_CHAN_DISABLED; |
1070 | return; | 1176 | return; |
1071 | } | 1177 | } |
1072 | 1178 | ||
1179 | chan_reg_rule_print_dbg(chan, desired_bw_khz, reg_rule); | ||
1180 | |||
1073 | power_rule = ®_rule->power_rule; | 1181 | power_rule = ®_rule->power_rule; |
1074 | freq_range = ®_rule->freq_range; | 1182 | freq_range = ®_rule->freq_range; |
1075 | 1183 | ||
@@ -1215,6 +1323,21 @@ static int ignore_request(struct wiphy *wiphy, | |||
1215 | return -EINVAL; | 1323 | return -EINVAL; |
1216 | } | 1324 | } |
1217 | 1325 | ||
1326 | static void reg_set_request_processed(void) | ||
1327 | { | ||
1328 | bool need_more_processing = false; | ||
1329 | |||
1330 | last_request->processed = true; | ||
1331 | |||
1332 | spin_lock(®_requests_lock); | ||
1333 | if (!list_empty(®_requests_list)) | ||
1334 | need_more_processing = true; | ||
1335 | spin_unlock(®_requests_lock); | ||
1336 | |||
1337 | if (need_more_processing) | ||
1338 | schedule_work(®_work); | ||
1339 | } | ||
1340 | |||
1218 | /** | 1341 | /** |
1219 | * __regulatory_hint - hint to the wireless core a regulatory domain | 1342 | * __regulatory_hint - hint to the wireless core a regulatory domain |
1220 | * @wiphy: if the hint comes from country information from an AP, this | 1343 | * @wiphy: if the hint comes from country information from an AP, this |
@@ -1290,8 +1413,10 @@ new_request: | |||
1290 | * have applied the requested regulatory domain before we just | 1413 | * have applied the requested regulatory domain before we just |
1291 | * inform userspace we have processed the request | 1414 | * inform userspace we have processed the request |
1292 | */ | 1415 | */ |
1293 | if (r == -EALREADY) | 1416 | if (r == -EALREADY) { |
1294 | nl80211_send_reg_change_event(last_request); | 1417 | nl80211_send_reg_change_event(last_request); |
1418 | reg_set_request_processed(); | ||
1419 | } | ||
1295 | return r; | 1420 | return r; |
1296 | } | 1421 | } |
1297 | 1422 | ||
@@ -1307,16 +1432,13 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1307 | 1432 | ||
1308 | BUG_ON(!reg_request->alpha2); | 1433 | BUG_ON(!reg_request->alpha2); |
1309 | 1434 | ||
1310 | mutex_lock(&cfg80211_mutex); | ||
1311 | mutex_lock(®_mutex); | ||
1312 | |||
1313 | if (wiphy_idx_valid(reg_request->wiphy_idx)) | 1435 | if (wiphy_idx_valid(reg_request->wiphy_idx)) |
1314 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1436 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
1315 | 1437 | ||
1316 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1438 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
1317 | !wiphy) { | 1439 | !wiphy) { |
1318 | kfree(reg_request); | 1440 | kfree(reg_request); |
1319 | goto out; | 1441 | return; |
1320 | } | 1442 | } |
1321 | 1443 | ||
1322 | r = __regulatory_hint(wiphy, reg_request); | 1444 | r = __regulatory_hint(wiphy, reg_request); |
@@ -1324,28 +1446,46 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1324 | if (r == -EALREADY && wiphy && | 1446 | if (r == -EALREADY && wiphy && |
1325 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | 1447 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) |
1326 | wiphy_update_regulatory(wiphy, initiator); | 1448 | wiphy_update_regulatory(wiphy, initiator); |
1327 | out: | ||
1328 | mutex_unlock(®_mutex); | ||
1329 | mutex_unlock(&cfg80211_mutex); | ||
1330 | } | 1449 | } |
1331 | 1450 | ||
1332 | /* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */ | 1451 | /* |
1452 | * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* | ||
1453 | * Regulatory hints come on a first come first serve basis and we | ||
1454 | * must process each one atomically. | ||
1455 | */ | ||
1333 | static void reg_process_pending_hints(void) | 1456 | static void reg_process_pending_hints(void) |
1334 | { | 1457 | { |
1335 | struct regulatory_request *reg_request; | 1458 | struct regulatory_request *reg_request; |
1336 | 1459 | ||
1460 | mutex_lock(&cfg80211_mutex); | ||
1461 | mutex_lock(®_mutex); | ||
1462 | |||
1463 | /* When last_request->processed becomes true this will be rescheduled */ | ||
1464 | if (last_request && !last_request->processed) { | ||
1465 | REG_DBG_PRINT("Pending regulatory request, waiting " | ||
1466 | "for it to be processed..."); | ||
1467 | goto out; | ||
1468 | } | ||
1469 | |||
1337 | spin_lock(®_requests_lock); | 1470 | spin_lock(®_requests_lock); |
1338 | while (!list_empty(®_requests_list)) { | ||
1339 | reg_request = list_first_entry(®_requests_list, | ||
1340 | struct regulatory_request, | ||
1341 | list); | ||
1342 | list_del_init(®_request->list); | ||
1343 | 1471 | ||
1472 | if (list_empty(®_requests_list)) { | ||
1344 | spin_unlock(®_requests_lock); | 1473 | spin_unlock(®_requests_lock); |
1345 | reg_process_hint(reg_request); | 1474 | goto out; |
1346 | spin_lock(®_requests_lock); | ||
1347 | } | 1475 | } |
1476 | |||
1477 | reg_request = list_first_entry(®_requests_list, | ||
1478 | struct regulatory_request, | ||
1479 | list); | ||
1480 | list_del_init(®_request->list); | ||
1481 | |||
1348 | spin_unlock(®_requests_lock); | 1482 | spin_unlock(®_requests_lock); |
1483 | |||
1484 | reg_process_hint(reg_request); | ||
1485 | |||
1486 | out: | ||
1487 | mutex_unlock(®_mutex); | ||
1488 | mutex_unlock(&cfg80211_mutex); | ||
1349 | } | 1489 | } |
1350 | 1490 | ||
1351 | /* Processes beacon hints -- this has nothing to do with country IEs */ | 1491 | /* Processes beacon hints -- this has nothing to do with country IEs */ |
@@ -1392,8 +1532,6 @@ static void reg_todo(struct work_struct *work) | |||
1392 | reg_process_pending_beacon_hints(); | 1532 | reg_process_pending_beacon_hints(); |
1393 | } | 1533 | } |
1394 | 1534 | ||
1395 | static DECLARE_WORK(reg_work, reg_todo); | ||
1396 | |||
1397 | static void queue_regulatory_request(struct regulatory_request *request) | 1535 | static void queue_regulatory_request(struct regulatory_request *request) |
1398 | { | 1536 | { |
1399 | if (isalpha(request->alpha2[0])) | 1537 | if (isalpha(request->alpha2[0])) |
@@ -1428,12 +1566,7 @@ static int regulatory_hint_core(const char *alpha2) | |||
1428 | request->alpha2[1] = alpha2[1]; | 1566 | request->alpha2[1] = alpha2[1]; |
1429 | request->initiator = NL80211_REGDOM_SET_BY_CORE; | 1567 | request->initiator = NL80211_REGDOM_SET_BY_CORE; |
1430 | 1568 | ||
1431 | /* | 1569 | queue_regulatory_request(request); |
1432 | * This ensures last_request is populated once modules | ||
1433 | * come swinging in and calling regulatory hints and | ||
1434 | * wiphy_apply_custom_regulatory(). | ||
1435 | */ | ||
1436 | reg_process_hint(request); | ||
1437 | 1570 | ||
1438 | return 0; | 1571 | return 0; |
1439 | } | 1572 | } |
@@ -1559,7 +1692,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) | |||
1559 | if (is_user_regdom_saved()) { | 1692 | if (is_user_regdom_saved()) { |
1560 | /* Unless we're asked to ignore it and reset it */ | 1693 | /* Unless we're asked to ignore it and reset it */ |
1561 | if (reset_user) { | 1694 | if (reset_user) { |
1562 | REG_DBG_PRINT("cfg80211: Restoring regulatory settings " | 1695 | REG_DBG_PRINT("Restoring regulatory settings " |
1563 | "including user preference\n"); | 1696 | "including user preference\n"); |
1564 | user_alpha2[0] = '9'; | 1697 | user_alpha2[0] = '9'; |
1565 | user_alpha2[1] = '7'; | 1698 | user_alpha2[1] = '7'; |
@@ -1570,7 +1703,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) | |||
1570 | * back as they were for a full restore. | 1703 | * back as they were for a full restore. |
1571 | */ | 1704 | */ |
1572 | if (!is_world_regdom(ieee80211_regdom)) { | 1705 | if (!is_world_regdom(ieee80211_regdom)) { |
1573 | REG_DBG_PRINT("cfg80211: Keeping preference on " | 1706 | REG_DBG_PRINT("Keeping preference on " |
1574 | "module parameter ieee80211_regdom: %c%c\n", | 1707 | "module parameter ieee80211_regdom: %c%c\n", |
1575 | ieee80211_regdom[0], | 1708 | ieee80211_regdom[0], |
1576 | ieee80211_regdom[1]); | 1709 | ieee80211_regdom[1]); |
@@ -1578,7 +1711,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) | |||
1578 | alpha2[1] = ieee80211_regdom[1]; | 1711 | alpha2[1] = ieee80211_regdom[1]; |
1579 | } | 1712 | } |
1580 | } else { | 1713 | } else { |
1581 | REG_DBG_PRINT("cfg80211: Restoring regulatory settings " | 1714 | REG_DBG_PRINT("Restoring regulatory settings " |
1582 | "while preserving user preference for: %c%c\n", | 1715 | "while preserving user preference for: %c%c\n", |
1583 | user_alpha2[0], | 1716 | user_alpha2[0], |
1584 | user_alpha2[1]); | 1717 | user_alpha2[1]); |
@@ -1586,14 +1719,14 @@ static void restore_alpha2(char *alpha2, bool reset_user) | |||
1586 | alpha2[1] = user_alpha2[1]; | 1719 | alpha2[1] = user_alpha2[1]; |
1587 | } | 1720 | } |
1588 | } else if (!is_world_regdom(ieee80211_regdom)) { | 1721 | } else if (!is_world_regdom(ieee80211_regdom)) { |
1589 | REG_DBG_PRINT("cfg80211: Keeping preference on " | 1722 | REG_DBG_PRINT("Keeping preference on " |
1590 | "module parameter ieee80211_regdom: %c%c\n", | 1723 | "module parameter ieee80211_regdom: %c%c\n", |
1591 | ieee80211_regdom[0], | 1724 | ieee80211_regdom[0], |
1592 | ieee80211_regdom[1]); | 1725 | ieee80211_regdom[1]); |
1593 | alpha2[0] = ieee80211_regdom[0]; | 1726 | alpha2[0] = ieee80211_regdom[0]; |
1594 | alpha2[1] = ieee80211_regdom[1]; | 1727 | alpha2[1] = ieee80211_regdom[1]; |
1595 | } else | 1728 | } else |
1596 | REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n"); | 1729 | REG_DBG_PRINT("Restoring regulatory settings\n"); |
1597 | } | 1730 | } |
1598 | 1731 | ||
1599 | /* | 1732 | /* |
@@ -1661,7 +1794,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
1661 | 1794 | ||
1662 | void regulatory_hint_disconnect(void) | 1795 | void regulatory_hint_disconnect(void) |
1663 | { | 1796 | { |
1664 | REG_DBG_PRINT("cfg80211: All devices are disconnected, going to " | 1797 | REG_DBG_PRINT("All devices are disconnected, going to " |
1665 | "restore regulatory settings\n"); | 1798 | "restore regulatory settings\n"); |
1666 | restore_regulatory_settings(false); | 1799 | restore_regulatory_settings(false); |
1667 | } | 1800 | } |
@@ -1691,7 +1824,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
1691 | if (!reg_beacon) | 1824 | if (!reg_beacon) |
1692 | return -ENOMEM; | 1825 | return -ENOMEM; |
1693 | 1826 | ||
1694 | REG_DBG_PRINT("cfg80211: Found new beacon on " | 1827 | REG_DBG_PRINT("Found new beacon on " |
1695 | "frequency: %d MHz (Ch %d) on %s\n", | 1828 | "frequency: %d MHz (Ch %d) on %s\n", |
1696 | beacon_chan->center_freq, | 1829 | beacon_chan->center_freq, |
1697 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | 1830 | ieee80211_frequency_to_channel(beacon_chan->center_freq), |
@@ -1721,8 +1854,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1721 | const struct ieee80211_freq_range *freq_range = NULL; | 1854 | const struct ieee80211_freq_range *freq_range = NULL; |
1722 | const struct ieee80211_power_rule *power_rule = NULL; | 1855 | const struct ieee80211_power_rule *power_rule = NULL; |
1723 | 1856 | ||
1724 | printk(KERN_INFO " (start_freq - end_freq @ bandwidth), " | 1857 | pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); |
1725 | "(max_antenna_gain, max_eirp)\n"); | ||
1726 | 1858 | ||
1727 | for (i = 0; i < rd->n_reg_rules; i++) { | 1859 | for (i = 0; i < rd->n_reg_rules; i++) { |
1728 | reg_rule = &rd->reg_rules[i]; | 1860 | reg_rule = &rd->reg_rules[i]; |
@@ -1734,16 +1866,14 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1734 | * in certain regions | 1866 | * in certain regions |
1735 | */ | 1867 | */ |
1736 | if (power_rule->max_antenna_gain) | 1868 | if (power_rule->max_antenna_gain) |
1737 | printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), " | 1869 | pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", |
1738 | "(%d mBi, %d mBm)\n", | ||
1739 | freq_range->start_freq_khz, | 1870 | freq_range->start_freq_khz, |
1740 | freq_range->end_freq_khz, | 1871 | freq_range->end_freq_khz, |
1741 | freq_range->max_bandwidth_khz, | 1872 | freq_range->max_bandwidth_khz, |
1742 | power_rule->max_antenna_gain, | 1873 | power_rule->max_antenna_gain, |
1743 | power_rule->max_eirp); | 1874 | power_rule->max_eirp); |
1744 | else | 1875 | else |
1745 | printk(KERN_INFO " (%d KHz - %d KHz @ %d KHz), " | 1876 | pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", |
1746 | "(N/A, %d mBm)\n", | ||
1747 | freq_range->start_freq_khz, | 1877 | freq_range->start_freq_khz, |
1748 | freq_range->end_freq_khz, | 1878 | freq_range->end_freq_khz, |
1749 | freq_range->max_bandwidth_khz, | 1879 | freq_range->max_bandwidth_khz, |
@@ -1762,27 +1892,20 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1762 | rdev = cfg80211_rdev_by_wiphy_idx( | 1892 | rdev = cfg80211_rdev_by_wiphy_idx( |
1763 | last_request->wiphy_idx); | 1893 | last_request->wiphy_idx); |
1764 | if (rdev) { | 1894 | if (rdev) { |
1765 | printk(KERN_INFO "cfg80211: Current regulatory " | 1895 | pr_info("Current regulatory domain updated by AP to: %c%c\n", |
1766 | "domain updated by AP to: %c%c\n", | ||
1767 | rdev->country_ie_alpha2[0], | 1896 | rdev->country_ie_alpha2[0], |
1768 | rdev->country_ie_alpha2[1]); | 1897 | rdev->country_ie_alpha2[1]); |
1769 | } else | 1898 | } else |
1770 | printk(KERN_INFO "cfg80211: Current regulatory " | 1899 | pr_info("Current regulatory domain intersected:\n"); |
1771 | "domain intersected:\n"); | ||
1772 | } else | 1900 | } else |
1773 | printk(KERN_INFO "cfg80211: Current regulatory " | 1901 | pr_info("Current regulatory domain intersected:\n"); |
1774 | "domain intersected:\n"); | ||
1775 | } else if (is_world_regdom(rd->alpha2)) | 1902 | } else if (is_world_regdom(rd->alpha2)) |
1776 | printk(KERN_INFO "cfg80211: World regulatory " | 1903 | pr_info("World regulatory domain updated:\n"); |
1777 | "domain updated:\n"); | ||
1778 | else { | 1904 | else { |
1779 | if (is_unknown_alpha2(rd->alpha2)) | 1905 | if (is_unknown_alpha2(rd->alpha2)) |
1780 | printk(KERN_INFO "cfg80211: Regulatory domain " | 1906 | pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); |
1781 | "changed to driver built-in settings " | ||
1782 | "(unknown country)\n"); | ||
1783 | else | 1907 | else |
1784 | printk(KERN_INFO "cfg80211: Regulatory domain " | 1908 | pr_info("Regulatory domain changed to country: %c%c\n", |
1785 | "changed to country: %c%c\n", | ||
1786 | rd->alpha2[0], rd->alpha2[1]); | 1909 | rd->alpha2[0], rd->alpha2[1]); |
1787 | } | 1910 | } |
1788 | print_rd_rules(rd); | 1911 | print_rd_rules(rd); |
@@ -1790,8 +1913,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1790 | 1913 | ||
1791 | static void print_regdomain_info(const struct ieee80211_regdomain *rd) | 1914 | static void print_regdomain_info(const struct ieee80211_regdomain *rd) |
1792 | { | 1915 | { |
1793 | printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", | 1916 | pr_info("Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]); |
1794 | rd->alpha2[0], rd->alpha2[1]); | ||
1795 | print_rd_rules(rd); | 1917 | print_rd_rules(rd); |
1796 | } | 1918 | } |
1797 | 1919 | ||
@@ -1842,8 +1964,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1842 | return -EINVAL; | 1964 | return -EINVAL; |
1843 | 1965 | ||
1844 | if (!is_valid_rd(rd)) { | 1966 | if (!is_valid_rd(rd)) { |
1845 | printk(KERN_ERR "cfg80211: Invalid " | 1967 | pr_err("Invalid regulatory domain detected:\n"); |
1846 | "regulatory domain detected:\n"); | ||
1847 | print_regdomain_info(rd); | 1968 | print_regdomain_info(rd); |
1848 | return -EINVAL; | 1969 | return -EINVAL; |
1849 | } | 1970 | } |
@@ -1959,6 +2080,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
1959 | 2080 | ||
1960 | nl80211_send_reg_change_event(last_request); | 2081 | nl80211_send_reg_change_event(last_request); |
1961 | 2082 | ||
2083 | reg_set_request_processed(); | ||
2084 | |||
1962 | mutex_unlock(®_mutex); | 2085 | mutex_unlock(®_mutex); |
1963 | 2086 | ||
1964 | return r; | 2087 | return r; |
@@ -2015,8 +2138,7 @@ int __init regulatory_init(void) | |||
2015 | * early boot for call_usermodehelper(). For now treat these | 2138 | * early boot for call_usermodehelper(). For now treat these |
2016 | * errors as non-fatal. | 2139 | * errors as non-fatal. |
2017 | */ | 2140 | */ |
2018 | printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable " | 2141 | pr_err("kobject_uevent_env() was unable to call CRDA during init\n"); |
2019 | "to call CRDA during init"); | ||
2020 | #ifdef CONFIG_CFG80211_REG_DEBUG | 2142 | #ifdef CONFIG_CFG80211_REG_DEBUG |
2021 | /* We want to find out exactly why when debugging */ | 2143 | /* We want to find out exactly why when debugging */ |
2022 | WARN_ON(err); | 2144 | WARN_ON(err); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 503ebb86ba18..ea427f418f64 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -464,6 +464,9 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
464 | if (res->pub.beacon_ies) { | 464 | if (res->pub.beacon_ies) { |
465 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | 465 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); |
466 | size_t ielen = res->pub.len_beacon_ies; | 466 | size_t ielen = res->pub.len_beacon_ies; |
467 | bool information_elements_is_beacon_ies = | ||
468 | (found->pub.information_elements == | ||
469 | found->pub.beacon_ies); | ||
467 | 470 | ||
468 | if (found->pub.beacon_ies && | 471 | if (found->pub.beacon_ies && |
469 | !found->beacon_ies_allocated && | 472 | !found->beacon_ies_allocated && |
@@ -487,6 +490,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
487 | found->pub.len_beacon_ies = ielen; | 490 | found->pub.len_beacon_ies = ielen; |
488 | } | 491 | } |
489 | } | 492 | } |
493 | |||
494 | /* Override IEs if they were from a beacon before */ | ||
495 | if (information_elements_is_beacon_ies) { | ||
496 | found->pub.information_elements = | ||
497 | found->pub.beacon_ies; | ||
498 | found->pub.len_information_elements = | ||
499 | found->pub.len_beacon_ies; | ||
500 | } | ||
490 | } | 501 | } |
491 | 502 | ||
492 | kref_put(&res->ref, bss_release); | 503 | kref_put(&res->ref, bss_release); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 76120aeda57d..7620ae2fcf18 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -502,7 +502,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
502 | skb_orphan(skb); | 502 | skb_orphan(skb); |
503 | 503 | ||
504 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { | 504 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { |
505 | printk(KERN_ERR "failed to reallocate Tx buffer\n"); | 505 | pr_err("failed to reallocate Tx buffer\n"); |
506 | return -ENOMEM; | 506 | return -ENOMEM; |
507 | } | 507 | } |
508 | skb->truesize += head_need; | 508 | skb->truesize += head_need; |
@@ -685,20 +685,18 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
685 | continue; | 685 | continue; |
686 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, | 686 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, |
687 | &wdev->connect_keys->params[i])) { | 687 | &wdev->connect_keys->params[i])) { |
688 | printk(KERN_ERR "%s: failed to set key %d\n", | 688 | netdev_err(dev, "failed to set key %d\n", i); |
689 | dev->name, i); | ||
690 | continue; | 689 | continue; |
691 | } | 690 | } |
692 | if (wdev->connect_keys->def == i) | 691 | if (wdev->connect_keys->def == i) |
693 | if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { | 692 | if (rdev->ops->set_default_key(wdev->wiphy, dev, |
694 | printk(KERN_ERR "%s: failed to set defkey %d\n", | 693 | i, true, true)) { |
695 | dev->name, i); | 694 | netdev_err(dev, "failed to set defkey %d\n", i); |
696 | continue; | 695 | continue; |
697 | } | 696 | } |
698 | if (wdev->connect_keys->defmgmt == i) | 697 | if (wdev->connect_keys->defmgmt == i) |
699 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) | 698 | if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i)) |
700 | printk(KERN_ERR "%s: failed to set mgtdef %d\n", | 699 | netdev_err(dev, "failed to set mgtdef %d\n", i); |
701 | dev->name, i); | ||
702 | } | 700 | } |
703 | 701 | ||
704 | kfree(wdev->connect_keys); | 702 | kfree(wdev->connect_keys); |
@@ -795,6 +793,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
795 | 793 | ||
796 | if (ntype != otype) { | 794 | if (ntype != otype) { |
797 | dev->ieee80211_ptr->use_4addr = false; | 795 | dev->ieee80211_ptr->use_4addr = false; |
796 | dev->ieee80211_ptr->mesh_id_up_len = 0; | ||
798 | 797 | ||
799 | switch (otype) { | 798 | switch (otype) { |
800 | case NL80211_IFTYPE_ADHOC: | 799 | case NL80211_IFTYPE_ADHOC: |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 12222ee6ebf2..3e5dbd4e4cd5 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -548,8 +548,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
548 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 548 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
549 | rejoin = true; | 549 | rejoin = true; |
550 | } | 550 | } |
551 | err = rdev->ops->set_default_key(&rdev->wiphy, | 551 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, |
552 | dev, idx); | 552 | idx, true, true); |
553 | } | 553 | } |
554 | if (!err) { | 554 | if (!err) { |
555 | wdev->wext.default_key = idx; | 555 | wdev->wext.default_key = idx; |
@@ -627,8 +627,8 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
627 | err = 0; | 627 | err = 0; |
628 | wdev_lock(wdev); | 628 | wdev_lock(wdev); |
629 | if (wdev->current_bss) | 629 | if (wdev->current_bss) |
630 | err = rdev->ops->set_default_key(&rdev->wiphy, | 630 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, |
631 | dev, idx); | 631 | idx, true, true); |
632 | if (!err) | 632 | if (!err) |
633 | wdev->wext.default_key = idx; | 633 | wdev->wext.default_key = idx; |
634 | wdev_unlock(wdev); | 634 | wdev_unlock(wdev); |
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index dc675a3daa3d..fdbc23c10d8c 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c | |||
@@ -467,8 +467,8 @@ void wireless_send_event(struct net_device * dev, | |||
467 | * The best the driver could do is to log an error message. | 467 | * The best the driver could do is to log an error message. |
468 | * We will do it ourselves instead... | 468 | * We will do it ourselves instead... |
469 | */ | 469 | */ |
470 | printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", | 470 | netdev_err(dev, "(WE) : Invalid/Unknown Wireless Event (0x%04X)\n", |
471 | dev->name, cmd); | 471 | cmd); |
472 | return; | 472 | return; |
473 | } | 473 | } |
474 | 474 | ||
@@ -476,11 +476,13 @@ void wireless_send_event(struct net_device * dev, | |||
476 | if (descr->header_type == IW_HEADER_TYPE_POINT) { | 476 | if (descr->header_type == IW_HEADER_TYPE_POINT) { |
477 | /* Check if number of token fits within bounds */ | 477 | /* Check if number of token fits within bounds */ |
478 | if (wrqu->data.length > descr->max_tokens) { | 478 | if (wrqu->data.length > descr->max_tokens) { |
479 | printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); | 479 | netdev_err(dev, "(WE) : Wireless Event too big (%d)\n", |
480 | wrqu->data.length); | ||
480 | return; | 481 | return; |
481 | } | 482 | } |
482 | if (wrqu->data.length < descr->min_tokens) { | 483 | if (wrqu->data.length < descr->min_tokens) { |
483 | printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); | 484 | netdev_err(dev, "(WE) : Wireless Event too small (%d)\n", |
485 | wrqu->data.length); | ||
484 | return; | 486 | return; |
485 | } | 487 | } |
486 | /* Calculate extra_len - extra is NULL for restricted events */ | 488 | /* Calculate extra_len - extra is NULL for restricted events */ |
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index f7af98dff409..ad96ee90fe27 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -1357,11 +1357,11 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1357 | void __user *argp = (void __user *)arg; | 1357 | void __user *argp = (void __user *)arg; |
1358 | int rc; | 1358 | int rc; |
1359 | 1359 | ||
1360 | lock_kernel(); | ||
1361 | switch (cmd) { | 1360 | switch (cmd) { |
1362 | case TIOCOUTQ: { | 1361 | case TIOCOUTQ: { |
1363 | int amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); | 1362 | int amount; |
1364 | 1363 | ||
1364 | amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); | ||
1365 | if (amount < 0) | 1365 | if (amount < 0) |
1366 | amount = 0; | 1366 | amount = 0; |
1367 | rc = put_user(amount, (unsigned int __user *)argp); | 1367 | rc = put_user(amount, (unsigned int __user *)argp); |
@@ -1375,8 +1375,10 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1375 | * These two are safe on a single CPU system as | 1375 | * These two are safe on a single CPU system as |
1376 | * only user tasks fiddle here | 1376 | * only user tasks fiddle here |
1377 | */ | 1377 | */ |
1378 | lock_sock(sk); | ||
1378 | if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) | 1379 | if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) |
1379 | amount = skb->len; | 1380 | amount = skb->len; |
1381 | release_sock(sk); | ||
1380 | rc = put_user(amount, (unsigned int __user *)argp); | 1382 | rc = put_user(amount, (unsigned int __user *)argp); |
1381 | break; | 1383 | break; |
1382 | } | 1384 | } |
@@ -1422,9 +1424,11 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1422 | rc = x25_subscr_ioctl(cmd, argp); | 1424 | rc = x25_subscr_ioctl(cmd, argp); |
1423 | break; | 1425 | break; |
1424 | case SIOCX25GFACILITIES: { | 1426 | case SIOCX25GFACILITIES: { |
1425 | struct x25_facilities fac = x25->facilities; | 1427 | lock_sock(sk); |
1426 | rc = copy_to_user(argp, &fac, | 1428 | rc = copy_to_user(argp, &x25->facilities, |
1427 | sizeof(fac)) ? -EFAULT : 0; | 1429 | sizeof(x25->facilities)) |
1430 | ? -EFAULT : 0; | ||
1431 | release_sock(sk); | ||
1428 | break; | 1432 | break; |
1429 | } | 1433 | } |
1430 | 1434 | ||
@@ -1435,18 +1439,19 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1435 | sizeof(facilities))) | 1439 | sizeof(facilities))) |
1436 | break; | 1440 | break; |
1437 | rc = -EINVAL; | 1441 | rc = -EINVAL; |
1442 | lock_sock(sk); | ||
1438 | if (sk->sk_state != TCP_LISTEN && | 1443 | if (sk->sk_state != TCP_LISTEN && |
1439 | sk->sk_state != TCP_CLOSE) | 1444 | sk->sk_state != TCP_CLOSE) |
1440 | break; | 1445 | goto out_fac_release; |
1441 | if (facilities.pacsize_in < X25_PS16 || | 1446 | if (facilities.pacsize_in < X25_PS16 || |
1442 | facilities.pacsize_in > X25_PS4096) | 1447 | facilities.pacsize_in > X25_PS4096) |
1443 | break; | 1448 | goto out_fac_release; |
1444 | if (facilities.pacsize_out < X25_PS16 || | 1449 | if (facilities.pacsize_out < X25_PS16 || |
1445 | facilities.pacsize_out > X25_PS4096) | 1450 | facilities.pacsize_out > X25_PS4096) |
1446 | break; | 1451 | goto out_fac_release; |
1447 | if (facilities.winsize_in < 1 || | 1452 | if (facilities.winsize_in < 1 || |
1448 | facilities.winsize_in > 127) | 1453 | facilities.winsize_in > 127) |
1449 | break; | 1454 | goto out_fac_release; |
1450 | if (facilities.throughput) { | 1455 | if (facilities.throughput) { |
1451 | int out = facilities.throughput & 0xf0; | 1456 | int out = facilities.throughput & 0xf0; |
1452 | int in = facilities.throughput & 0x0f; | 1457 | int in = facilities.throughput & 0x0f; |
@@ -1454,24 +1459,28 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1454 | facilities.throughput |= | 1459 | facilities.throughput |= |
1455 | X25_DEFAULT_THROUGHPUT << 4; | 1460 | X25_DEFAULT_THROUGHPUT << 4; |
1456 | else if (out < 0x30 || out > 0xD0) | 1461 | else if (out < 0x30 || out > 0xD0) |
1457 | break; | 1462 | goto out_fac_release; |
1458 | if (!in) | 1463 | if (!in) |
1459 | facilities.throughput |= | 1464 | facilities.throughput |= |
1460 | X25_DEFAULT_THROUGHPUT; | 1465 | X25_DEFAULT_THROUGHPUT; |
1461 | else if (in < 0x03 || in > 0x0D) | 1466 | else if (in < 0x03 || in > 0x0D) |
1462 | break; | 1467 | goto out_fac_release; |
1463 | } | 1468 | } |
1464 | if (facilities.reverse && | 1469 | if (facilities.reverse && |
1465 | (facilities.reverse & 0x81) != 0x81) | 1470 | (facilities.reverse & 0x81) != 0x81) |
1466 | break; | 1471 | goto out_fac_release; |
1467 | x25->facilities = facilities; | 1472 | x25->facilities = facilities; |
1468 | rc = 0; | 1473 | rc = 0; |
1474 | out_fac_release: | ||
1475 | release_sock(sk); | ||
1469 | break; | 1476 | break; |
1470 | } | 1477 | } |
1471 | 1478 | ||
1472 | case SIOCX25GDTEFACILITIES: { | 1479 | case SIOCX25GDTEFACILITIES: { |
1480 | lock_sock(sk); | ||
1473 | rc = copy_to_user(argp, &x25->dte_facilities, | 1481 | rc = copy_to_user(argp, &x25->dte_facilities, |
1474 | sizeof(x25->dte_facilities)); | 1482 | sizeof(x25->dte_facilities)); |
1483 | release_sock(sk); | ||
1475 | if (rc) | 1484 | if (rc) |
1476 | rc = -EFAULT; | 1485 | rc = -EFAULT; |
1477 | break; | 1486 | break; |
@@ -1483,26 +1492,31 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1483 | if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) | 1492 | if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) |
1484 | break; | 1493 | break; |
1485 | rc = -EINVAL; | 1494 | rc = -EINVAL; |
1495 | lock_sock(sk); | ||
1486 | if (sk->sk_state != TCP_LISTEN && | 1496 | if (sk->sk_state != TCP_LISTEN && |
1487 | sk->sk_state != TCP_CLOSE) | 1497 | sk->sk_state != TCP_CLOSE) |
1488 | break; | 1498 | goto out_dtefac_release; |
1489 | if (dtefacs.calling_len > X25_MAX_AE_LEN) | 1499 | if (dtefacs.calling_len > X25_MAX_AE_LEN) |
1490 | break; | 1500 | goto out_dtefac_release; |
1491 | if (dtefacs.calling_ae == NULL) | 1501 | if (dtefacs.calling_ae == NULL) |
1492 | break; | 1502 | goto out_dtefac_release; |
1493 | if (dtefacs.called_len > X25_MAX_AE_LEN) | 1503 | if (dtefacs.called_len > X25_MAX_AE_LEN) |
1494 | break; | 1504 | goto out_dtefac_release; |
1495 | if (dtefacs.called_ae == NULL) | 1505 | if (dtefacs.called_ae == NULL) |
1496 | break; | 1506 | goto out_dtefac_release; |
1497 | x25->dte_facilities = dtefacs; | 1507 | x25->dte_facilities = dtefacs; |
1498 | rc = 0; | 1508 | rc = 0; |
1509 | out_dtefac_release: | ||
1510 | release_sock(sk); | ||
1499 | break; | 1511 | break; |
1500 | } | 1512 | } |
1501 | 1513 | ||
1502 | case SIOCX25GCALLUSERDATA: { | 1514 | case SIOCX25GCALLUSERDATA: { |
1503 | struct x25_calluserdata cud = x25->calluserdata; | 1515 | lock_sock(sk); |
1504 | rc = copy_to_user(argp, &cud, | 1516 | rc = copy_to_user(argp, &x25->calluserdata, |
1505 | sizeof(cud)) ? -EFAULT : 0; | 1517 | sizeof(x25->calluserdata)) |
1518 | ? -EFAULT : 0; | ||
1519 | release_sock(sk); | ||
1506 | break; | 1520 | break; |
1507 | } | 1521 | } |
1508 | 1522 | ||
@@ -1516,16 +1530,19 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1516 | rc = -EINVAL; | 1530 | rc = -EINVAL; |
1517 | if (calluserdata.cudlength > X25_MAX_CUD_LEN) | 1531 | if (calluserdata.cudlength > X25_MAX_CUD_LEN) |
1518 | break; | 1532 | break; |
1533 | lock_sock(sk); | ||
1519 | x25->calluserdata = calluserdata; | 1534 | x25->calluserdata = calluserdata; |
1535 | release_sock(sk); | ||
1520 | rc = 0; | 1536 | rc = 0; |
1521 | break; | 1537 | break; |
1522 | } | 1538 | } |
1523 | 1539 | ||
1524 | case SIOCX25GCAUSEDIAG: { | 1540 | case SIOCX25GCAUSEDIAG: { |
1525 | struct x25_causediag causediag; | 1541 | lock_sock(sk); |
1526 | causediag = x25->causediag; | 1542 | rc = copy_to_user(argp, &x25->causediag, |
1527 | rc = copy_to_user(argp, &causediag, | 1543 | sizeof(x25->causediag)) |
1528 | sizeof(causediag)) ? -EFAULT : 0; | 1544 | ? -EFAULT : 0; |
1545 | release_sock(sk); | ||
1529 | break; | 1546 | break; |
1530 | } | 1547 | } |
1531 | 1548 | ||
@@ -1534,7 +1551,9 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1534 | rc = -EFAULT; | 1551 | rc = -EFAULT; |
1535 | if (copy_from_user(&causediag, argp, sizeof(causediag))) | 1552 | if (copy_from_user(&causediag, argp, sizeof(causediag))) |
1536 | break; | 1553 | break; |
1554 | lock_sock(sk); | ||
1537 | x25->causediag = causediag; | 1555 | x25->causediag = causediag; |
1556 | release_sock(sk); | ||
1538 | rc = 0; | 1557 | rc = 0; |
1539 | break; | 1558 | break; |
1540 | 1559 | ||
@@ -1543,31 +1562,37 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1543 | case SIOCX25SCUDMATCHLEN: { | 1562 | case SIOCX25SCUDMATCHLEN: { |
1544 | struct x25_subaddr sub_addr; | 1563 | struct x25_subaddr sub_addr; |
1545 | rc = -EINVAL; | 1564 | rc = -EINVAL; |
1565 | lock_sock(sk); | ||
1546 | if(sk->sk_state != TCP_CLOSE) | 1566 | if(sk->sk_state != TCP_CLOSE) |
1547 | break; | 1567 | goto out_cud_release; |
1548 | rc = -EFAULT; | 1568 | rc = -EFAULT; |
1549 | if (copy_from_user(&sub_addr, argp, | 1569 | if (copy_from_user(&sub_addr, argp, |
1550 | sizeof(sub_addr))) | 1570 | sizeof(sub_addr))) |
1551 | break; | 1571 | goto out_cud_release; |
1552 | rc = -EINVAL; | 1572 | rc = -EINVAL; |
1553 | if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) | 1573 | if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) |
1554 | break; | 1574 | goto out_cud_release; |
1555 | x25->cudmatchlength = sub_addr.cudmatchlength; | 1575 | x25->cudmatchlength = sub_addr.cudmatchlength; |
1556 | rc = 0; | 1576 | rc = 0; |
1577 | out_cud_release: | ||
1578 | release_sock(sk); | ||
1557 | break; | 1579 | break; |
1558 | } | 1580 | } |
1559 | 1581 | ||
1560 | case SIOCX25CALLACCPTAPPRV: { | 1582 | case SIOCX25CALLACCPTAPPRV: { |
1561 | rc = -EINVAL; | 1583 | rc = -EINVAL; |
1584 | lock_kernel(); | ||
1562 | if (sk->sk_state != TCP_CLOSE) | 1585 | if (sk->sk_state != TCP_CLOSE) |
1563 | break; | 1586 | break; |
1564 | clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); | 1587 | clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); |
1588 | unlock_kernel(); | ||
1565 | rc = 0; | 1589 | rc = 0; |
1566 | break; | 1590 | break; |
1567 | } | 1591 | } |
1568 | 1592 | ||
1569 | case SIOCX25SENDCALLACCPT: { | 1593 | case SIOCX25SENDCALLACCPT: { |
1570 | rc = -EINVAL; | 1594 | rc = -EINVAL; |
1595 | lock_kernel(); | ||
1571 | if (sk->sk_state != TCP_ESTABLISHED) | 1596 | if (sk->sk_state != TCP_ESTABLISHED) |
1572 | break; | 1597 | break; |
1573 | /* must call accptapprv above */ | 1598 | /* must call accptapprv above */ |
@@ -1575,6 +1600,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1575 | break; | 1600 | break; |
1576 | x25_write_internal(sk, X25_CALL_ACCEPTED); | 1601 | x25_write_internal(sk, X25_CALL_ACCEPTED); |
1577 | x25->state = X25_STATE_3; | 1602 | x25->state = X25_STATE_3; |
1603 | unlock_kernel(); | ||
1578 | rc = 0; | 1604 | rc = 0; |
1579 | break; | 1605 | break; |
1580 | } | 1606 | } |
@@ -1583,7 +1609,6 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1583 | rc = -ENOIOCTLCMD; | 1609 | rc = -ENOIOCTLCMD; |
1584 | break; | 1610 | break; |
1585 | } | 1611 | } |
1586 | unlock_kernel(); | ||
1587 | 1612 | ||
1588 | return rc; | 1613 | return rc; |
1589 | } | 1614 | } |
@@ -1619,16 +1644,20 @@ static int compat_x25_subscr_ioctl(unsigned int cmd, | |||
1619 | dev_put(dev); | 1644 | dev_put(dev); |
1620 | 1645 | ||
1621 | if (cmd == SIOCX25GSUBSCRIP) { | 1646 | if (cmd == SIOCX25GSUBSCRIP) { |
1647 | read_lock_bh(&x25_neigh_list_lock); | ||
1622 | x25_subscr.extended = nb->extended; | 1648 | x25_subscr.extended = nb->extended; |
1623 | x25_subscr.global_facil_mask = nb->global_facil_mask; | 1649 | x25_subscr.global_facil_mask = nb->global_facil_mask; |
1650 | read_unlock_bh(&x25_neigh_list_lock); | ||
1624 | rc = copy_to_user(x25_subscr32, &x25_subscr, | 1651 | rc = copy_to_user(x25_subscr32, &x25_subscr, |
1625 | sizeof(*x25_subscr32)) ? -EFAULT : 0; | 1652 | sizeof(*x25_subscr32)) ? -EFAULT : 0; |
1626 | } else { | 1653 | } else { |
1627 | rc = -EINVAL; | 1654 | rc = -EINVAL; |
1628 | if (x25_subscr.extended == 0 || x25_subscr.extended == 1) { | 1655 | if (x25_subscr.extended == 0 || x25_subscr.extended == 1) { |
1629 | rc = 0; | 1656 | rc = 0; |
1657 | write_lock_bh(&x25_neigh_list_lock); | ||
1630 | nb->extended = x25_subscr.extended; | 1658 | nb->extended = x25_subscr.extended; |
1631 | nb->global_facil_mask = x25_subscr.global_facil_mask; | 1659 | nb->global_facil_mask = x25_subscr.global_facil_mask; |
1660 | write_unlock_bh(&x25_neigh_list_lock); | ||
1632 | } | 1661 | } |
1633 | } | 1662 | } |
1634 | x25_neigh_put(nb); | 1663 | x25_neigh_put(nb); |
@@ -1654,19 +1683,15 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, | |||
1654 | break; | 1683 | break; |
1655 | case SIOCGSTAMP: | 1684 | case SIOCGSTAMP: |
1656 | rc = -EINVAL; | 1685 | rc = -EINVAL; |
1657 | lock_kernel(); | ||
1658 | if (sk) | 1686 | if (sk) |
1659 | rc = compat_sock_get_timestamp(sk, | 1687 | rc = compat_sock_get_timestamp(sk, |
1660 | (struct timeval __user*)argp); | 1688 | (struct timeval __user*)argp); |
1661 | unlock_kernel(); | ||
1662 | break; | 1689 | break; |
1663 | case SIOCGSTAMPNS: | 1690 | case SIOCGSTAMPNS: |
1664 | rc = -EINVAL; | 1691 | rc = -EINVAL; |
1665 | lock_kernel(); | ||
1666 | if (sk) | 1692 | if (sk) |
1667 | rc = compat_sock_get_timestampns(sk, | 1693 | rc = compat_sock_get_timestampns(sk, |
1668 | (struct timespec __user*)argp); | 1694 | (struct timespec __user*)argp); |
1669 | unlock_kernel(); | ||
1670 | break; | 1695 | break; |
1671 | case SIOCGIFADDR: | 1696 | case SIOCGIFADDR: |
1672 | case SIOCSIFADDR: | 1697 | case SIOCSIFADDR: |
@@ -1685,22 +1710,16 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, | |||
1685 | rc = -EPERM; | 1710 | rc = -EPERM; |
1686 | if (!capable(CAP_NET_ADMIN)) | 1711 | if (!capable(CAP_NET_ADMIN)) |
1687 | break; | 1712 | break; |
1688 | lock_kernel(); | ||
1689 | rc = x25_route_ioctl(cmd, argp); | 1713 | rc = x25_route_ioctl(cmd, argp); |
1690 | unlock_kernel(); | ||
1691 | break; | 1714 | break; |
1692 | case SIOCX25GSUBSCRIP: | 1715 | case SIOCX25GSUBSCRIP: |
1693 | lock_kernel(); | ||
1694 | rc = compat_x25_subscr_ioctl(cmd, argp); | 1716 | rc = compat_x25_subscr_ioctl(cmd, argp); |
1695 | unlock_kernel(); | ||
1696 | break; | 1717 | break; |
1697 | case SIOCX25SSUBSCRIP: | 1718 | case SIOCX25SSUBSCRIP: |
1698 | rc = -EPERM; | 1719 | rc = -EPERM; |
1699 | if (!capable(CAP_NET_ADMIN)) | 1720 | if (!capable(CAP_NET_ADMIN)) |
1700 | break; | 1721 | break; |
1701 | lock_kernel(); | ||
1702 | rc = compat_x25_subscr_ioctl(cmd, argp); | 1722 | rc = compat_x25_subscr_ioctl(cmd, argp); |
1703 | unlock_kernel(); | ||
1704 | break; | 1723 | break; |
1705 | case SIOCX25GFACILITIES: | 1724 | case SIOCX25GFACILITIES: |
1706 | case SIOCX25SFACILITIES: | 1725 | case SIOCX25SFACILITIES: |
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index b25c6463c3e9..4cbc942f762a 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c | |||
@@ -31,8 +31,8 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <net/x25.h> | 32 | #include <net/x25.h> |
33 | 33 | ||
34 | static LIST_HEAD(x25_neigh_list); | 34 | LIST_HEAD(x25_neigh_list); |
35 | static DEFINE_RWLOCK(x25_neigh_list_lock); | 35 | DEFINE_RWLOCK(x25_neigh_list_lock); |
36 | 36 | ||
37 | static void x25_t20timer_expiry(unsigned long); | 37 | static void x25_t20timer_expiry(unsigned long); |
38 | 38 | ||
@@ -360,16 +360,20 @@ int x25_subscr_ioctl(unsigned int cmd, void __user *arg) | |||
360 | dev_put(dev); | 360 | dev_put(dev); |
361 | 361 | ||
362 | if (cmd == SIOCX25GSUBSCRIP) { | 362 | if (cmd == SIOCX25GSUBSCRIP) { |
363 | read_lock_bh(&x25_neigh_list_lock); | ||
363 | x25_subscr.extended = nb->extended; | 364 | x25_subscr.extended = nb->extended; |
364 | x25_subscr.global_facil_mask = nb->global_facil_mask; | 365 | x25_subscr.global_facil_mask = nb->global_facil_mask; |
366 | read_unlock_bh(&x25_neigh_list_lock); | ||
365 | rc = copy_to_user(arg, &x25_subscr, | 367 | rc = copy_to_user(arg, &x25_subscr, |
366 | sizeof(x25_subscr)) ? -EFAULT : 0; | 368 | sizeof(x25_subscr)) ? -EFAULT : 0; |
367 | } else { | 369 | } else { |
368 | rc = -EINVAL; | 370 | rc = -EINVAL; |
369 | if (!(x25_subscr.extended && x25_subscr.extended != 1)) { | 371 | if (!(x25_subscr.extended && x25_subscr.extended != 1)) { |
370 | rc = 0; | 372 | rc = 0; |
373 | write_lock_bh(&x25_neigh_list_lock); | ||
371 | nb->extended = x25_subscr.extended; | 374 | nb->extended = x25_subscr.extended; |
372 | nb->global_facil_mask = x25_subscr.global_facil_mask; | 375 | nb->global_facil_mask = x25_subscr.global_facil_mask; |
376 | write_unlock_bh(&x25_neigh_list_lock); | ||
373 | } | 377 | } |
374 | } | 378 | } |
375 | x25_neigh_put(nb); | 379 | x25_neigh_put(nb); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 044e77898512..8b3ef404c794 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1433,7 +1433,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1433 | } | 1433 | } |
1434 | 1434 | ||
1435 | xdst->route = dst; | 1435 | xdst->route = dst; |
1436 | memcpy(&dst1->metrics, &dst->metrics, sizeof(dst->metrics)); | 1436 | dst_copy_metrics(dst1, dst); |
1437 | 1437 | ||
1438 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 1438 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
1439 | family = xfrm[i]->props.family; | 1439 | family = xfrm[i]->props.family; |
@@ -2271,7 +2271,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst) | |||
2271 | if (pmtu > route_mtu_cached) | 2271 | if (pmtu > route_mtu_cached) |
2272 | pmtu = route_mtu_cached; | 2272 | pmtu = route_mtu_cached; |
2273 | 2273 | ||
2274 | dst->metrics[RTAX_MTU-1] = pmtu; | 2274 | dst_metric_set(dst, RTAX_MTU, pmtu); |
2275 | } while ((dst = dst->next)); | 2275 | } while ((dst = dst->next)); |
2276 | } | 2276 | } |
2277 | 2277 | ||
@@ -2349,7 +2349,7 @@ static int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, | |||
2349 | mtu = xfrm_state_mtu(dst->xfrm, mtu); | 2349 | mtu = xfrm_state_mtu(dst->xfrm, mtu); |
2350 | if (mtu > last->route_mtu_cached) | 2350 | if (mtu > last->route_mtu_cached) |
2351 | mtu = last->route_mtu_cached; | 2351 | mtu = last->route_mtu_cached; |
2352 | dst->metrics[RTAX_MTU-1] = mtu; | 2352 | dst_metric_set(dst, RTAX_MTU, mtu); |
2353 | 2353 | ||
2354 | if (last == first) | 2354 | if (last == first) |
2355 | break; | 2355 | break; |
@@ -2361,6 +2361,16 @@ static int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, | |||
2361 | return 1; | 2361 | return 1; |
2362 | } | 2362 | } |
2363 | 2363 | ||
2364 | static unsigned int xfrm_default_advmss(const struct dst_entry *dst) | ||
2365 | { | ||
2366 | return dst_metric_advmss(dst->path); | ||
2367 | } | ||
2368 | |||
2369 | static unsigned int xfrm_default_mtu(const struct dst_entry *dst) | ||
2370 | { | ||
2371 | return dst_mtu(dst->path); | ||
2372 | } | ||
2373 | |||
2364 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | 2374 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) |
2365 | { | 2375 | { |
2366 | struct net *net; | 2376 | struct net *net; |
@@ -2378,6 +2388,10 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2378 | dst_ops->kmem_cachep = xfrm_dst_cache; | 2388 | dst_ops->kmem_cachep = xfrm_dst_cache; |
2379 | if (likely(dst_ops->check == NULL)) | 2389 | if (likely(dst_ops->check == NULL)) |
2380 | dst_ops->check = xfrm_dst_check; | 2390 | dst_ops->check = xfrm_dst_check; |
2391 | if (likely(dst_ops->default_advmss == NULL)) | ||
2392 | dst_ops->default_advmss = xfrm_default_advmss; | ||
2393 | if (likely(dst_ops->default_mtu == NULL)) | ||
2394 | dst_ops->default_mtu = xfrm_default_mtu; | ||
2381 | if (likely(dst_ops->negative_advice == NULL)) | 2395 | if (likely(dst_ops->negative_advice == NULL)) |
2382 | dst_ops->negative_advice = xfrm_negative_advice; | 2396 | dst_ops->negative_advice = xfrm_negative_advice; |
2383 | if (likely(dst_ops->link_failure == NULL)) | 2397 | if (likely(dst_ops->link_failure == NULL)) |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 8bae6b22c846..8eb889510916 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -148,7 +148,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
148 | !attrs[XFRMA_ALG_AUTH_TRUNC]) || | 148 | !attrs[XFRMA_ALG_AUTH_TRUNC]) || |
149 | attrs[XFRMA_ALG_AEAD] || | 149 | attrs[XFRMA_ALG_AEAD] || |
150 | attrs[XFRMA_ALG_CRYPT] || | 150 | attrs[XFRMA_ALG_CRYPT] || |
151 | attrs[XFRMA_ALG_COMP]) | 151 | attrs[XFRMA_ALG_COMP] || |
152 | attrs[XFRMA_TFCPAD]) | ||
152 | goto out; | 153 | goto out; |
153 | break; | 154 | break; |
154 | 155 | ||
@@ -165,6 +166,9 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
165 | attrs[XFRMA_ALG_CRYPT]) && | 166 | attrs[XFRMA_ALG_CRYPT]) && |
166 | attrs[XFRMA_ALG_AEAD]) | 167 | attrs[XFRMA_ALG_AEAD]) |
167 | goto out; | 168 | goto out; |
169 | if (attrs[XFRMA_TFCPAD] && | ||
170 | p->mode != XFRM_MODE_TUNNEL) | ||
171 | goto out; | ||
168 | break; | 172 | break; |
169 | 173 | ||
170 | case IPPROTO_COMP: | 174 | case IPPROTO_COMP: |
@@ -172,7 +176,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
172 | attrs[XFRMA_ALG_AEAD] || | 176 | attrs[XFRMA_ALG_AEAD] || |
173 | attrs[XFRMA_ALG_AUTH] || | 177 | attrs[XFRMA_ALG_AUTH] || |
174 | attrs[XFRMA_ALG_AUTH_TRUNC] || | 178 | attrs[XFRMA_ALG_AUTH_TRUNC] || |
175 | attrs[XFRMA_ALG_CRYPT]) | 179 | attrs[XFRMA_ALG_CRYPT] || |
180 | attrs[XFRMA_TFCPAD]) | ||
176 | goto out; | 181 | goto out; |
177 | break; | 182 | break; |
178 | 183 | ||
@@ -186,6 +191,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
186 | attrs[XFRMA_ALG_CRYPT] || | 191 | attrs[XFRMA_ALG_CRYPT] || |
187 | attrs[XFRMA_ENCAP] || | 192 | attrs[XFRMA_ENCAP] || |
188 | attrs[XFRMA_SEC_CTX] || | 193 | attrs[XFRMA_SEC_CTX] || |
194 | attrs[XFRMA_TFCPAD] || | ||
189 | !attrs[XFRMA_COADDR]) | 195 | !attrs[XFRMA_COADDR]) |
190 | goto out; | 196 | goto out; |
191 | break; | 197 | break; |
@@ -439,6 +445,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
439 | goto error; | 445 | goto error; |
440 | } | 446 | } |
441 | 447 | ||
448 | if (attrs[XFRMA_TFCPAD]) | ||
449 | x->tfcpad = nla_get_u32(attrs[XFRMA_TFCPAD]); | ||
450 | |||
442 | if (attrs[XFRMA_COADDR]) { | 451 | if (attrs[XFRMA_COADDR]) { |
443 | x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]), | 452 | x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]), |
444 | sizeof(*x->coaddr), GFP_KERNEL); | 453 | sizeof(*x->coaddr), GFP_KERNEL); |
@@ -688,6 +697,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
688 | if (x->encap) | 697 | if (x->encap) |
689 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 698 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
690 | 699 | ||
700 | if (x->tfcpad) | ||
701 | NLA_PUT_U32(skb, XFRMA_TFCPAD, x->tfcpad); | ||
702 | |||
691 | if (xfrm_mark_put(skb, &x->mark)) | 703 | if (xfrm_mark_put(skb, &x->mark)) |
692 | goto nla_put_failure; | 704 | goto nla_put_failure; |
693 | 705 | ||
@@ -2122,6 +2134,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
2122 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, | 2134 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, |
2123 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | 2135 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, |
2124 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, | 2136 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, |
2137 | [XFRMA_TFCPAD] = { .type = NLA_U32 }, | ||
2125 | }; | 2138 | }; |
2126 | 2139 | ||
2127 | static struct xfrm_link { | 2140 | static struct xfrm_link { |
@@ -2301,6 +2314,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) | |||
2301 | l += nla_total_size(sizeof(*x->calg)); | 2314 | l += nla_total_size(sizeof(*x->calg)); |
2302 | if (x->encap) | 2315 | if (x->encap) |
2303 | l += nla_total_size(sizeof(*x->encap)); | 2316 | l += nla_total_size(sizeof(*x->encap)); |
2317 | if (x->tfcpad) | ||
2318 | l += nla_total_size(sizeof(x->tfcpad)); | ||
2304 | if (x->security) | 2319 | if (x->security) |
2305 | l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + | 2320 | l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + |
2306 | x->security->ctx_len); | 2321 | x->security->ctx_len); |