diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 23:53:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-02 23:53:45 -0400 |
commit | cd6362befe4cc7bf589a5236d2a780af2d47bcc9 (patch) | |
tree | 3bd4e13ec3f92a00dc4f6c3d65e820b54dbfe46e /drivers/net/hyperv | |
parent | 0f1b1e6d73cb989ce2c071edc57deade3b084dfe (diff) | |
parent | b1586f099ba897542ece36e8a23c1a62907261ef (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
"Here is my initial pull request for the networking subsystem during
this merge window:
1) Support for ESN in AH (RFC 4302) from Fan Du.
2) Add full kernel doc for ethtool command structures, from Ben
Hutchings.
3) Add BCM7xxx PHY driver, from Florian Fainelli.
4) Export computed TCP rate information in netlink socket dumps, from
Eric Dumazet.
5) Allow IPSEC SA to be dumped partially using a filter, from Nicolas
Dichtel.
6) Convert many drivers to pci_enable_msix_range(), from Alexander
Gordeev.
7) Record SKB timestamps more efficiently, from Eric Dumazet.
8) Switch to microsecond resolution for TCP round trip times, also
from Eric Dumazet.
9) Clean up and fix 6lowpan fragmentation handling by making use of
the existing inet_frag api for it's implementation.
10) Add TX grant mapping to xen-netback driver, from Zoltan Kiss.
11) Auto size SKB lengths when composing netlink messages based upon
past message sizes used, from Eric Dumazet.
12) qdisc dumps can take a long time, add a cond_resched(), From Eric
Dumazet.
13) Sanitize netpoll core and drivers wrt. SKB handling semantics.
Get rid of never-used-in-tree netpoll RX handling. From Eric W
Biederman.
14) Support inter-address-family and namespace changing in VTI tunnel
driver(s). From Steffen Klassert.
15) Add Altera TSE driver, from Vince Bridgers.
16) Optimizing csum_replace2() so that it doesn't adjust the checksum
by checksumming the entire header, from Eric Dumazet.
17) Expand BPF internal implementation for faster interpreting, more
direct translations into JIT'd code, and much cleaner uses of BPF
filtering in non-socket ocntexts. From Daniel Borkmann and Alexei
Starovoitov"
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1976 commits)
netpoll: Use skb_irq_freeable to make zap_completion_queue safe.
net: Add a test to see if a skb is freeable in irq context
qlcnic: Fix build failure due to undefined reference to `vxlan_get_rx_port'
net: ptp: move PTP classifier in its own file
net: sxgbe: make "core_ops" static
net: sxgbe: fix logical vs bitwise operation
net: sxgbe: sxgbe_mdio_register() frees the bus
Call efx_set_channels() before efx->type->dimension_resources()
xen-netback: disable rogue vif in kthread context
net/mlx4: Set proper build dependancy with vxlan
be2net: fix build dependency on VxLAN
mac802154: make csma/cca parameters per-wpan
mac802154: allow only one WPAN to be up at any given time
net: filter: minor: fix kdoc in __sk_run_filter
netlink: don't compare the nul-termination in nla_strcmp
can: c_can: Avoid led toggling for every packet.
can: c_can: Simplify TX interrupt cleanup
can: c_can: Store dlc private
can: c_can: Reduce register access
can: c_can: Make the code readable
...
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 207 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc.c | 93 | ||||
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 337 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 187 |
4 files changed, 607 insertions, 217 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 7b594ce3f21d..13010b4dae5b 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | /* Fwd declaration */ | 31 | /* Fwd declaration */ |
32 | struct hv_netvsc_packet; | 32 | struct hv_netvsc_packet; |
33 | struct ndis_tcp_ip_checksum_info; | ||
33 | 34 | ||
34 | /* Represent the xfer page packet which contains 1 or more netvsc packet */ | 35 | /* Represent the xfer page packet which contains 1 or more netvsc packet */ |
35 | struct xferpage_packet { | 36 | struct xferpage_packet { |
@@ -73,7 +74,7 @@ struct hv_netvsc_packet { | |||
73 | } completion; | 74 | } completion; |
74 | 75 | ||
75 | /* This points to the memory after page_buf */ | 76 | /* This points to the memory after page_buf */ |
76 | void *extension; | 77 | struct rndis_message *rndis_msg; |
77 | 78 | ||
78 | u32 total_data_buflen; | 79 | u32 total_data_buflen; |
79 | /* Points to the send/receive buffer where the ethernet frame is */ | 80 | /* Points to the send/receive buffer where the ethernet frame is */ |
@@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device, | |||
117 | void netvsc_linkstatus_callback(struct hv_device *device_obj, | 118 | void netvsc_linkstatus_callback(struct hv_device *device_obj, |
118 | unsigned int status); | 119 | unsigned int status); |
119 | int netvsc_recv_callback(struct hv_device *device_obj, | 120 | int netvsc_recv_callback(struct hv_device *device_obj, |
120 | struct hv_netvsc_packet *packet); | 121 | struct hv_netvsc_packet *packet, |
122 | struct ndis_tcp_ip_checksum_info *csum_info); | ||
121 | int rndis_filter_open(struct hv_device *dev); | 123 | int rndis_filter_open(struct hv_device *dev); |
122 | int rndis_filter_close(struct hv_device *dev); | 124 | int rndis_filter_close(struct hv_device *dev); |
123 | int rndis_filter_device_add(struct hv_device *dev, | 125 | int rndis_filter_device_add(struct hv_device *dev, |
@@ -126,11 +128,6 @@ void rndis_filter_device_remove(struct hv_device *dev); | |||
126 | int rndis_filter_receive(struct hv_device *dev, | 128 | int rndis_filter_receive(struct hv_device *dev, |
127 | struct hv_netvsc_packet *pkt); | 129 | struct hv_netvsc_packet *pkt); |
128 | 130 | ||
129 | |||
130 | |||
131 | int rndis_filter_send(struct hv_device *dev, | ||
132 | struct hv_netvsc_packet *pkt); | ||
133 | |||
134 | int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); | 131 | int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); |
135 | int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); | 132 | int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); |
136 | 133 | ||
@@ -139,6 +136,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); | |||
139 | 136 | ||
140 | #define NVSP_PROTOCOL_VERSION_1 2 | 137 | #define NVSP_PROTOCOL_VERSION_1 2 |
141 | #define NVSP_PROTOCOL_VERSION_2 0x30002 | 138 | #define NVSP_PROTOCOL_VERSION_2 0x30002 |
139 | #define NVSP_PROTOCOL_VERSION_4 0x40000 | ||
140 | #define NVSP_PROTOCOL_VERSION_5 0x50000 | ||
142 | 141 | ||
143 | enum { | 142 | enum { |
144 | NVSP_MSG_TYPE_NONE = 0, | 143 | NVSP_MSG_TYPE_NONE = 0, |
@@ -193,6 +192,23 @@ enum { | |||
193 | 192 | ||
194 | NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE, | 193 | NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE, |
195 | NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, | 194 | NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, |
195 | |||
196 | NVSP_MSG2_MAX = NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, | ||
197 | |||
198 | /* Version 4 messages */ | ||
199 | NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION, | ||
200 | NVSP_MSG4_TYPE_SWITCH_DATA_PATH, | ||
201 | NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED, | ||
202 | |||
203 | NVSP_MSG4_MAX = NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED, | ||
204 | |||
205 | /* Version 5 messages */ | ||
206 | NVSP_MSG5_TYPE_OID_QUERY_EX, | ||
207 | NVSP_MSG5_TYPE_OID_QUERY_EX_COMP, | ||
208 | NVSP_MSG5_TYPE_SUBCHANNEL, | ||
209 | NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE, | ||
210 | |||
211 | NVSP_MSG5_MAX = NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE, | ||
196 | }; | 212 | }; |
197 | 213 | ||
198 | enum { | 214 | enum { |
@@ -447,10 +463,44 @@ union nvsp_2_message_uber { | |||
447 | struct nvsp_2_free_rxbuf free_rxbuf; | 463 | struct nvsp_2_free_rxbuf free_rxbuf; |
448 | } __packed; | 464 | } __packed; |
449 | 465 | ||
466 | enum nvsp_subchannel_operation { | ||
467 | NVSP_SUBCHANNEL_NONE = 0, | ||
468 | NVSP_SUBCHANNEL_ALLOCATE, | ||
469 | NVSP_SUBCHANNEL_MAX | ||
470 | }; | ||
471 | |||
472 | struct nvsp_5_subchannel_request { | ||
473 | u32 op; | ||
474 | u32 num_subchannels; | ||
475 | } __packed; | ||
476 | |||
477 | struct nvsp_5_subchannel_complete { | ||
478 | u32 status; | ||
479 | u32 num_subchannels; /* Actual number of subchannels allocated */ | ||
480 | } __packed; | ||
481 | |||
482 | struct nvsp_5_send_indirect_table { | ||
483 | /* The number of entries in the send indirection table */ | ||
484 | u32 count; | ||
485 | |||
486 | /* The offset of the send indireciton table from top of this struct. | ||
487 | * The send indirection table tells which channel to put the send | ||
488 | * traffic on. Each entry is a channel number. | ||
489 | */ | ||
490 | u32 offset; | ||
491 | } __packed; | ||
492 | |||
493 | union nvsp_5_message_uber { | ||
494 | struct nvsp_5_subchannel_request subchn_req; | ||
495 | struct nvsp_5_subchannel_complete subchn_comp; | ||
496 | struct nvsp_5_send_indirect_table send_table; | ||
497 | } __packed; | ||
498 | |||
450 | union nvsp_all_messages { | 499 | union nvsp_all_messages { |
451 | union nvsp_message_init_uber init_msg; | 500 | union nvsp_message_init_uber init_msg; |
452 | union nvsp_1_message_uber v1_msg; | 501 | union nvsp_1_message_uber v1_msg; |
453 | union nvsp_2_message_uber v2_msg; | 502 | union nvsp_2_message_uber v2_msg; |
503 | union nvsp_5_message_uber v5_msg; | ||
454 | } __packed; | 504 | } __packed; |
455 | 505 | ||
456 | /* ALL Messages */ | 506 | /* ALL Messages */ |
@@ -463,6 +513,7 @@ struct nvsp_message { | |||
463 | #define NETVSC_MTU 65536 | 513 | #define NETVSC_MTU 65536 |
464 | 514 | ||
465 | #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ | 515 | #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ |
516 | #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ | ||
466 | 517 | ||
467 | #define NETVSC_RECEIVE_BUFFER_ID 0xcafe | 518 | #define NETVSC_RECEIVE_BUFFER_ID 0xcafe |
468 | 519 | ||
@@ -506,6 +557,8 @@ struct netvsc_device { | |||
506 | 557 | ||
507 | /* Holds rndis device info */ | 558 | /* Holds rndis device info */ |
508 | void *extension; | 559 | void *extension; |
560 | /* The recive buffer for this device */ | ||
561 | unsigned char cb_buffer[NETVSC_PACKET_SIZE]; | ||
509 | }; | 562 | }; |
510 | 563 | ||
511 | /* NdisInitialize message */ | 564 | /* NdisInitialize message */ |
@@ -671,9 +724,133 @@ struct ndis_pkt_8021q_info { | |||
671 | }; | 724 | }; |
672 | }; | 725 | }; |
673 | 726 | ||
727 | struct ndis_oject_header { | ||
728 | u8 type; | ||
729 | u8 revision; | ||
730 | u16 size; | ||
731 | }; | ||
732 | |||
733 | #define NDIS_OBJECT_TYPE_DEFAULT 0x80 | ||
734 | #define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3 | ||
735 | #define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0 | ||
736 | #define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1 | ||
737 | #define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED 2 | ||
738 | #define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED 2 | ||
739 | #define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1 | ||
740 | #define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2 | ||
741 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1 | ||
742 | #define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2 | ||
743 | #define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 | ||
744 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 | ||
745 | |||
746 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1 | ||
747 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 | ||
748 | #define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 | ||
749 | |||
750 | /* | ||
751 | * New offload OIDs for NDIS 6 | ||
752 | */ | ||
753 | #define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */ | ||
754 | #define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C /* set only */ | ||
755 | #define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */ | ||
756 | #define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */ | ||
757 | #define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */ | ||
758 | #define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */ | ||
759 | |||
760 | struct ndis_offload_params { | ||
761 | struct ndis_oject_header header; | ||
762 | u8 ip_v4_csum; | ||
763 | u8 tcp_ip_v4_csum; | ||
764 | u8 udp_ip_v4_csum; | ||
765 | u8 tcp_ip_v6_csum; | ||
766 | u8 udp_ip_v6_csum; | ||
767 | u8 lso_v1; | ||
768 | u8 ip_sec_v1; | ||
769 | u8 lso_v2_ipv4; | ||
770 | u8 lso_v2_ipv6; | ||
771 | u8 tcp_connection_ip_v4; | ||
772 | u8 tcp_connection_ip_v6; | ||
773 | u32 flags; | ||
774 | u8 ip_sec_v2; | ||
775 | u8 ip_sec_v2_ip_v4; | ||
776 | struct { | ||
777 | u8 rsc_ip_v4; | ||
778 | u8 rsc_ip_v6; | ||
779 | }; | ||
780 | struct { | ||
781 | u8 encapsulated_packet_task_offload; | ||
782 | u8 encapsulation_types; | ||
783 | }; | ||
784 | }; | ||
785 | |||
786 | struct ndis_tcp_ip_checksum_info { | ||
787 | union { | ||
788 | struct { | ||
789 | u32 is_ipv4:1; | ||
790 | u32 is_ipv6:1; | ||
791 | u32 tcp_checksum:1; | ||
792 | u32 udp_checksum:1; | ||
793 | u32 ip_header_checksum:1; | ||
794 | u32 reserved:11; | ||
795 | u32 tcp_header_offset:10; | ||
796 | } transmit; | ||
797 | struct { | ||
798 | u32 tcp_checksum_failed:1; | ||
799 | u32 udp_checksum_failed:1; | ||
800 | u32 ip_checksum_failed:1; | ||
801 | u32 tcp_checksum_succeeded:1; | ||
802 | u32 udp_checksum_succeeded:1; | ||
803 | u32 ip_checksum_succeeded:1; | ||
804 | u32 loopback:1; | ||
805 | u32 tcp_checksum_value_invalid:1; | ||
806 | u32 ip_checksum_value_invalid:1; | ||
807 | } receive; | ||
808 | u32 value; | ||
809 | }; | ||
810 | }; | ||
811 | |||
812 | struct ndis_tcp_lso_info { | ||
813 | union { | ||
814 | struct { | ||
815 | u32 unused:30; | ||
816 | u32 type:1; | ||
817 | u32 reserved2:1; | ||
818 | } transmit; | ||
819 | struct { | ||
820 | u32 mss:20; | ||
821 | u32 tcp_header_offset:10; | ||
822 | u32 type:1; | ||
823 | u32 reserved2:1; | ||
824 | } lso_v1_transmit; | ||
825 | struct { | ||
826 | u32 tcp_payload:30; | ||
827 | u32 type:1; | ||
828 | u32 reserved2:1; | ||
829 | } lso_v1_transmit_complete; | ||
830 | struct { | ||
831 | u32 mss:20; | ||
832 | u32 tcp_header_offset:10; | ||
833 | u32 type:1; | ||
834 | u32 ip_version:1; | ||
835 | } lso_v2_transmit; | ||
836 | struct { | ||
837 | u32 reserved:30; | ||
838 | u32 type:1; | ||
839 | u32 reserved2:1; | ||
840 | } lso_v2_transmit_complete; | ||
841 | u32 value; | ||
842 | }; | ||
843 | }; | ||
844 | |||
674 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | 845 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ |
675 | sizeof(struct ndis_pkt_8021q_info)) | 846 | sizeof(struct ndis_pkt_8021q_info)) |
676 | 847 | ||
848 | #define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | ||
849 | sizeof(struct ndis_tcp_ip_checksum_info)) | ||
850 | |||
851 | #define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | ||
852 | sizeof(struct ndis_tcp_lso_info)) | ||
853 | |||
677 | /* Format of Information buffer passed in a SetRequest for the OID */ | 854 | /* Format of Information buffer passed in a SetRequest for the OID */ |
678 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ | 855 | /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ |
679 | struct rndis_config_parameter_info { | 856 | struct rndis_config_parameter_info { |
@@ -846,12 +1023,6 @@ struct rndis_message { | |||
846 | }; | 1023 | }; |
847 | 1024 | ||
848 | 1025 | ||
849 | struct rndis_filter_packet { | ||
850 | void *completion_ctx; | ||
851 | void (*completion)(void *context); | ||
852 | struct rndis_message msg; | ||
853 | }; | ||
854 | |||
855 | /* Handy macros */ | 1026 | /* Handy macros */ |
856 | 1027 | ||
857 | /* get the size of an RNDIS message. Pass in the message type, */ | 1028 | /* get the size of an RNDIS message. Pass in the message type, */ |
@@ -905,6 +1076,16 @@ struct rndis_filter_packet { | |||
905 | #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 | 1076 | #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 |
906 | #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 | 1077 | #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 |
907 | 1078 | ||
1079 | #define INFO_IPV4 2 | ||
1080 | #define INFO_IPV6 4 | ||
1081 | #define INFO_TCP 2 | ||
1082 | #define INFO_UDP 4 | ||
1083 | |||
1084 | #define TRANSPORT_INFO_NOT_IP 0 | ||
1085 | #define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP) | ||
1086 | #define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP) | ||
1087 | #define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP) | ||
1088 | #define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP) | ||
908 | 1089 | ||
909 | 1090 | ||
910 | #endif /* _HYPERV_NET_H */ | 1091 | #endif /* _HYPERV_NET_H */ |
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 03a2c6e17158..daddea2654ce 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c | |||
@@ -290,7 +290,7 @@ static int negotiate_nvsp_ver(struct hv_device *device, | |||
290 | NVSP_STAT_SUCCESS) | 290 | NVSP_STAT_SUCCESS) |
291 | return -EINVAL; | 291 | return -EINVAL; |
292 | 292 | ||
293 | if (nvsp_ver != NVSP_PROTOCOL_VERSION_2) | 293 | if (nvsp_ver == NVSP_PROTOCOL_VERSION_1) |
294 | return 0; | 294 | return 0; |
295 | 295 | ||
296 | /* NVSPv2 only: Send NDIS config */ | 296 | /* NVSPv2 only: Send NDIS config */ |
@@ -314,6 +314,9 @@ static int netvsc_connect_vsp(struct hv_device *device) | |||
314 | struct nvsp_message *init_packet; | 314 | struct nvsp_message *init_packet; |
315 | int ndis_version; | 315 | int ndis_version; |
316 | struct net_device *ndev; | 316 | struct net_device *ndev; |
317 | u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2, | ||
318 | NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 }; | ||
319 | int i, num_ver = 4; /* number of different NVSP versions */ | ||
317 | 320 | ||
318 | net_device = get_outbound_net_device(device); | 321 | net_device = get_outbound_net_device(device); |
319 | if (!net_device) | 322 | if (!net_device) |
@@ -323,13 +326,14 @@ static int netvsc_connect_vsp(struct hv_device *device) | |||
323 | init_packet = &net_device->channel_init_pkt; | 326 | init_packet = &net_device->channel_init_pkt; |
324 | 327 | ||
325 | /* Negotiate the latest NVSP protocol supported */ | 328 | /* Negotiate the latest NVSP protocol supported */ |
326 | if (negotiate_nvsp_ver(device, net_device, init_packet, | 329 | for (i = num_ver - 1; i >= 0; i--) |
327 | NVSP_PROTOCOL_VERSION_2) == 0) { | 330 | if (negotiate_nvsp_ver(device, net_device, init_packet, |
328 | net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2; | 331 | ver_list[i]) == 0) { |
329 | } else if (negotiate_nvsp_ver(device, net_device, init_packet, | 332 | net_device->nvsp_version = ver_list[i]; |
330 | NVSP_PROTOCOL_VERSION_1) == 0) { | 333 | break; |
331 | net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1; | 334 | } |
332 | } else { | 335 | |
336 | if (i < 0) { | ||
333 | ret = -EPROTO; | 337 | ret = -EPROTO; |
334 | goto cleanup; | 338 | goto cleanup; |
335 | } | 339 | } |
@@ -339,7 +343,10 @@ static int netvsc_connect_vsp(struct hv_device *device) | |||
339 | /* Send the ndis version */ | 343 | /* Send the ndis version */ |
340 | memset(init_packet, 0, sizeof(struct nvsp_message)); | 344 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
341 | 345 | ||
342 | ndis_version = 0x00050001; | 346 | if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_4) |
347 | ndis_version = 0x00050001; | ||
348 | else | ||
349 | ndis_version = 0x0006001e; | ||
343 | 350 | ||
344 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER; | 351 | init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER; |
345 | init_packet->msg.v1_msg. | 352 | init_packet->msg.v1_msg. |
@@ -358,6 +365,11 @@ static int netvsc_connect_vsp(struct hv_device *device) | |||
358 | goto cleanup; | 365 | goto cleanup; |
359 | 366 | ||
360 | /* Post the big receive buffer to NetVSP */ | 367 | /* Post the big receive buffer to NetVSP */ |
368 | if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2) | ||
369 | net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; | ||
370 | else | ||
371 | net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; | ||
372 | |||
361 | ret = netvsc_init_recv_buf(device); | 373 | ret = netvsc_init_recv_buf(device); |
362 | 374 | ||
363 | cleanup: | 375 | cleanup: |
@@ -432,17 +444,14 @@ static inline u32 hv_ringbuf_avail_percent( | |||
432 | return avail_write * 100 / ring_info->ring_datasize; | 444 | return avail_write * 100 / ring_info->ring_datasize; |
433 | } | 445 | } |
434 | 446 | ||
435 | static void netvsc_send_completion(struct hv_device *device, | 447 | static void netvsc_send_completion(struct netvsc_device *net_device, |
448 | struct hv_device *device, | ||
436 | struct vmpacket_descriptor *packet) | 449 | struct vmpacket_descriptor *packet) |
437 | { | 450 | { |
438 | struct netvsc_device *net_device; | ||
439 | struct nvsp_message *nvsp_packet; | 451 | struct nvsp_message *nvsp_packet; |
440 | struct hv_netvsc_packet *nvsc_packet; | 452 | struct hv_netvsc_packet *nvsc_packet; |
441 | struct net_device *ndev; | 453 | struct net_device *ndev; |
442 | 454 | ||
443 | net_device = get_inbound_net_device(device); | ||
444 | if (!net_device) | ||
445 | return; | ||
446 | ndev = net_device->ndev; | 455 | ndev = net_device->ndev; |
447 | 456 | ||
448 | nvsp_packet = (struct nvsp_message *)((unsigned long)packet + | 457 | nvsp_packet = (struct nvsp_message *)((unsigned long)packet + |
@@ -561,13 +570,13 @@ int netvsc_send(struct hv_device *device, | |||
561 | } | 570 | } |
562 | 571 | ||
563 | static void netvsc_send_recv_completion(struct hv_device *device, | 572 | static void netvsc_send_recv_completion(struct hv_device *device, |
573 | struct netvsc_device *net_device, | ||
564 | u64 transaction_id, u32 status) | 574 | u64 transaction_id, u32 status) |
565 | { | 575 | { |
566 | struct nvsp_message recvcompMessage; | 576 | struct nvsp_message recvcompMessage; |
567 | int retries = 0; | 577 | int retries = 0; |
568 | int ret; | 578 | int ret; |
569 | struct net_device *ndev; | 579 | struct net_device *ndev; |
570 | struct netvsc_device *net_device = hv_get_drvdata(device); | ||
571 | 580 | ||
572 | ndev = net_device->ndev; | 581 | ndev = net_device->ndev; |
573 | 582 | ||
@@ -653,14 +662,15 @@ static void netvsc_receive_completion(void *context) | |||
653 | 662 | ||
654 | /* Send a receive completion for the xfer page packet */ | 663 | /* Send a receive completion for the xfer page packet */ |
655 | if (fsend_receive_comp) | 664 | if (fsend_receive_comp) |
656 | netvsc_send_recv_completion(device, transaction_id, status); | 665 | netvsc_send_recv_completion(device, net_device, transaction_id, |
666 | status); | ||
657 | 667 | ||
658 | } | 668 | } |
659 | 669 | ||
660 | static void netvsc_receive(struct hv_device *device, | 670 | static void netvsc_receive(struct netvsc_device *net_device, |
661 | struct vmpacket_descriptor *packet) | 671 | struct hv_device *device, |
672 | struct vmpacket_descriptor *packet) | ||
662 | { | 673 | { |
663 | struct netvsc_device *net_device; | ||
664 | struct vmtransfer_page_packet_header *vmxferpage_packet; | 674 | struct vmtransfer_page_packet_header *vmxferpage_packet; |
665 | struct nvsp_message *nvsp_packet; | 675 | struct nvsp_message *nvsp_packet; |
666 | struct hv_netvsc_packet *netvsc_packet = NULL; | 676 | struct hv_netvsc_packet *netvsc_packet = NULL; |
@@ -673,9 +683,6 @@ static void netvsc_receive(struct hv_device *device, | |||
673 | 683 | ||
674 | LIST_HEAD(listHead); | 684 | LIST_HEAD(listHead); |
675 | 685 | ||
676 | net_device = get_inbound_net_device(device); | ||
677 | if (!net_device) | ||
678 | return; | ||
679 | ndev = net_device->ndev; | 686 | ndev = net_device->ndev; |
680 | 687 | ||
681 | /* | 688 | /* |
@@ -741,7 +748,7 @@ static void netvsc_receive(struct hv_device *device, | |||
741 | spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, | 748 | spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, |
742 | flags); | 749 | flags); |
743 | 750 | ||
744 | netvsc_send_recv_completion(device, | 751 | netvsc_send_recv_completion(device, net_device, |
745 | vmxferpage_packet->d.trans_id, | 752 | vmxferpage_packet->d.trans_id, |
746 | NVSP_STAT_FAIL); | 753 | NVSP_STAT_FAIL); |
747 | 754 | ||
@@ -800,22 +807,16 @@ static void netvsc_channel_cb(void *context) | |||
800 | struct netvsc_device *net_device; | 807 | struct netvsc_device *net_device; |
801 | u32 bytes_recvd; | 808 | u32 bytes_recvd; |
802 | u64 request_id; | 809 | u64 request_id; |
803 | unsigned char *packet; | ||
804 | struct vmpacket_descriptor *desc; | 810 | struct vmpacket_descriptor *desc; |
805 | unsigned char *buffer; | 811 | unsigned char *buffer; |
806 | int bufferlen = NETVSC_PACKET_SIZE; | 812 | int bufferlen = NETVSC_PACKET_SIZE; |
807 | struct net_device *ndev; | 813 | struct net_device *ndev; |
808 | 814 | ||
809 | packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char), | ||
810 | GFP_ATOMIC); | ||
811 | if (!packet) | ||
812 | return; | ||
813 | buffer = packet; | ||
814 | |||
815 | net_device = get_inbound_net_device(device); | 815 | net_device = get_inbound_net_device(device); |
816 | if (!net_device) | 816 | if (!net_device) |
817 | goto out; | 817 | return; |
818 | ndev = net_device->ndev; | 818 | ndev = net_device->ndev; |
819 | buffer = net_device->cb_buffer; | ||
819 | 820 | ||
820 | do { | 821 | do { |
821 | ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, | 822 | ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, |
@@ -825,11 +826,13 @@ static void netvsc_channel_cb(void *context) | |||
825 | desc = (struct vmpacket_descriptor *)buffer; | 826 | desc = (struct vmpacket_descriptor *)buffer; |
826 | switch (desc->type) { | 827 | switch (desc->type) { |
827 | case VM_PKT_COMP: | 828 | case VM_PKT_COMP: |
828 | netvsc_send_completion(device, desc); | 829 | netvsc_send_completion(net_device, |
830 | device, desc); | ||
829 | break; | 831 | break; |
830 | 832 | ||
831 | case VM_PKT_DATA_USING_XFER_PAGES: | 833 | case VM_PKT_DATA_USING_XFER_PAGES: |
832 | netvsc_receive(device, desc); | 834 | netvsc_receive(net_device, |
835 | device, desc); | ||
833 | break; | 836 | break; |
834 | 837 | ||
835 | default: | 838 | default: |
@@ -841,23 +844,16 @@ static void netvsc_channel_cb(void *context) | |||
841 | break; | 844 | break; |
842 | } | 845 | } |
843 | 846 | ||
844 | /* reset */ | ||
845 | if (bufferlen > NETVSC_PACKET_SIZE) { | ||
846 | kfree(buffer); | ||
847 | buffer = packet; | ||
848 | bufferlen = NETVSC_PACKET_SIZE; | ||
849 | } | ||
850 | } else { | 847 | } else { |
851 | /* reset */ | 848 | /* |
852 | if (bufferlen > NETVSC_PACKET_SIZE) { | 849 | * We are done for this pass. |
853 | kfree(buffer); | 850 | */ |
854 | buffer = packet; | ||
855 | bufferlen = NETVSC_PACKET_SIZE; | ||
856 | } | ||
857 | |||
858 | break; | 851 | break; |
859 | } | 852 | } |
853 | |||
860 | } else if (ret == -ENOBUFS) { | 854 | } else if (ret == -ENOBUFS) { |
855 | if (bufferlen > NETVSC_PACKET_SIZE) | ||
856 | kfree(buffer); | ||
861 | /* Handle large packet */ | 857 | /* Handle large packet */ |
862 | buffer = kmalloc(bytes_recvd, GFP_ATOMIC); | 858 | buffer = kmalloc(bytes_recvd, GFP_ATOMIC); |
863 | if (buffer == NULL) { | 859 | if (buffer == NULL) { |
@@ -872,8 +868,8 @@ static void netvsc_channel_cb(void *context) | |||
872 | } | 868 | } |
873 | } while (1); | 869 | } while (1); |
874 | 870 | ||
875 | out: | 871 | if (bufferlen > NETVSC_PACKET_SIZE) |
876 | kfree(buffer); | 872 | kfree(buffer); |
877 | return; | 873 | return; |
878 | } | 874 | } |
879 | 875 | ||
@@ -907,7 +903,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) | |||
907 | ndev = net_device->ndev; | 903 | ndev = net_device->ndev; |
908 | 904 | ||
909 | /* Initialize the NetVSC channel extension */ | 905 | /* Initialize the NetVSC channel extension */ |
910 | net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; | ||
911 | spin_lock_init(&net_device->recv_pkt_list_lock); | 906 | spin_lock_init(&net_device->recv_pkt_list_lock); |
912 | 907 | ||
913 | INIT_LIST_HEAD(&net_device->recv_pkt_list); | 908 | INIT_LIST_HEAD(&net_device->recv_pkt_list); |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index d6fce9750b95..4e4cf9e0c8d7 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
@@ -128,6 +128,27 @@ static int netvsc_close(struct net_device *net) | |||
128 | return ret; | 128 | return ret; |
129 | } | 129 | } |
130 | 130 | ||
131 | static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, | ||
132 | int pkt_type) | ||
133 | { | ||
134 | struct rndis_packet *rndis_pkt; | ||
135 | struct rndis_per_packet_info *ppi; | ||
136 | |||
137 | rndis_pkt = &msg->msg.pkt; | ||
138 | rndis_pkt->data_offset += ppi_size; | ||
139 | |||
140 | ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt + | ||
141 | rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len); | ||
142 | |||
143 | ppi->size = ppi_size; | ||
144 | ppi->type = pkt_type; | ||
145 | ppi->ppi_offset = sizeof(struct rndis_per_packet_info); | ||
146 | |||
147 | rndis_pkt->per_pkt_info_len += ppi_size; | ||
148 | |||
149 | return ppi; | ||
150 | } | ||
151 | |||
131 | static void netvsc_xmit_completion(void *context) | 152 | static void netvsc_xmit_completion(void *context) |
132 | { | 153 | { |
133 | struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; | 154 | struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; |
@@ -140,22 +161,164 @@ static void netvsc_xmit_completion(void *context) | |||
140 | dev_kfree_skb_any(skb); | 161 | dev_kfree_skb_any(skb); |
141 | } | 162 | } |
142 | 163 | ||
164 | static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, | ||
165 | struct hv_page_buffer *pb) | ||
166 | { | ||
167 | int j = 0; | ||
168 | |||
169 | /* Deal with compund pages by ignoring unused part | ||
170 | * of the page. | ||
171 | */ | ||
172 | page += (offset >> PAGE_SHIFT); | ||
173 | offset &= ~PAGE_MASK; | ||
174 | |||
175 | while (len > 0) { | ||
176 | unsigned long bytes; | ||
177 | |||
178 | bytes = PAGE_SIZE - offset; | ||
179 | if (bytes > len) | ||
180 | bytes = len; | ||
181 | pb[j].pfn = page_to_pfn(page); | ||
182 | pb[j].offset = offset; | ||
183 | pb[j].len = bytes; | ||
184 | |||
185 | offset += bytes; | ||
186 | len -= bytes; | ||
187 | |||
188 | if (offset == PAGE_SIZE && len) { | ||
189 | page++; | ||
190 | offset = 0; | ||
191 | j++; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | return j + 1; | ||
196 | } | ||
197 | |||
198 | static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, | ||
199 | struct hv_page_buffer *pb) | ||
200 | { | ||
201 | u32 slots_used = 0; | ||
202 | char *data = skb->data; | ||
203 | int frags = skb_shinfo(skb)->nr_frags; | ||
204 | int i; | ||
205 | |||
206 | /* The packet is laid out thus: | ||
207 | * 1. hdr | ||
208 | * 2. skb linear data | ||
209 | * 3. skb fragment data | ||
210 | */ | ||
211 | if (hdr != NULL) | ||
212 | slots_used += fill_pg_buf(virt_to_page(hdr), | ||
213 | offset_in_page(hdr), | ||
214 | len, &pb[slots_used]); | ||
215 | |||
216 | slots_used += fill_pg_buf(virt_to_page(data), | ||
217 | offset_in_page(data), | ||
218 | skb_headlen(skb), &pb[slots_used]); | ||
219 | |||
220 | for (i = 0; i < frags; i++) { | ||
221 | skb_frag_t *frag = skb_shinfo(skb)->frags + i; | ||
222 | |||
223 | slots_used += fill_pg_buf(skb_frag_page(frag), | ||
224 | frag->page_offset, | ||
225 | skb_frag_size(frag), &pb[slots_used]); | ||
226 | } | ||
227 | return slots_used; | ||
228 | } | ||
229 | |||
230 | static int count_skb_frag_slots(struct sk_buff *skb) | ||
231 | { | ||
232 | int i, frags = skb_shinfo(skb)->nr_frags; | ||
233 | int pages = 0; | ||
234 | |||
235 | for (i = 0; i < frags; i++) { | ||
236 | skb_frag_t *frag = skb_shinfo(skb)->frags + i; | ||
237 | unsigned long size = skb_frag_size(frag); | ||
238 | unsigned long offset = frag->page_offset; | ||
239 | |||
240 | /* Skip unused frames from start of page */ | ||
241 | offset &= ~PAGE_MASK; | ||
242 | pages += PFN_UP(offset + size); | ||
243 | } | ||
244 | return pages; | ||
245 | } | ||
246 | |||
247 | static int netvsc_get_slots(struct sk_buff *skb) | ||
248 | { | ||
249 | char *data = skb->data; | ||
250 | unsigned int offset = offset_in_page(data); | ||
251 | unsigned int len = skb_headlen(skb); | ||
252 | int slots; | ||
253 | int frag_slots; | ||
254 | |||
255 | slots = DIV_ROUND_UP(offset + len, PAGE_SIZE); | ||
256 | frag_slots = count_skb_frag_slots(skb); | ||
257 | return slots + frag_slots; | ||
258 | } | ||
259 | |||
260 | static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off) | ||
261 | { | ||
262 | u32 ret_val = TRANSPORT_INFO_NOT_IP; | ||
263 | |||
264 | if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) && | ||
265 | (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) { | ||
266 | goto not_ip; | ||
267 | } | ||
268 | |||
269 | *trans_off = skb_transport_offset(skb); | ||
270 | |||
271 | if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) { | ||
272 | struct iphdr *iphdr = ip_hdr(skb); | ||
273 | |||
274 | if (iphdr->protocol == IPPROTO_TCP) | ||
275 | ret_val = TRANSPORT_INFO_IPV4_TCP; | ||
276 | else if (iphdr->protocol == IPPROTO_UDP) | ||
277 | ret_val = TRANSPORT_INFO_IPV4_UDP; | ||
278 | } else { | ||
279 | if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) | ||
280 | ret_val = TRANSPORT_INFO_IPV6_TCP; | ||
281 | else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) | ||
282 | ret_val = TRANSPORT_INFO_IPV6_UDP; | ||
283 | } | ||
284 | |||
285 | not_ip: | ||
286 | return ret_val; | ||
287 | } | ||
288 | |||
143 | static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | 289 | static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) |
144 | { | 290 | { |
145 | struct net_device_context *net_device_ctx = netdev_priv(net); | 291 | struct net_device_context *net_device_ctx = netdev_priv(net); |
146 | struct hv_netvsc_packet *packet; | 292 | struct hv_netvsc_packet *packet; |
147 | int ret; | 293 | int ret; |
148 | unsigned int i, num_pages, npg_data; | 294 | unsigned int num_data_pgs; |
149 | 295 | struct rndis_message *rndis_msg; | |
150 | /* Add multipages for skb->data and additional 2 for RNDIS */ | 296 | struct rndis_packet *rndis_pkt; |
151 | npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) | 297 | u32 rndis_msg_size; |
152 | >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; | 298 | bool isvlan; |
153 | num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2; | 299 | struct rndis_per_packet_info *ppi; |
300 | struct ndis_tcp_ip_checksum_info *csum_info; | ||
301 | struct ndis_tcp_lso_info *lso_info; | ||
302 | int hdr_offset; | ||
303 | u32 net_trans_info; | ||
304 | |||
305 | |||
306 | /* We will atmost need two pages to describe the rndis | ||
307 | * header. We can only transmit MAX_PAGE_BUFFER_COUNT number | ||
308 | * of pages in a single packet. | ||
309 | */ | ||
310 | num_data_pgs = netvsc_get_slots(skb) + 2; | ||
311 | if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { | ||
312 | netdev_err(net, "Packet too big: %u\n", skb->len); | ||
313 | dev_kfree_skb(skb); | ||
314 | net->stats.tx_dropped++; | ||
315 | return NETDEV_TX_OK; | ||
316 | } | ||
154 | 317 | ||
155 | /* Allocate a netvsc packet based on # of frags. */ | 318 | /* Allocate a netvsc packet based on # of frags. */ |
156 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + | 319 | packet = kzalloc(sizeof(struct hv_netvsc_packet) + |
157 | (num_pages * sizeof(struct hv_page_buffer)) + | 320 | (num_data_pgs * sizeof(struct hv_page_buffer)) + |
158 | sizeof(struct rndis_filter_packet) + | 321 | sizeof(struct rndis_message) + |
159 | NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); | 322 | NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); |
160 | if (!packet) { | 323 | if (!packet) { |
161 | /* out of memory, drop packet */ | 324 | /* out of memory, drop packet */ |
@@ -168,53 +331,111 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
168 | 331 | ||
169 | packet->vlan_tci = skb->vlan_tci; | 332 | packet->vlan_tci = skb->vlan_tci; |
170 | 333 | ||
171 | packet->extension = (void *)(unsigned long)packet + | 334 | packet->is_data_pkt = true; |
335 | packet->total_data_buflen = skb->len; | ||
336 | |||
337 | packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + | ||
172 | sizeof(struct hv_netvsc_packet) + | 338 | sizeof(struct hv_netvsc_packet) + |
173 | (num_pages * sizeof(struct hv_page_buffer)); | 339 | (num_data_pgs * sizeof(struct hv_page_buffer))); |
340 | |||
341 | /* Set the completion routine */ | ||
342 | packet->completion.send.send_completion = netvsc_xmit_completion; | ||
343 | packet->completion.send.send_completion_ctx = packet; | ||
344 | packet->completion.send.send_completion_tid = (unsigned long)skb; | ||
174 | 345 | ||
175 | /* If the rndis msg goes beyond 1 page, we will add 1 later */ | 346 | isvlan = packet->vlan_tci & VLAN_TAG_PRESENT; |
176 | packet->page_buf_cnt = num_pages - 1; | 347 | |
348 | /* Add the rndis header */ | ||
349 | rndis_msg = packet->rndis_msg; | ||
350 | rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; | ||
351 | rndis_msg->msg_len = packet->total_data_buflen; | ||
352 | rndis_pkt = &rndis_msg->msg.pkt; | ||
353 | rndis_pkt->data_offset = sizeof(struct rndis_packet); | ||
354 | rndis_pkt->data_len = packet->total_data_buflen; | ||
355 | rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); | ||
356 | |||
357 | rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); | ||
358 | |||
359 | if (isvlan) { | ||
360 | struct ndis_pkt_8021q_info *vlan; | ||
361 | |||
362 | rndis_msg_size += NDIS_VLAN_PPI_SIZE; | ||
363 | ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE, | ||
364 | IEEE_8021Q_INFO); | ||
365 | vlan = (struct ndis_pkt_8021q_info *)((void *)ppi + | ||
366 | ppi->ppi_offset); | ||
367 | vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK; | ||
368 | vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >> | ||
369 | VLAN_PRIO_SHIFT; | ||
370 | } | ||
177 | 371 | ||
178 | /* Initialize it from the skb */ | 372 | net_trans_info = get_net_transport_info(skb, &hdr_offset); |
179 | packet->total_data_buflen = skb->len; | 373 | if (net_trans_info == TRANSPORT_INFO_NOT_IP) |
374 | goto do_send; | ||
375 | |||
376 | /* | ||
377 | * Setup the sendside checksum offload only if this is not a | ||
378 | * GSO packet. | ||
379 | */ | ||
380 | if (skb_is_gso(skb)) | ||
381 | goto do_lso; | ||
382 | |||
383 | rndis_msg_size += NDIS_CSUM_PPI_SIZE; | ||
384 | ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, | ||
385 | TCPIP_CHKSUM_PKTINFO); | ||
386 | |||
387 | csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + | ||
388 | ppi->ppi_offset); | ||
180 | 389 | ||
181 | /* Start filling in the page buffers starting after RNDIS buffer. */ | 390 | if (net_trans_info & (INFO_IPV4 << 16)) |
182 | packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; | 391 | csum_info->transmit.is_ipv4 = 1; |
183 | packet->page_buf[1].offset | ||
184 | = (unsigned long)skb->data & (PAGE_SIZE - 1); | ||
185 | if (npg_data == 1) | ||
186 | packet->page_buf[1].len = skb_headlen(skb); | ||
187 | else | 392 | else |
188 | packet->page_buf[1].len = PAGE_SIZE | 393 | csum_info->transmit.is_ipv6 = 1; |
189 | - packet->page_buf[1].offset; | 394 | |
190 | 395 | if (net_trans_info & INFO_TCP) { | |
191 | for (i = 2; i <= npg_data; i++) { | 396 | csum_info->transmit.tcp_checksum = 1; |
192 | packet->page_buf[i].pfn = virt_to_phys(skb->data | 397 | csum_info->transmit.tcp_header_offset = hdr_offset; |
193 | + PAGE_SIZE * (i-1)) >> PAGE_SHIFT; | 398 | } else if (net_trans_info & INFO_UDP) { |
194 | packet->page_buf[i].offset = 0; | 399 | csum_info->transmit.udp_checksum = 1; |
195 | packet->page_buf[i].len = PAGE_SIZE; | ||
196 | } | 400 | } |
197 | if (npg_data > 1) | 401 | goto do_send; |
198 | packet->page_buf[npg_data].len = (((unsigned long)skb->data | 402 | |
199 | + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1; | 403 | do_lso: |
200 | 404 | rndis_msg_size += NDIS_LSO_PPI_SIZE; | |
201 | /* Additional fragments are after SKB data */ | 405 | ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE, |
202 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 406 | TCP_LARGESEND_PKTINFO); |
203 | const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; | 407 | |
204 | 408 | lso_info = (struct ndis_tcp_lso_info *)((void *)ppi + | |
205 | packet->page_buf[i+npg_data+1].pfn = | 409 | ppi->ppi_offset); |
206 | page_to_pfn(skb_frag_page(f)); | 410 | |
207 | packet->page_buf[i+npg_data+1].offset = f->page_offset; | 411 | lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; |
208 | packet->page_buf[i+npg_data+1].len = skb_frag_size(f); | 412 | if (net_trans_info & (INFO_IPV4 << 16)) { |
413 | lso_info->lso_v2_transmit.ip_version = | ||
414 | NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; | ||
415 | ip_hdr(skb)->tot_len = 0; | ||
416 | ip_hdr(skb)->check = 0; | ||
417 | tcp_hdr(skb)->check = | ||
418 | ~csum_tcpudp_magic(ip_hdr(skb)->saddr, | ||
419 | ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); | ||
420 | } else { | ||
421 | lso_info->lso_v2_transmit.ip_version = | ||
422 | NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; | ||
423 | ipv6_hdr(skb)->payload_len = 0; | ||
424 | tcp_hdr(skb)->check = | ||
425 | ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
426 | &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); | ||
209 | } | 427 | } |
428 | lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; | ||
429 | lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; | ||
210 | 430 | ||
211 | /* Set the completion routine */ | 431 | do_send: |
212 | packet->completion.send.send_completion = netvsc_xmit_completion; | 432 | /* Start filling in the page buffers with the rndis hdr */ |
213 | packet->completion.send.send_completion_ctx = packet; | 433 | rndis_msg->msg_len += rndis_msg_size; |
214 | packet->completion.send.send_completion_tid = (unsigned long)skb; | 434 | packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, |
435 | skb, &packet->page_buf[0]); | ||
436 | |||
437 | ret = netvsc_send(net_device_ctx->device_ctx, packet); | ||
215 | 438 | ||
216 | ret = rndis_filter_send(net_device_ctx->device_ctx, | ||
217 | packet); | ||
218 | if (ret == 0) { | 439 | if (ret == 0) { |
219 | net->stats.tx_bytes += skb->len; | 440 | net->stats.tx_bytes += skb->len; |
220 | net->stats.tx_packets++; | 441 | net->stats.tx_packets++; |
@@ -264,7 +485,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, | |||
264 | * "wire" on the specified device. | 485 | * "wire" on the specified device. |
265 | */ | 486 | */ |
266 | int netvsc_recv_callback(struct hv_device *device_obj, | 487 | int netvsc_recv_callback(struct hv_device *device_obj, |
267 | struct hv_netvsc_packet *packet) | 488 | struct hv_netvsc_packet *packet, |
489 | struct ndis_tcp_ip_checksum_info *csum_info) | ||
268 | { | 490 | { |
269 | struct net_device *net; | 491 | struct net_device *net; |
270 | struct sk_buff *skb; | 492 | struct sk_buff *skb; |
@@ -291,7 +513,17 @@ int netvsc_recv_callback(struct hv_device *device_obj, | |||
291 | packet->total_data_buflen); | 513 | packet->total_data_buflen); |
292 | 514 | ||
293 | skb->protocol = eth_type_trans(skb, net); | 515 | skb->protocol = eth_type_trans(skb, net); |
294 | skb->ip_summed = CHECKSUM_NONE; | 516 | if (csum_info) { |
517 | /* We only look at the IP checksum here. | ||
518 | * Should we be dropping the packet if checksum | ||
519 | * failed? How do we deal with other checksums - TCP/UDP? | ||
520 | */ | ||
521 | if (csum_info->receive.ip_checksum_succeeded) | ||
522 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
523 | else | ||
524 | skb->ip_summed = CHECKSUM_NONE; | ||
525 | } | ||
526 | |||
295 | if (packet->vlan_tci & VLAN_TAG_PRESENT) | 527 | if (packet->vlan_tci & VLAN_TAG_PRESENT) |
296 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), | 528 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), |
297 | packet->vlan_tci); | 529 | packet->vlan_tci); |
@@ -327,7 +559,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) | |||
327 | if (nvdev == NULL || nvdev->destroy) | 559 | if (nvdev == NULL || nvdev->destroy) |
328 | return -ENODEV; | 560 | return -ENODEV; |
329 | 561 | ||
330 | if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2) | 562 | if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) |
331 | limit = NETVSC_MTU; | 563 | limit = NETVSC_MTU; |
332 | 564 | ||
333 | if (mtu < 68 || mtu > limit) | 565 | if (mtu < 68 || mtu > limit) |
@@ -452,9 +684,10 @@ static int netvsc_probe(struct hv_device *dev, | |||
452 | 684 | ||
453 | net->netdev_ops = &device_ops; | 685 | net->netdev_ops = &device_ops; |
454 | 686 | ||
455 | /* TODO: Add GSO and Checksum offload */ | 687 | net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM | |
456 | net->hw_features = 0; | 688 | NETIF_F_TSO; |
457 | net->features = NETIF_F_HW_VLAN_CTAG_TX; | 689 | net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | |
690 | NETIF_F_IP_CSUM | NETIF_F_TSO; | ||
458 | 691 | ||
459 | SET_ETHTOOL_OPS(net, ðtool_ops); | 692 | SET_ETHTOOL_OPS(net, ðtool_ops); |
460 | SET_NETDEV_DEV(net, &dev->device); | 693 | SET_NETDEV_DEV(net, &dev->device); |
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index b54fd257652b..4a37e3db9e32 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
@@ -58,9 +58,6 @@ struct rndis_request { | |||
58 | u8 request_ext[RNDIS_EXT_LEN]; | 58 | u8 request_ext[RNDIS_EXT_LEN]; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static void rndis_filter_send_completion(void *ctx); | ||
62 | |||
63 | |||
64 | static struct rndis_device *get_rndis_device(void) | 61 | static struct rndis_device *get_rndis_device(void) |
65 | { | 62 | { |
66 | struct rndis_device *device; | 63 | struct rndis_device *device; |
@@ -297,7 +294,7 @@ static void rndis_filter_receive_response(struct rndis_device *dev, | |||
297 | "rndis response buffer overflow " | 294 | "rndis response buffer overflow " |
298 | "detected (size %u max %zu)\n", | 295 | "detected (size %u max %zu)\n", |
299 | resp->msg_len, | 296 | resp->msg_len, |
300 | sizeof(struct rndis_filter_packet)); | 297 | sizeof(struct rndis_message)); |
301 | 298 | ||
302 | if (resp->ndis_msg_type == | 299 | if (resp->ndis_msg_type == |
303 | RNDIS_MSG_RESET_C) { | 300 | RNDIS_MSG_RESET_C) { |
@@ -373,6 +370,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, | |||
373 | struct rndis_packet *rndis_pkt; | 370 | struct rndis_packet *rndis_pkt; |
374 | u32 data_offset; | 371 | u32 data_offset; |
375 | struct ndis_pkt_8021q_info *vlan; | 372 | struct ndis_pkt_8021q_info *vlan; |
373 | struct ndis_tcp_ip_checksum_info *csum_info; | ||
376 | 374 | ||
377 | rndis_pkt = &msg->msg.pkt; | 375 | rndis_pkt = &msg->msg.pkt; |
378 | 376 | ||
@@ -411,7 +409,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev, | |||
411 | pkt->vlan_tci = 0; | 409 | pkt->vlan_tci = 0; |
412 | } | 410 | } |
413 | 411 | ||
414 | netvsc_recv_callback(dev->net_dev->dev, pkt); | 412 | csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO); |
413 | netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info); | ||
415 | } | 414 | } |
416 | 415 | ||
417 | int rndis_filter_receive(struct hv_device *dev, | 416 | int rndis_filter_receive(struct hv_device *dev, |
@@ -630,6 +629,61 @@ cleanup: | |||
630 | return ret; | 629 | return ret; |
631 | } | 630 | } |
632 | 631 | ||
632 | int rndis_filter_set_offload_params(struct hv_device *hdev, | ||
633 | struct ndis_offload_params *req_offloads) | ||
634 | { | ||
635 | struct netvsc_device *nvdev = hv_get_drvdata(hdev); | ||
636 | struct rndis_device *rdev = nvdev->extension; | ||
637 | struct net_device *ndev = nvdev->ndev; | ||
638 | struct rndis_request *request; | ||
639 | struct rndis_set_request *set; | ||
640 | struct ndis_offload_params *offload_params; | ||
641 | struct rndis_set_complete *set_complete; | ||
642 | u32 extlen = sizeof(struct ndis_offload_params); | ||
643 | int ret, t; | ||
644 | |||
645 | request = get_rndis_request(rdev, RNDIS_MSG_SET, | ||
646 | RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); | ||
647 | if (!request) | ||
648 | return -ENOMEM; | ||
649 | |||
650 | set = &request->request_msg.msg.set_req; | ||
651 | set->oid = OID_TCP_OFFLOAD_PARAMETERS; | ||
652 | set->info_buflen = extlen; | ||
653 | set->info_buf_offset = sizeof(struct rndis_set_request); | ||
654 | set->dev_vc_handle = 0; | ||
655 | |||
656 | offload_params = (struct ndis_offload_params *)((ulong)set + | ||
657 | set->info_buf_offset); | ||
658 | *offload_params = *req_offloads; | ||
659 | offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT; | ||
660 | offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3; | ||
661 | offload_params->header.size = extlen; | ||
662 | |||
663 | ret = rndis_filter_send_request(rdev, request); | ||
664 | if (ret != 0) | ||
665 | goto cleanup; | ||
666 | |||
667 | t = wait_for_completion_timeout(&request->wait_event, 5*HZ); | ||
668 | if (t == 0) { | ||
669 | netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n"); | ||
670 | /* can't put_rndis_request, since we may still receive a | ||
671 | * send-completion. | ||
672 | */ | ||
673 | return -EBUSY; | ||
674 | } else { | ||
675 | set_complete = &request->response_msg.msg.set_complete; | ||
676 | if (set_complete->status != RNDIS_STATUS_SUCCESS) { | ||
677 | netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", | ||
678 | set_complete->status); | ||
679 | ret = -EINVAL; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | cleanup: | ||
684 | put_rndis_request(rdev, request); | ||
685 | return ret; | ||
686 | } | ||
633 | 687 | ||
634 | static int rndis_filter_query_device_link_status(struct rndis_device *dev) | 688 | static int rndis_filter_query_device_link_status(struct rndis_device *dev) |
635 | { | 689 | { |
@@ -829,6 +883,7 @@ int rndis_filter_device_add(struct hv_device *dev, | |||
829 | struct netvsc_device *net_device; | 883 | struct netvsc_device *net_device; |
830 | struct rndis_device *rndis_device; | 884 | struct rndis_device *rndis_device; |
831 | struct netvsc_device_info *device_info = additional_info; | 885 | struct netvsc_device_info *device_info = additional_info; |
886 | struct ndis_offload_params offloads; | ||
832 | 887 | ||
833 | rndis_device = get_rndis_device(); | 888 | rndis_device = get_rndis_device(); |
834 | if (!rndis_device) | 889 | if (!rndis_device) |
@@ -868,6 +923,26 @@ int rndis_filter_device_add(struct hv_device *dev, | |||
868 | 923 | ||
869 | memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); | 924 | memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); |
870 | 925 | ||
926 | /* Turn on the offloads; the host supports all of the relevant | ||
927 | * offloads. | ||
928 | */ | ||
929 | memset(&offloads, 0, sizeof(struct ndis_offload_params)); | ||
930 | /* A value of zero means "no change"; now turn on what we | ||
931 | * want. | ||
932 | */ | ||
933 | offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
934 | offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
935 | offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
936 | offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
937 | offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
938 | offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; | ||
939 | |||
940 | |||
941 | ret = rndis_filter_set_offload_params(dev, &offloads); | ||
942 | if (ret) | ||
943 | goto err_dev_remv; | ||
944 | |||
945 | |||
871 | rndis_filter_query_device_link_status(rndis_device); | 946 | rndis_filter_query_device_link_status(rndis_device); |
872 | 947 | ||
873 | device_info->link_state = rndis_device->link_state; | 948 | device_info->link_state = rndis_device->link_state; |
@@ -877,6 +952,10 @@ int rndis_filter_device_add(struct hv_device *dev, | |||
877 | device_info->link_state ? "down" : "up"); | 952 | device_info->link_state ? "down" : "up"); |
878 | 953 | ||
879 | return ret; | 954 | return ret; |
955 | |||
956 | err_dev_remv: | ||
957 | rndis_filter_device_remove(dev); | ||
958 | return ret; | ||
880 | } | 959 | } |
881 | 960 | ||
882 | void rndis_filter_device_remove(struct hv_device *dev) | 961 | void rndis_filter_device_remove(struct hv_device *dev) |
@@ -913,101 +992,3 @@ int rndis_filter_close(struct hv_device *dev) | |||
913 | 992 | ||
914 | return rndis_filter_close_device(nvdev->extension); | 993 | return rndis_filter_close_device(nvdev->extension); |
915 | } | 994 | } |
916 | |||
917 | int rndis_filter_send(struct hv_device *dev, | ||
918 | struct hv_netvsc_packet *pkt) | ||
919 | { | ||
920 | int ret; | ||
921 | struct rndis_filter_packet *filter_pkt; | ||
922 | struct rndis_message *rndis_msg; | ||
923 | struct rndis_packet *rndis_pkt; | ||
924 | u32 rndis_msg_size; | ||
925 | bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT; | ||
926 | |||
927 | /* Add the rndis header */ | ||
928 | filter_pkt = (struct rndis_filter_packet *)pkt->extension; | ||
929 | |||
930 | rndis_msg = &filter_pkt->msg; | ||
931 | rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); | ||
932 | if (isvlan) | ||
933 | rndis_msg_size += NDIS_VLAN_PPI_SIZE; | ||
934 | |||
935 | rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; | ||
936 | rndis_msg->msg_len = pkt->total_data_buflen + | ||
937 | rndis_msg_size; | ||
938 | |||
939 | rndis_pkt = &rndis_msg->msg.pkt; | ||
940 | rndis_pkt->data_offset = sizeof(struct rndis_packet); | ||
941 | if (isvlan) | ||
942 | rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE; | ||
943 | rndis_pkt->data_len = pkt->total_data_buflen; | ||
944 | |||
945 | if (isvlan) { | ||
946 | struct rndis_per_packet_info *ppi; | ||
947 | struct ndis_pkt_8021q_info *vlan; | ||
948 | |||
949 | rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); | ||
950 | rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE; | ||
951 | |||
952 | ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + | ||
953 | rndis_pkt->per_pkt_info_offset); | ||
954 | ppi->size = NDIS_VLAN_PPI_SIZE; | ||
955 | ppi->type = IEEE_8021Q_INFO; | ||
956 | ppi->ppi_offset = sizeof(struct rndis_per_packet_info); | ||
957 | |||
958 | vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + | ||
959 | ppi->ppi_offset); | ||
960 | vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK; | ||
961 | vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; | ||
962 | } | ||
963 | |||
964 | pkt->is_data_pkt = true; | ||
965 | pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT; | ||
966 | pkt->page_buf[0].offset = | ||
967 | (unsigned long)rndis_msg & (PAGE_SIZE-1); | ||
968 | pkt->page_buf[0].len = rndis_msg_size; | ||
969 | |||
970 | /* Add one page_buf if the rndis msg goes beyond page boundary */ | ||
971 | if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) { | ||
972 | int i; | ||
973 | for (i = pkt->page_buf_cnt; i > 1; i--) | ||
974 | pkt->page_buf[i] = pkt->page_buf[i-1]; | ||
975 | pkt->page_buf_cnt++; | ||
976 | pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; | ||
977 | pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) | ||
978 | rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT; | ||
979 | pkt->page_buf[1].offset = 0; | ||
980 | pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len; | ||
981 | } | ||
982 | |||
983 | /* Save the packet send completion and context */ | ||
984 | filter_pkt->completion = pkt->completion.send.send_completion; | ||
985 | filter_pkt->completion_ctx = | ||
986 | pkt->completion.send.send_completion_ctx; | ||
987 | |||
988 | /* Use ours */ | ||
989 | pkt->completion.send.send_completion = rndis_filter_send_completion; | ||
990 | pkt->completion.send.send_completion_ctx = filter_pkt; | ||
991 | |||
992 | ret = netvsc_send(dev, pkt); | ||
993 | if (ret != 0) { | ||
994 | /* | ||
995 | * Reset the completion to originals to allow retries from | ||
996 | * above | ||
997 | */ | ||
998 | pkt->completion.send.send_completion = | ||
999 | filter_pkt->completion; | ||
1000 | pkt->completion.send.send_completion_ctx = | ||
1001 | filter_pkt->completion_ctx; | ||
1002 | } | ||
1003 | |||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | static void rndis_filter_send_completion(void *ctx) | ||
1008 | { | ||
1009 | struct rndis_filter_packet *filter_pkt = ctx; | ||
1010 | |||
1011 | /* Pass it back to the original handler */ | ||
1012 | filter_pkt->completion(filter_pkt->completion_ctx); | ||
1013 | } | ||